我有一个类似于以下的查询:
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
失败并且它不是 LEFT JOIN
那么 tab1.tab_qty
的值也是 NULL
并且应该返回 0
作为最终结果。
使用 MariaDB。 ID 字段为 INTEGER 类型,QTY 字段为 DECIMAL 类型。
答案 0 :(得分:0)
聚合函数的存在强制返回一行,即使没有找到匹配的内连接。考虑以下
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 IS NULL,因此返回 0,并且 IF 现在为真(因为 0 <= 0)因此使用下一个参数 tab1.tab_qty
和这也是 NULL,所以现在最外面的 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 |
+---------+
db<>fiddle here (为重复使用示例向 nick 道歉)
nb:您可以在那个小提琴上更改 dbms 版本