为什么这个 CASE GREATEST 返回 NULL?

Why is this CASE GREATEST returning NULL?

我有一个看起来像这样的 select 查询,这样我就知道哪个日期是最新的 (dtStart) 以及哪个 table 最新的日期来自 (TableOrigin)。

WITH ranked_entity AS (
 SELECT
    table5.id,
    GREATEST(
        COALESCE(table1.dtEvaluationStart, '0000-00-00 00:00:00'), 
        COALESCE(table2.dtStart, '0000-00-00 00:00:00'), 
        COALESCE(table3.dtEvaluationStart, '0000-00-00 00:00:00'),
        COALESCE(table4.dtStart, '0000-00-00 00:00:00')) as dtStart,
    CASE GREATEST(
        COALESCE(table1.dtEvaluationStart, '0000-00-00 00:00:00'), 
        COALESCE(table2.dtStart, '0000-00-00 00:00:00'), 
        COALESCE(table3.dtEvaluationStart, '0000-00-00 00:00:00'),
        COALESCE(table4.dtStart, '0000-00-00 00:00:00')
        )
    WHEN table1.dtEvaluationStart THEN 'table1'
    WHEN table2.dtStart THEN 'table2'
    WHEN table3.dtEvaluationStart THEN 'table3'
    WHEN table4.dtStart THEN 'table4'
    END AS TableOrigin,
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY dtStart DESC) AS rn
 FROM table5 
    LEFT JOIN table1 ON table5.id = table1.fid 
    LEFT JOIN table2 ON table5.id = table2.fid
    LEFT JOIN table3 ON table5.id = table3.fid 
    LEFT JOIN table4 ON table5.id = table4.fid
)
    SELECT * FROM ranked_entity WHERE rn = 1;

但有时 TableOrigin 为 NULL,即使设置了 dtStart。为什么会这样?

例如,在一行中,dtStart 列的值“2020-05-14 14:34:18”取自 table3,因为它是列中的最新日期四个 table。这意味着列 TableOrigin 应该具有该行的值 'table3'。但是 TableOrigin 是 NULL。 并非所有行都发生这种情况,在某些行中,TableOrigin 值是正确的。

示例数据:

table5
+-----+
| id  |
+-----+
| 198 |
| 197 |
+-----+

table1
+-----+---------------------+
| fid |  dtEvaluationStart  |
+-----+---------------------+
| 198 | 2018-01-11 13:59:17 |
| 197 | 2020-01-21 09:29:35 |
+-----+---------------------+

table2
+-----+---------------------+
| fid |       dtStart       |
+-----+---------------------+
| 198 | 2018-02-01 12:57:50 |
| 197 | 2020-11-18 10:14:31 |
+-----+---------------------+

table3
+-----+---------------------+
| fid |       dtStart       |
+-----+---------------------+
| 197 | 2018-01-10 14:58:19 |
+-----+---------------------+

table4
+-----+---------------------+
| fid |       dtStart       |
+-----+---------------------+
| 198 | 2020-03-01 09:40:09 |
| 197 | 2020-03-04 08:10:59 |
+-----+---------------------+

output
+-----+---------------------+-------------+
| id  |       dtStart       | TableOrigin |
+-----+---------------------+-------------+
| 198 | 2020-03-01 09:40:09 | NULL        |
| 197 | 2020-11-18 10:14:31 | table2      |
+-----+---------------------+-------------+

dstart 总是会被设置。但是,如果值为'0000-00-00 00:00:00',那么所有比较的值(大概)都是NULL。常数值不匹配 NULL 因此列名不匹配。

NULL 值表达了这一点。

如果在这种情况下您还希望 dtstart 成为 NULL,则使用 NULLIF():

NULLIF(GREATEST(COALESCE(table1.dtEvaluationStart, '0000-00-00 00:00:00'), 
                COALESCE(table2.dtStart, '0000-00-00 00:00:00'), 
                COALESCE(table3.dtEvaluationStart, '0000-00-00 00:00:00'),
                COALESCE(table4.dtStart, '0000-00-00 00:00:00')
               ), '0000-00-00 00:00:00'
      )

尽管代码在 MySql 中运行良好,但在 MariaDB 中不起作用。
作为解决方法,您可以在 CASE 表达式中重复 COALESCE()

WITH ranked_entity AS (
 SELECT
    table5.id,
    GREATEST(
        COALESCE(table1.dtEvaluationStart, '0000-00-00 00:00:00'), 
        COALESCE(table2.dtStart, '0000-00-00 00:00:00'), 
        COALESCE(table3.dtEvaluationStart, '0000-00-00 00:00:00'),
        COALESCE(table4.dtStart, '0000-00-00 00:00:00')) as dtStart,
    CASE GREATEST(
        COALESCE(table1.dtEvaluationStart, '0000-00-00 00:00:00'), 
        COALESCE(table2.dtStart, '0000-00-00 00:00:00'), 
        COALESCE(table3.dtEvaluationStart, '0000-00-00 00:00:00'),
        COALESCE(table4.dtStart, '0000-00-00 00:00:00')
        )
    WHEN COALESCE(table1.dtEvaluationStart, '0000-00-00 00:00:00') THEN 'table1'
    WHEN COALESCE(table2.dtStart, '0000-00-00 00:00:00') THEN 'table2'
    WHEN COALESCE(table3.dtEvaluationStart, '0000-00-00 00:00:00') THEN 'table3'
    WHEN COALESCE(table4.dtStart, '0000-00-00 00:00:00') THEN 'table4'
    END AS TableOrigin,
    ROW_NUMBER() OVER (PARTITION BY table5.id ORDER BY table4.dtStart DESC) AS rn
 FROM table5 
    LEFT JOIN table1 ON table5.id = table1.fid 
    LEFT JOIN table2 ON table5.id = table2.fid
    LEFT JOIN table3 ON table5.id = table3.fid 
    LEFT JOIN table4 ON table5.id = table4.fid
)
SELECT * FROM ranked_entity WHERE rn = 1;

参见demo
结果:

>  id | dtStart             | TableOrigin | rn
> --: | :------------------ | :---------- | -:
> 197 | 2020-11-18 10:14:31 | table2      |  1
> 198 | 2020-03-01 09:40:09 | table4      |  1