这是一个扩展版本相关的前面的问题 。 我已经张贴了一个新问题了欧文Brandstetter修改建议我这样做。 (我意识到,我其实是想这个,人家回答我的第一个问题后)
具有下列数据(空白表示NULL):
ID User ColA ColB ColC
1 1 15 20
2 1 11 4
3 1 3
4 2 5 5 10
5 2 6
6 2 8
7 1 1
我怎样才能得到每列的最后一个非空值的所有用户,最简单的方法是什么? 因此,对于给定的数据将是导致:
User ColA ColB ColC
1 11 1 20
2 6 8 10
我没有太多发现,似乎做类似我形容是一些功能COALESCE
,但预计将在我的情况下,这是行不通的。
注 :标准SQL如果可能的话,PostgreSQL的除外。 所涉及的列数可能会发生变化,从而不依赖于这三个特定列的解决方案是最好的。
“标准” SQL
类似我贴在前面的问题,一个递归CTE是优雅的,可能做到在标准SQL的最快方法-尤其是对每个用户的多行。
WITH RECURSIVE t AS (
SELECT row_number() OVER (PARTITION BY usr ORDER BY id DESC) AS rn
,usr, cola, colb, colc
FROM tbl
)
, x AS (
SELECT rn, usr, cola, colb, colc
FROM t
WHERE rn = 1
UNION ALL
SELECT t.rn, t.usr
, COALESCE(x.cola, t.cola)
, COALESCE(x.colb, t.colb)
, COALESCE(x.colc, t.colc)
FROM x
JOIN t USING (usr)
WHERE t.rn = x.rn + 1
AND (x.cola IS NULL OR x.colb IS NULL OR x.colc IS NULL)
)
SELECT DISTINCT ON (usr)
usr, cola, colb, colc
FROM x
ORDER BY usr, rn DESC;
- > sqlfiddle所请求的PostgreSQL。
唯一的非标准元件是DISTINCT ON
,这是一个扩展DISTINCT
在标准。 更换最终SELECT
这个为标准的SQL:
SELECT usr
,max(cola) As cola
,max(colb) As colb
,max(colc) As colc
FROM x
GROUP BY usr
ORDER BY usr;
对于“标准SQL”的要求存在一定的局限性。 该标准只存在于纸上。 没有RDBMS实现了100%的标准SQL - 这将是毫无意义,也因为这里的标准,并有包括无意义的部分。 可以说,PostgreSQL的实现是最接近标准之一。
PL / pgSQL函数
该解决方案是PostgreSQL特有的,而应该表现非常好。
我的同桌建设作为小提琴证明以上。
CREATE OR REPLACE FUNCTION f_last_nonull_per_user()
RETURNS SETOF tbl AS
$func$
DECLARE
_row tbl; -- table name can be used as row type
_new tbl;
BEGIN
FOR _new IN
SELECT * FROM tbl ORDER BY usr, id DESC
LOOP
IF _new.usr = _row.usr THEN
_row.id := _new.id; -- copy only id
IF _row.cola IS NULL AND _new.cola IS NOT NULL THEN
_row.cola := _new.cola; END IF; -- only if no value found yet
IF _row.colb IS NULL AND _new.colb IS NOT NULL THEN
_row.colb := _new.colb; END IF;
IF _row.colc IS NULL AND _new.colc IS NOT NULL THEN
_row.colc := _new.colc; END IF;
ELSE
IF _new.usr <> _row.usr THEN -- doesn't fire on first row
RETURN NEXT _row;
END IF;
_row := _new; -- remember row for next iteration
END IF;
END LOOP;
RETURN NEXT _row; -- return row for last usr
END
$func$ LANGUAGE plpgsql;
呼叫:
SELECT * FROM f_last_nonull_per_user();
返回整行-包括最小id
,我们需要填写的所有列。
这个查询很容易转换到MS SQL。 如果你需要更具体的东西加评论。 MySQL查询:
SQLFIDDLEExample
SELECT
t1.User,
(SELECT ColA
FROM Table1
WHERE ColA is not null
AND Table1.User = t1.User
ORDER BY ID DESC
LIMIT 1 ) as ColA,
(SELECT ColB
FROM Table1
WHERE ColB is not null
AND Table1.User = t1.User
ORDER BY ID DESC
LIMIT 1 ) as ColB,
(SELECT ColC
FROM Table1
WHERE ColC is not null
AND Table1.User = t1.User
ORDER BY ID DESC
LIMIT 1 ) as ColC
FROM Table1 t1
GROUP BY t1.User
结果:
| USER | COLA | COLB | COLC |
-----------------------------
| 1 | 11 | 1 | 20 |
| 2 | 6 | 8 | 10 |