2013-03-17 18 views
5

Sto cercando di ripulire i record memorizzati in una tabella MySQL. Se una riga contiene %X%, ho bisogno di cancellare quella riga e la riga immediatamente sotto di essa, indipendentemente dal contenuto. Per esempio. (Scusate se la tabella è un insulto l'intelligenza di nessuno):CANCELLARE un record in posizione relazionale in 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 

C'è un modo per fare questo usando solo un paio di domande? Oppure dovrò eseguire prima una query SELECT (utilizzando il parametro di ricerca) e scorrere tra questi risultati ed eseguire un DELETE ... WHERE per ogni indice restituito + 1

+0

@Aiias: Questa è una domanda completamente diversa. – duskwuff

risposta

0

Non esiste un modo ragionevole per farlo in una singola query. (Può essere possibile, ma la query si finisce per dover utilizzare sarà irragionevolmente complesso, e sarà quasi certamente non essere portabile su altri motori di SQL.)

utilizzare l'approccio SELECT-allora-DELETE lei ha descritto in la tua domanda.

2

Questo dovrebbe funzionare anche se è un po 'goffo (potrebbe voler controllare l'argomento COME quanto utilizza pattern matching (vedi commenti) DELETE FROM table. db DOVE idcol IN (SELECT idcol DA db. table DOVE col COME '% X%') ​​ O IDCol IN (SELECT IDCol +1 FROM db . tavolo WHERE col` LIKE '% X%') ​​

+0

Questo si basa su non spazi vuoti negli ID. – CBroe

+0

sì questo è molto vero – Tucker

+0

LIKE non usa espressioni regolari, fa REGEXP; vedi http://dev.mysql.com/doc/refman/5.6/en/string-comparison-functions.html#operator_like – ysth

1

Supponiamo che la tavola è stato nominato test e conteneva alle colonne denominate id e data.

si comincia con una SELECT che ci dà l'id di tutte le righe che hanno una riga precedente (più alto id di tutti gli ID inferiore id del nostro riga corrente):

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) 

che ci dà l'ids 3 e 6. Le loro precedenti righe 2 e 5 contengono %X%, quindi va bene.

Ora consente di ottenere gli ID delle righe che contengono %X% e combinarle con quelle precedenti, via l'unione:

(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%' 
) 

che ci dà 3, 6, 2, 5 - bello!

Ora, non è possibile eliminare da una tabella e selezionare dalla stessa tabella in MySQL - quindi utilizzare una tabella temporanea, archiviare i nostri id che devono essere eliminati e quindi leggere da quella tabella temporanea per eliminare dal nostro tavolo originale:

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); 

... e ci ritroviamo con gli iD 1, 4 e 7 nella nostra tabella test!

(E poiché le righe precedenti sono selezionate utilizzando <, ORDER BY e LIMIT, funziona anche se gli ID non sono continui.)

1

Si può fare tutto in un unico DELETE dichiarazione:

Supponendo che la "fila subito dopo" si basa sull'ordine della vostra colonna ID INT-based, è possibile utilizzare le variabili di MySQL per assegnare numeri di riga che conti per lacune nella vostra ID:

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)


Quello che fa è che ci vuole prima i dati e colloca basa su la colonna ID, quindi eseguiamo un offset LEFT JOIN su un set di risultati quasi identico, tranne per il fatto che la colonna di classifica è dietro a 1. Questo diventa le righe e il loro lato immediati "prossimi" righe a fianco in modo da poter tirare entrambi i loro id allo stesso tempo nella dichiarazione genitore 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%' 

Resa:

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 

Noi quindi JOIN - DELETE l'intera istruzione a condizione che elimini le righe i cui ID siano "sottoselezionati" ID o NEXTID.

Problemi correlati