2014-07-25 4 views
7

Sto provando a selezionare i record duplicati in base a una corrispondenza di tre colonne. L'elenco delle triple potrebbe essere molto lungo (1000), quindi mi piacerebbe renderlo conciso.Clausole MySQL IN, cercando di far corrispondere la lista IN delle tuple

Quando ho un elenco di dimensioni 10 (noto duplicati) corrisponda solo 2 (quelli apparentemente casuali) e manca l'altra 8. mi aspettavo 10 record di tornare, ma ho visto solo 2.

ho ridotto a questo problema:

Questo restituisce un record. Expecting 2:

select * 
from ali 
where (accountOid, dt, x) in 
(
    (64, '2014-03-01', 10000.0), 
    (64, '2014-04-23', -122.91) 
) 

restituisce due record, come previsto:

select * 
from ali 
where (accountOid, dt, x) in ((64, '2014-03-01', 10000.0)) 
or (accountOid, dt, x) in ((64, '2014-04-23', -122.91)) 

Tutte le idee perché la prima query restituisce solo un record?

+2

sono riuscito a riprodurre il problema sulla mia macchina (MySQL 5.6 .14). Puoi fare un violino? – Vatev

+0

Puoi modificare la tua domanda e descrivere i tipi di dati delle colonne ('SHOW CREATE TABLE ali')? Se stai usando 'FLOAT' o' DOUBLE' per colonna 'x', i confronti di uguaglianza possono fallire perché il valore esatto viene arrotondato in modi imprevisti. Inoltre, si prega di specificare esattamente quale versione di MySQL si usa. –

+0

Puoi pubblicare il codice che stai utilizzando. L'ho copiato su un tavolo e all'inizio sembrava che fosse un valore di un operando, ma è stata colpa mia se mancava una parentesi. Come Vatev non ero in grado di riprodurre il problema – DanceSC

risposta

1

Io suggerirei di non utilizzare IN() per questo, invece di utilizzare una query in cui esiste, ad esempio:

CREATE TABLE inlist 
    (`id` int, `accountOid` int, `dt` datetime, `x` decimal(18,4)) 
; 

INSERT INTO inlist 
    (`id`, `accountOid`, `dt`, `x`) 
VALUES 
    (1, 64, '2014-03-01 00:00:00', 10000.0), 
    (2, 64, '2014-04-23 00:00:00', -122.91) 
; 

select * 
from ali 
where exists (select null 
       from inlist 
       where ali.accountOid = inlist.accountOid 
       and ali.dt = inlist.dt 
       and ali.x = inlist.x 
      ) 
; 

sono stato in grado di riprodurre un problema (confrontare http://sqlfiddle.com/#!2/7d2658/6-http://sqlfiddle.com/#!2/fe851/1 sia MySQL 5.5 .3) dove se la colonna x era numerica e il valore negativo NON era abbinata usando IN() ma era abbinata quando numerica o decimale usando una tabella e dove esiste.

Forse non un test conclusivo, ma personalmente non avrei comunque utilizzato IN() per questo.

Perché non si determinano i duplicati in questo modo?

select 
     accountOid 
     , dt 
     , x 
from ali 
group by 
     accountOid 
     , dt 
     , x 
having 
     count(*) > 1 

quindi utilizzarlo come una tabella derivata nel cui esiste condizione:

select * 
from ali 
where exists (
       select null 
       from (
         select 
           accountOid 
          , dt 
          , x 
         from ali 
         group by 
           accountOid 
          , dt 
          , x 
         having 
           count(*) > 1 
        ) as inlist 
       where ali.accountOid = inlist.accountOid 
       and ali.dt = inlist.dt 
       and ali.x = inlist.x 
      ) 

vedere http://sqlfiddle.com/#!2/ede292/1 per la query immediatamente sopra

+0

La sintassi [inner syntax sembrerebbe più semplice] (http://sqlfiddle.com/#!2/ede292/2) per me. Mi aspetto anche che il join sia altrettanto efficiente, anche se, secondo SQL Fiddle, i piani di query differiscono e non sono molto bravo a interpretarli. –

+0

sì, buon punto, join interno utilizzando la stessa tabella derivata è anche un'opzione. I piani di esecuzione di sqlfiddle spesso non sono rilevanti in quanto non ci sono indici e la scala dei dati è troppo piccola - ma non c'è una grande differenza nei 2 approcci. –

Problemi correlati