为什么这个查询会返回结果?

时间:2021-04-06 04:05:22

标签: 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_id1 且不存在记录,其中 tab2.tab_table_id = 1 为什么查询返回的结果等于 tab1.tab_qty 的值?

我的思路是 JOIN 失败,所以 tab2.tab_qtynull 导致 IF 进入真正的分支。这应该返回要返回的 tab1.tab_qty 的值,但是由于 JOIN 失败并且它不是 LEFT JOIN 那么 tab1.tab_qty 的值也是 NULL并且应该返回 0 作为最终结果。

使用 MariaDB。 ID 字段为 INTEGER 类型,QTY 字段为 DECIMAL 类型。

1 个答案:

答案 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 版本

相关问题