2013-03-17 64 views
5

Próbuję wyczyścić rekordy przechowywane w tabeli MySQL. Jeśli wiersz zawiera %X%, muszę usunąć ten wiersz i wiersz bezpośrednio pod nim, niezależnie od zawartości. Na przykład. (Przepraszam, jeśli tabela jest obrażanie czyjąś inteligencję):USUŃ rekord w pozycji relacyjnej w MySQL?

| 1 | leave alone 
| 2 | Contains %X% - Delete 
| 3 | This row should also be deleted 
| 4 | leave alone 
| 5 | Contains %X% - Delete 
| 6 | This row should also be deleted 
| 7 | leave alone 

Czy istnieje sposób, aby to zrobić używając tylko kilka pytań? Czy najpierw będę musiał wykonać zapytanie SELECT (używając parametru wyszukiwania %x%), a następnie przejrzeć te wyniki i wykonać polecenie DELETE ... WHERE dla każdego zwróconego indeksu + 1

+0

@Aasas: To zupełnie inne pytanie. – duskwuff

Odpowiedz

0

Nie ma rozsądnego sposobu na zrobienie tego w jednym zapytaniu. (Może to być możliwe, ale kwerenda skończyć konieczności używania będzie bezzasadnie skomplikowane, a prawie na pewno nie jest przenośny do innych silników SQL.)

Przyciskiem SELECT-then-DELETE podejście opisałeś w Twoje pytanie.

2

To powinno działać choć jej nieco niezgrabne (może chcieć sprawdzić LIKE argumentu, ponieważ wykorzystuje wzorzec dopasowania (patrz komentarze) DELETE FROM table. db GDZIE idcol IN (SELECT idcol OD db. table GDZIE col LIKE '% X%') ​​ LUB idcol IN (SELECT idcol +1 FROM db . stół WHERE col` LIKE '%% X')

+0

To zależy od braków w identyfikatorach. – CBroe

+0

tak to jest bardzo prawdziwe – Tucker

+0

LIKE nie używa wyrażeń regularnych, REGEXP ma; zobacz http://dev.mysql.com/doc/refman/5.6/en/string-comparison-functions.html#operator_like – ysth

1

Załóżmy, że stół został nazwany test i zawierał kolumn wymienionych id i data.

Zaczynamy SELECT, który daje nam id wszystkich wierszy, które mają poprzedni rząd (najwyższy id wszystkich identyfikatorów niższy niż id naszego bieżącego wiersza):

SELECT t1.id FROM test t1 
    JOIN test t2 ON 
    (t2.id, true) 
     = 
    (SELECT t3.id, t3.data LIKE '%X%' FROM test t3 
     WHERE t3.id < t1.id ORDER BY id DESC LIMIT 1) 

To daje nam identyfikatory 3 i 6. Ich poprzednie wiersze 2 i 5 zawierają %X%, więc to dobrze.

Teraz przejdźmy identyfikatory wierszy, które zawierają %X% i połączyć je z poprzednimi, poprzez UNII:

(SELECT t1.id FROM test t1 
    JOIN test t2 ON 
    (t2.id, true) 
     = 
    (SELECT t3.id, t3.data LIKE '%X%' FROM test t3 
     WHERE t3.id < t1.id ORDER BY id DESC LIMIT 1) 
) 
UNION 
(
    SELECT id FROM test WHERE data LIKE '%X%' 
) 

To daje nam 3, 6, 2, 5 - nice!

Teraz nie możemy usunąć z tabeli i wybrać z tej samej tabeli w MySQL - więc użyjmy tabeli tymczasowej, przechowuj nasze identyfikatory, które mają zostać usunięte, a następnie odczytaj z tej tabeli tymczasowej, aby usunąć od naszej pierwotnej tabeli:

CREATE TEMPORARY TABLE deleteids (id INT); 

INSERT INTO deleteids 
    (SELECT t1.id FROM test t1 
    JOIN test t2 ON 
     (t2.id, true) 
     = 
     (SELECT t3.id, t3.data LIKE '%X%' FROM test t3 
      WHERE t3.id < t1.id ORDER BY id DESC LIMIT 1) 
) 
    UNION 
    (
    SELECT id FROM test WHERE data LIKE '%X%' 
); 

    DELETE FROM test WHERE id in (SELECT * FROM deleteids); 

... i jesteśmy w lewo z identyfikatorami 1, 4 i 7 w naszej test stole!

(A ponieważ poprzednie wiersze są wybierane przy użyciu <, ORDER BY i LIMIT, działa to również, jeśli identyfikatory nie są ciągłe.)

1

Można zrobić to wszystko w jednym DELETE stwierdzeniem:

Przyjmując „rząd natychmiast po” oparta jest na porządku kolumnie ID INT oparte można wykorzystać zmienne MySQL przypisać numery wierszy, które rachunki dla luk w swoich identyfikatorów:

DELETE a FROM tbl a 
JOIN (
    SELECT a.id, b.id AS nextid 
    FROM (
     SELECT  a.id, a.text, @rn:[email protected]+1 AS rownum 
     FROM  tbl a 
     CROSS JOIN (SELECT @rn:=1) rn_init 
     ORDER BY a.id 
    ) a 
    LEFT JOIN (
     SELECT  a.id, @rn2:[email protected]+1 AS rownum 
     FROM  tbl a 
     CROSS JOIN (SELECT @rn2:=0) rn_init 
     ORDER BY a.id 
    ) b ON a.rownum = b.rownum 
    WHERE a.text LIKE '%X%' 
) b ON a.id IN (b.id, b.nextid) 

SQL Fiddle Demo (added additional data for example)


Co to robi to po raz pierwszy bierze swoje dane i plasuje je na podstawie twoja kolumna ID, następnie wykonujemy przesunięcie LEFT JOIN na prawie identycznym zestawie wyników, z tym wyjątkiem, że kolumna rangowa jest opóźniona o 1. To dostaje wierszy i ich natychmiastowe „next” wierszy obok siebie tak, że możemy wyciągnąć zarówno z ich identyfikatorami w tym samym czasie w rachunku rodzic DELETE:

SELECT a.id, a.text, b.id AS nextid, b.text AS nexttext 
FROM (
    SELECT  a.id, a.text, @rn:[email protected]+1 AS rownum 
    FROM  tbl a 
    CROSS JOIN (SELECT @rn:=1) rn_init 
    ORDER BY a.id 
) a 
LEFT JOIN (
    SELECT  a.id, a.text, @rn2:[email protected]+1 AS rownum 
    FROM  tbl a 
    CROSS JOIN (SELECT @rn2:=0) rn_init 
    ORDER BY a.id 
) b ON a.rownum = b.rownum 
WHERE a.text LIKE '%X%' 

Wynik:

ID  | TEXT     | NEXTID | NEXTTEXT 
2  | Contains %X% - Delete | 3  | This row should also be deleted 
5  | Contains %X% - Delete | 6  | This row should also be deleted 
257 | Contains %X% - Delete | 3434  | This row should also be deleted 
4000 | Contains %X% - Delete | 4005  | Contains %X% - Delete 
4005 | Contains %X% - Delete | 6000  | Contains %X% - Delete 
6000 | Contains %X% - Delete | 6534  | This row should also be deleted 

Mamy następnie JOIN - to całe oświadczenie pod warunkiem, że usuwa on wiersze, których identyfikatory są "podselekcjami" ID lub NEXTID.