SELECT子句中的COALESCE功能

时间:2016-12-11 17:37:07

标签: mysql tsql coalesce

问题:是根据id命令查找表中的最后一个非NULL值,在此处找到http://sqlmag.com/t-sql/last-non-null-puzzle

CREATE TABLE Score(`id` int, `col1` INT NULL);
INSERT INTO Score
    (`id`, `col1`)
VALUES
    (2, NULL),
    (3, 10),
    (5, -1),
    (7, NULL),
    (11, NULL),
    (13, -12),
    (17, NULL),
    (19, NULL),
    (23, 1759);

期望的输出:

id          col1        lastval
----------- ----------- -----------
2           NULL        NULL
3           10          10
5           -1          -1
7           NULL        -1
11          NULL        -1
13          -12         -12
17          NULL        -12
19          NULL        -12
23          1759        1759

我在SQLFiddle MySQL 5.6中的代码

SELECT s1.id, COALESCE(s2.col1)
FROM score s1 JOIN score s2
ON s1.id >= s2.id
GROUP BY s1.id
ORDER BY s1.id, s2.id DESC

我理解的COALESCE给出了列表中遇到的第一个非NULL值。但它为所有列提供(null)。你能指出COALESCE无效的原因吗? 此外,我意识到删除COALESCE也应回答问题,因为GROUP BY子句返回s2.col1列中的第一个值。我可能在这里错了。

2 个答案:

答案 0 :(得分:2)

COALESCE()在其参数列表中返回第一个非空值没有将COALESCE()应用于分组行集上的同一表达式的隐式行为。它不是像SUM()或GROUP_CONCAT()那样的聚合函数。

在你做的时候用一个参数是没有意义的,因为你只给了它一个参数。所以它与将s2.col1放在查询的选择列表中而不将其置于COALESCE()调用中完全相同。

然后,当引用GROUP BY函数中的非分组列时,您将保留MySQL的默认行为:MySQL从组中的某一行任意选择s2.col1的值。实际上,这是按索引顺序读取的组中的第一行,但您不应该依赖于此。

因此,在您的示例中,您的联接将每行s1连接到所有行s2,以使s2.id更早。每个组都包含表{001}中的第一行。对于col1,该行有一个NULL。

我通读了你想要解决的SQL难题。它在MySQL中会特别尴尬,因为MySQL不支持窗口函数。

在这些情况下的解决方案通常涉及使用MySQL User-Defined Variables,当您的查询迭代表中的行时,它会更改值。这可能非常棘手。

以下是我如何以可移植的方式解决问题(没有MySQL用户变量):

s2.id=2

以下是使用MySQL用户变量解决问题的方法:

SELECT s1.id, s1.col1, s2.col1 as lastval
FROM Score AS s1
LEFT OUTER JOIN Score AS s2 ON s2.id <= s1.id AND s2.col1 IS NOT NULL
LEFT OUTER JOIN Score AS s3 ON s3.id > s2.id AND s3.id <= s1.id AND s3.col1 IS NOT NULL
WHERE s3.id IS NULL
ORDER BY s1.id;

我会避免您在下面的评论中发布的查询,因为它使用了相关的子查询。相关的子查询通常不利于性能。

答案 1 :(得分:0)

我没有得到你想要做的事情,而且我不确定它是否适用于mysql,但这个适用于tsql。我希望它有所帮助

    SELECT s1.id, COALESCE(min(s2.col1),0) FROM score s1 
    JOIN score s2 ON s1.id >= s2.id GROUP BY s1.id
    ORDER BY s1.id, min(s2.col1) DESC