#sql #mariadb
Вопрос:
У меня есть запрос, похожий на следующий:
SELECT
IFNULL(IF(IFNULL(tab2.tab_qty, 0) <= 0,
tab1.tab_qty,
SUM(tab1.tab_qty IFNULL(tab2.tab_qty, 0))
) ,0) AS tab_qty
FROM my_table tab1
JOIN my_table tab2 ON (tab1.table_id = tab2.tab_table_id)
WHERE tab1.table_id = ?
Если tab1.table_id
есть 1
и записи не существует, то tab2.tab_table_id = 1
почему запрос возвращает результаты, равные значению tab1.tab_qty
?
Моя линия мышления заключается JOIN
в том, что сбой tab2.tab_qty
null
приводит IF
к тому, что они попадают в истинную ветвь. Это должно возвращать значение tab1.tab_qty
подлежащего возврату, но так JOIN
как сбой и это не a LEFT JOIN
, то значение tab1.tab_qty
также NULL
является и должно возвращаться 0
в качестве конечного результата.
Используя MariaDB. Поля идентификатора имеют ЦЕЛОЧИСЛЕННЫЙ тип, а поля количества-ДЕСЯТИЧНЫЙ тип.
Комментарии:
1. Он действительно возвращает 0: dbfiddle.uk/…
2. Когда вы введете агрегат, вы получите в результате одну строку. Сама сумма равна нулю.
3. @shawnt00, но эта сторона вопроса «ЕСЛИ» не оценивается.
4. @Ник, используя этот идентичный запрос с переименованными только таблицами и столбцами, я получаю другой результат на своем сервере. Версия 10.3.22 MariaDB. Такой растерянный.
5. К сожалению, если мы не можем воспроизвести ошибку, трудно дать совет по ее исправлению.
Ответ №1:
Наличие функции агрегирования заставляет возвращать строку, даже если для внутреннего соединения не найдено совпадения. Учесть следующее
create table my_table (table_id int, tab_qty decimal, tab_table_id int)
insert into my_table (table_id, tab_qty, tab_table_id) values
(1, 10, 2),
(2, 5, 2)
select
tab1.table_id as no_join_is_no_row
FROM my_table tab1
INNER JOIN my_table tab2 ON tab1.table_id = tab2.tab_table_id
WHERE tab1.table_id = 1
Ни Одна Строка Не Возвращена
-------------------
| no_join_is_no_row |
-------------------
Но если мы сейчас запросим sum(tab1.tab_qty)
в том же простом запросе, где все еще нет совпадающих строк в таблице:
select
sum(tab1.tab_qty) forced_row_by_aggregation
FROM my_table tab1
INNER JOIN my_table tab2 ON tab1.table_id = tab2.tab_table_id
WHERE tab1.table_id = 1
Результат имеет 1 строку
---------------------------
| forced_row_by_aggregation |
---------------------------
| null |
---------------------------
Таким образом, в вашем исходном запросе IF(IFNULL(tab2.tab_qty, 0) <= 0
tab2.tab_qty ИМЕЕТ значение NULL, поэтому возвращается 0, а значение IF теперь равно true (так как 0 <= 0), поэтому используется следующий параметр tab1.tab_qty
, который также равен НУЛЮ, поэтому теперь самый внешний IFNULL(....,0)
срабатывает и возвращает ноль.
Вы можете отследить это, изменив запрос, чтобы возвращать что-то, отличное от нулей, с помощью различных значений IFNULL, например
SELECT
IFNULL(IF(IFNULL(tab2.tab_qty, -1) <= 0, -- minus 1
tab1.tab_qty,
SUM(tab1.tab_qty IFNULL(tab2.tab_qty, -2)) -- minus 2
) ,-3) AS tab_qty -- minus 3
FROM my_table tab1
INNER JOIN my_table tab2 ON (tab1.table_id = tab2.tab_table_id)
WHERE tab1.table_id = 1
Который Возвращает
---------
| tab_qty |
---------
| -3 |
---------
бд<>скрипка <>здесь
(приношу извинения Нику за повторное использование примера)
примечание: Вы можете изменить версию СУБД на этой скрипке
Комментарии:
1. Извинений не требуется, я рад, что это было полезно. Не уверен, что я согласен с вашим последним разделом;
-1
и-2
-это промежуточные результаты, которые никогда не появятся на выходе. Возможно, также стоит отметить, что даже при наличии теста, который означает, что функция агрегирования не может быть выполнена, она все равно выполняется, например dbfiddle.uk/…2. @Ник -1 -2 -3 был предназначен только для того, чтобы четко различать, даже если его никогда не видели. Я думал , что обратил внимание на то, что строка появляется, даже если очень похожий запрос не возвращает ни одной строки, было ли это неясно. мммм
3. Я просто подумал, что было бы странно использовать значения
-1
и-2
, потому что они никогда не появятся на выходе, независимо от того, каковы входные данные. Но, может быть, именно так работает мой мозг… другой моей точкой зрения было то, что в скрипке, с которой я связан,SUM
никогда не будет вычисляться, но само ее присутствие в запросе вызывает агрегацию независимо от того, содержит ли результирующий набор 0 или любое количество строк.