Предложения MySql IN, пытающиеся сопоставить список кортежей IN

Я пытаюсь выбрать повторяющиеся записи на основе совпадения трех столбцов. Список троек может быть очень длинным (1000), поэтому я хотел бы сделать его кратким.

Когда у меня есть список размером 10 (известные дубликаты), он соответствует только 2 (кажущимся случайным) и пропускает остальные 8. Я ожидал, что вернется 10 записей, но увидел только 2.

Я сузил его до этой проблемы:

Это возвращает одну запись. Ожидание 2:

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

Возвращает две записи, как и ожидалось:

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

Есть идеи, почему первый запрос возвращает только одну запись?


person user3877299    schedule 25.07.2014    source источник
comment
Мне не удалось воспроизвести проблему на моей машине (MySQL 5.6.14). Можешь сделать скрипку?   -  person Vatev    schedule 25.07.2014
comment
Можете ли вы отредактировать свой вопрос и описать типы данных столбцов (SHOW CREATE TABLE ali)? Если вы используете FLOAT или DOUBLE для столбца x, это может привести к сбою сравнения на равенство, поскольку точное значение округляется неожиданным образом. Также укажите, какую именно версию MySQL вы используете.   -  person Bill Karwin    schedule 25.07.2014
comment
Можете ли вы опубликовать код, который вы используете. Я скопировал это в таблицу, и сначала это выглядело как значение операнда, но это была моя вина, что я пропустил набор скобок. Как и Ватев, я не смог воспроизвести проблему   -  person DanceSC    schedule 25.07.2014
comment
Не знаю, как сделать это скрипкой. Я изменил свой запрос, чтобы использовать: (a,b,c) = (...) или (a,b,c) = () или (a,b,c) = ()... Не идеально. знаю, но это работает. Я опубликую код, когда у меня будет больше времени. Спасибо за ваш интерес.   -  person user3877299    schedule 28.07.2014
comment
google for sql fiddle (sqlfiddle.com), это платформа для публикации и тестирования SQL. Или просто опубликуйте свое заявление о создании таблицы здесь.   -  person dube    schedule 29.07.2014


Ответы (1)


Я бы посоветовал вам не использовать IN() для этого, вместо этого используйте запрос, где существует, например:

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

Мне удалось воспроизвести проблему (сравните http://sqlfiddle.com/#!2/7d2658/6 на http://sqlfiddle.com/#!2/fe851/1 как MySQL 5.5.3), где, если столбец x был числовым, а значение отрицательное, оно НЕ совпадало с использованием IN (), но совпадало, когда числовое или десятичное с использованием таблицы и где существует.

Возможно, это не окончательный тест, но лично я бы все равно не использовал IN() для этого.

Почему вы не определяете дубликаты таким образом?

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

Затем используйте это как производную таблицу в условии «где существует»:

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
             )

см. http://sqlfiddle.com/#!2/ede292/1 для запроса сразу над

person Paul Maxwell    schedule 30.07.2014
comment
синтаксис внутреннего соединения кажется мне более простым. Я также ожидаю, что объединение будет таким же эффективным, хотя, согласно SQL Fiddle, планы запросов действительно различаются, и я не очень хорошо их интерпретирую. - person Andriy M; 30.07.2014
comment
да, хороший момент, внутреннее соединение с использованием той же производной таблицы также является вариантом. Планы выполнения sqlfiddle часто не так важны, поскольку нет индексов, а масштаб данных слишком мал, но в этих двух подходах нет большой разницы. - person Paul Maxwell; 30.07.2014