我正在创建一个对每个逻辑行都有一系列修订的表,并使用NULL值来指示特定单元格与上一个修订版本具有相同的值。例如:
id | logical_id | revision | x | y | z | other
---+------------+----------+---+---+---+--------
1 | 1 | 1 | 1 | 2 | 5 | blue
2 | 2 | 1 | 3 | 5 | 9 | red
3 | 1 | 2 | 9 | | |
4 | 2 | 2 | | 7 | | orange
5 | 1 | 3 | | 6 | |
6 3 | 1 | 0 | 0 | 0 | white
我需要一个查询,它接受每个logical_id并构建一行,其中包含修订后每个字段的最新条目("常规字段"),在本例中为x
,{{1} },y
和z
。这些字段的数量是任意的,尽管完全可以接受的是,查询需要根据这些字段的实际内容进行修改(我希望它)。
因此对于上表,输出将为:
other
我发现了这个问题," Database: Select last non-null entries",这似乎与我的问题几乎完全相同,但问题是关于Postgresql,并且给出的解决方案是使用语言SQLite中不可用的构造(FIRST_VALUE,PARTITION BY?),似乎只回答部分问题(例如,只查找单个逻辑id的结果),或者当我在SQLite中尝试它们时,它们根本就没有工作
作为额外的奖励,我还希望能够通过设置所有"常规字段"来标记logical_id | x | y | z | other
-----------+---+---+---+--------
1 | 9 | 6 | 5 | blue
2 | 3 | 7 | 9 | orange
3 | 0 | 0 | 0 | white
被删除。如果可能的话,为NULL。
答案 0 :(得分:1)
要查找每个逻辑ID的最大修订版行的非NULL值,可以使用子查询:
SELECT logical_id,
(SELECT x
FROM MyTable
WHERE logical_id = T.logical_id
AND x IS NOT NULL
ORDER BY revision DESC
LIMIT 1) AS x,
(SELECT y
FROM MyTable
WHERE logical_id = T.logical_id
AND y IS NOT NULL
ORDER BY revision DESC
LIMIT 1) AS y,
...
FROM (SELECT DISTINCT logical_id
FROM MyTable
-- WHERE ...
) AS T
或者,可以使用GROUP BY执行此操作,但是为了在使用MAX搜索最大修订版时能够获取实际列值,需要将修订版和其他值组合成单个字符串,然后提取列值:
SELECT logical_id,
substr(max(printf('%9d', revision) || x), 10) AS x,
substr(max(printf('%9d', revision) || y), 10) AS y,
...
FROM MyTable
-- WHERE ...
GROUP BY logical_id
要删除最新修订版全为NULL的逻辑ID,请添加如下WHERE子句:
...
WHERE logical_id NOT IN (SELECT logical_id
FROM (SELECT logical_id,
max(revision) AS revision
FROM MyTable
GROUP BY logical_id)
JOIN MyTable USING (logical_id, revision)
WHERE x IS NULL
AND y IS NULL
AND z IS NULL
AND other IS NULL)
...
答案 1 :(得分:1)
SQLite 3.25引入了窗口函数:
SELECT DISTINCT
logical_id
,FIRST_VALUE(x) OVER(PARTITION BY logical_id ORDER BY CASE WHEN x IS NULL THEN -1
ELSE id END DESC) AS x
,FIRST_VALUE(y) OVER(PARTITION BY logical_id ORDER BY CASE WHEN y IS NULL THEN -1
ELSE id END DESC) AS y
,FIRST_VALUE(z) OVER(PARTITION BY logical_id ORDER BY CASE WHEN z IS NULL THEN -1
ELSE id END DESC) AS z
,FIRST_VALUE(other) OVER(PARTITION BY logical_id ORDER BY CASE WHEN other IS NULL
THEN -1 ELSE id END DESC) AS other
FROM tab;
输出:
+-------------+----+----+----+--------+
| logical_id | x | y | z | other |
+-------------+----+----+----+--------+
| 1 | 9 | 6 | 5 | blue |
| 2 | 3 | 7 | 9 | orange |
| 3 | 0 | 0 | 0 | white |
+-------------+----+----+----+--------+