2014-07-25 6 views
7

Ich versuche, doppelte Datensätze basierend auf einer Übereinstimmung von drei Spalten auszuwählen. Die Liste der Tripel könnte sehr lang sein (1000), daher möchte ich es kurz fassen.MySql IN-Klauseln, versuchen, IN Liste von Tupeln

Wenn ich eine Liste der Größe 10 (bekannt Duplikate) haben es passt nur 2 (scheinbar zufällig sind) und vermisst die anderen 8 I 10 Datensätze erwartet zurück, sah aber nur 2.

Ich habe verengt es auf dieses Problem:

Dies gibt einen Datensatz zurück. Erwartet 2:

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

Gibt zwei Datensätze, wie erwartet:

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

Irgendwelche Ideen, warum die erste Abfrage nur einen Datensatz zurückgibt?

+2

Ich war nicht in der Lage, das Problem auf meinem Rechner (MySQL 5.6 zu reproduzieren .14). Kannst du eine Geige machen? – Vatev

+0

Können Sie Ihre Frage bearbeiten und die Datentypen von Spalten beschreiben ('SHOW CREATE TABLE ali')? Wenn Sie 'FLOAT' oder' DOUBLE' für die Spalte 'x' verwenden, kann dies dazu führen, dass Gleichheitsvergleiche fehlschlagen, weil der exakte Wert auf unerwartete Weise gerundet wird. Bitte geben Sie auch genau an, welche Version von MySQL Sie verwenden. –

+0

Können Sie den von Ihnen verwendeten Code posten? Ich habe das in eine Tabelle kopiert und zuerst sah es so aus, als wäre es ein Operandenwert, aber das war meine Schuld, weil ich einen Klammersatz vermisste. Wie Vatev konnte ich das Problem nicht reproduzieren – DanceSC

Antwort

1

Ich würde vorschlagen, dass Sie für diesen Einsatz in() nicht, stattdessen eine verwenden, wo existiert Abfrage, zB:

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

ich in der Lage war, ein Problem zu reproduzieren (vgl http://sqlfiddle.com/#!2/7d2658/6-http://sqlfiddle.com/#!2/fe851/1 sowohl MySQL 5.5 .3) Wenn die x-Spalte numerisch und der Wert negativ war, wurde sie NICHT mit IN() abgeglichen, aber sie wurde entweder numerisch oder dezimal unter Verwendung einer Tabelle und wo vorhanden abgeglichen.

Vielleicht kein schlüssiger Test, aber persönlich hätte ich IN() dafür sowieso nicht benutzt.

Warum ermitteln Sie die Duplikate nicht auf diese Weise?

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

Dann verwenden, die als eine abgeleitete Tabelle im wo vorhanden Zustand:

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 
      ) 

siehe http://sqlfiddle.com/#!2/ede292/1 für die Abfrage unmittelbar über

+0

Die [innere Join-Syntax würde mir einfacher erscheinen] (http://sqlfiddle.com/#!2/ede292/2). Ich würde auch erwarten, dass der Join so effizient ist, obwohl sich die Abfragepläne nach SQL Fiddle unterscheiden, und ich bin nicht sehr gut darin, diese zu interpretieren. –

+0

ja, guter Punkt, innerer Join mit der gleichen abgeleiteten Tabelle ist auch eine Option. Die Ausführungspläne von sqlfiddle sind oft nicht so relevant, da es keine Indizes gibt und die Datenskala zu klein ist - aber es gibt keinen großen Unterschied zwischen den beiden Ansätzen. –