Domanda

Se ho una tabella con 2 colonne importanti,

CREATE TABLE foo (id INT, a INT, b INT, KEY a, KEY b);

Come posso trovare tutte le righe che hanno a e b uguali in entrambe le righe? Ad esempio, in questo set di dati

id | a | b
----------
1  | 1 | 2
2  | 5 | 42
3  | 1 | 42
4  | 1 | 2 
5  | 1 | 2
6  | 1 | 42

Voglio recuperare tutte le righe tranne id = 2 poiché è univoco in (a, b) . Fondamentalmente, voglio trovare tutte le righe offensive che fermerebbero un

ALTER TABLE foo ADD UNIQUE (a, b);

Qualcosa di meglio di un n ^ 2 per loop sarebbe carino dato che la mia tabella ha 10 milioni di righe.

Per i punti bonus : come ho rimosso tutte le righe tranne una (non mi importa quali, purché ne rimanga una)

È stato utile?

Soluzione

SELECT * 
FROM foo first
JOIN foo second
  ON ( first.a = second.a
       AND first.b = second.b ) 
  AND (first.id <> second.id )

Dovrebbe venire fuori con tutte le righe in cui più di una riga ha la stessa combinazione di a e b.

Spero solo di avere un indice sulle colonne a e b.

Altri suggerimenti

select * from foo where a = b

O mi sto perdendo qualcosa?

===

Aggiornamento per chiarezza:

select * from 
foo as a
inner join foo as b
on a.a = b.a AND b.a = b.b
and a.id != b.id

++++++++++ Dopo la terza modifica di chiarezza:

select f1.id
FROM foo as f1
INNER JOIN foo as f2
ON f1.a = f2.a AND f1.b=f2.b AND f1.id != f2.id

Ma sono sparato, quindi controlla tu stesso.

Prova questo:

    With s as (Select a,b from foo group by a,b having Count(1)>1)
Select foo.* from foo,s where foo.a=s.a and foo.b=s.b

Questa query dovrebbe mostrare righe duplicate nella tabella pippo.

Potresti chiarire per favore cosa devi fare alla fine? La soluzione migliore può dipendere da questo (ad esempio, vuoi semplicemente eliminare tutte le righe chiave duplicata?)

Un modo è gestire questa tabella (non sono sicuro che mySQL la supporti, è di SYBASE) se tutto ciò che desideri sono righe con chiave univoca:

SELECT MIN(id), A, B FROM FOO GROUP BY A, B HAVING COUNT(*)>1

La tua domanda esatta (anche se sono un po 'perplesso sul perché avresti bisogno di tutte le righe tranne id = 2) è:

SELECT F1.*  
FROM FOO F1 , 
     (SELECT A, B FROM FOO GROUP BY A, B HAVING COUNT(*)>1) F2
WHERE F1.A=F2.A and F1.B=F2.B

Per eliminare tutti i duplicati, ad esempio puoi farlo

DELETE FOO WHERE NOT EXISTS
(SELECT 1 from
    (SELECT MIN(id) 'min_id' FROM FOO GROUP BY A, B HAVING COUNT(*)>1) UINIQUE_IDS 
 WHERE id = min_id)

In alternativa, puoi farlo

  SELECT MIN(id) 'id', A, B INTO TEMPDB..NEW_TABLE 
  FROM FOO GROUP BY A, B HAVING COUNT(*)>1

  TRUNCATE TABLE FOO
  // Drop indices on FOO
  INSERT FOO SELECT * FROM NEW_TABLE
  // Recreate indices on FOO

non dovrebbe funzionare?

SELECT * FROM foo WHERE a = b

=== edit ===

che ne dici

SELECT a, b FROM foo GROUP BY a, b HAVING COUNT(*) > 1

=== ri-modifica finale prima di rinunciare a questa domanda ===

SELECT foo.* FROM foo, (
   SELECT a, b FROM foo GROUP BY a, b HAVING COUNT(*) > 1
) foo2
WHERE foo.a = foo2.a AND foo.b = foo2.b

ecco un altro approccio

select * from foo f1 where exists(
  select * from foo f2 where
    f1.id != f2.id and
    f1.a = f2.a and
    f1.b = f2.b )

comunque, anche se lo trovo un po 'più leggibile, se hai una tabella così grande, dovresti controllare il piano di esecuzione, le sottoquery hanno una cattiva reputazione che coinvolge le prestazioni ...

dovresti anche considerare di creare l'indice (senza la clausola unica, ovviamente) per velocizzare la query ... per operazioni enormi, a volte è meglio impiegare il tempo a creare l'indice, eseguire l'aggiornamento e quindi rilasciare l'indice. .. in questo caso, immagino che un indice su (a, b) dovrebbe sicuramente aiutare molto ...

Il tuo obiettivo dichiarato è di rimuovere tutte le combinazioni duplicate di (a, b) . Per questo, puoi usare un DELETE multi-tabella:

DELETE t1
  FROM foo t1
  JOIN foo t2 USING (a, b)
 WHERE t2.id > t1.id

Prima di eseguirlo, puoi controllare quali righe verranno rimosse con:

SELECT DISTINCT t1.id
  FROM foo t1
  JOIN foo t2 USING (a, b)
 WHERE t2.id > t1.id

La clausola WHERE è t2.id > t1.id rimuoverà tutto tranne quello con il valore più alto per id . Nel tuo caso, rimarrebbero solo le righe con id pari a 2, 5 o 6.

Se il valore ID non ha alcuna importanza nel prodotto finale, vale a dire, se è possibile rinumerarli tutti e andrebbe bene, e se id è una colonna seriale, selezionare semplicemente " sulle due colonne in una nuova tabella, elimina tutti i dati dalla vecchia tabella, quindi copia nuovamente i valori temporanei.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top