问题:是根据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
列中的第一个值。我可能在这里错了。
答案 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