Sql 使用单个查询选择每列的最后一个值

Sql 使用单个查询选择每列的最后一个值,sql,null,Sql,Null,具有以下数据(空白表示为空): 如何在单个查询中获取每列的最后一个NOTNULL值?因此,给定数据的结果为: ColA ColB ColC 11 3 20 我没有发现太多,似乎与我描述的类似的函数是COALESCE,但在我的例子中它并没有像预期的那样工作。您可以使用子查询: select (select ColA from TheTable where ColA is not null order by ID desc limit 1) as ColA,

具有以下数据(空白表示为空):

如何在单个查询中获取每列的最后一个NOTNULL值?因此,给定数据的结果为:

ColA    ColB    ColC
11      3       20

我没有发现太多,似乎与我描述的类似的函数是
COALESCE
,但在我的例子中它并没有像预期的那样工作。

您可以使用子查询:

select
  (select ColA from TheTable where ColA is not null order by ID desc limit 1) as ColA,
  (select ColB from TheTable where ColB is not null order by ID desc limit 1) as ColB,
  (select ColC from TheTable where ColC is not null order by ID desc limit 1) as Col
SELECT first_value(cola) OVER (ORDER BY cola IS NULL, id DESC) AS cola
      ,first_value(colb) OVER (ORDER BY colb IS NULL, id DESC) AS colb
      ,first_value(colc) OVER (ORDER BY colc IS NULL, id DESC) AS colc
FROM   tbl
LIMIT  1;

看起来您必须使用纯SQL对每列运行单独的查询。对于一个只有3列的小表,应该可以

3窗口功能 您可以在一个查询中使用三个窗口函数执行相同的操作:不确定这是否比三个单独的子查询快:

select
  (select ColA from TheTable where ColA is not null order by ID desc limit 1) as ColA,
  (select ColB from TheTable where ColB is not null order by ID desc limit 1) as ColB,
  (select ColC from TheTable where ColC is not null order by ID desc limit 1) as Col
SELECT first_value(cola) OVER (ORDER BY cola IS NULL, id DESC) AS cola
      ,first_value(colb) OVER (ORDER BY colb IS NULL, id DESC) AS colb
      ,first_value(colc) OVER (ORDER BY colc IS NULL, id DESC) AS colc
FROM   tbl
LIMIT  1;
count()
作为窗口函数 您还可以利用
count()
不计算
NULL
值这一事实

WITH x AS (
   SELECT CASE WHEN count(cola) OVER w = 1 THEN cola ELSE NULL END AS cola
         ,CASE WHEN count(colb) OVER w = 1 THEN colb ELSE NULL END AS colb
         ,CASE WHEN count(colc) OVER w = 1 THEN colc ELSE NULL END AS colc
   FROM   tbl
   -- WHERE id > x -- safe to ignore a certain portion from a large table?
   WINDOW w AS (ORDER  BY id DESC)
   )
SELECT max(cola) AS cola, max(colb) AS colb, max(colc) AS colc
FROM   x
对于更大的表和更多的列,一个或一个过程函数将大大加快速度

递归CTE PL/pgSQL函数 我的钱花在这一款上,以获得最佳性能:

CREATE OR REPLACE FUNCTION f_last_nonull(OUT cola int
                                       , OUT colb int
                                       , OUT colc int) AS
$func$
DECLARE
   r record;
BEGIN

FOR r IN
   SELECT t.cola, t.colb, t.colc 
   FROM   tbl t
   ORDER  BY t.id DESC
LOOP
   IF cola IS NULL AND r.cola IS NOT NULL THEN cola := r.cola; END IF;
   IF colb IS NULL AND r.colb IS NOT NULL THEN colb := r.colb; END IF;
   IF colc IS NULL AND r.colc IS NOT NULL THEN colc := r.colc; END IF;

   EXIT WHEN NOT (cola IS NULL OR colb IS NULL OR colc IS NULL);
END LOOP;

END
$func$ LANGUAGE plpgsql;
电话:


使用
EXPLAIN ANALYZE
进行测试。如果您能回来比较一下这些解决方案,那就太好了。

在最后一个例子中,您是指最大值吗?@Blachshma否,尽管MAX实际上会返回相同的数据。。。只是巧合。那你怎么知道最后是什么呢?你有某种主键吗?@Blachshma我有一个时间戳,尽管我在示例中没有提到它。。。现在,我已经进行了编辑,删除了前面提到的巧合,并添加了一个INT键。通常不鼓励在已经有答案之后更改问题的性质,从而使现有答案无效。在这种情况下,请提出一个新问题。您始终可以链接回此链接以了解上下文。我回滚到原始版本递归CTE选项似乎仍然需要分别引用每一列。我说得对吗?您知道如何使查询接受任意数量的列吗?@user1598585:在系统目录中查找列后,您必须在plpgsql函数中构建动态SQL。可行,,但没有那么简单。@user1598585:我又添加了两个简单的解决方案。我希望带有窗口功能的解决方案比三个单独的查询更好——至少对于那些可以在内存中进行排序的表,因为数据只需要检索一次。@andrefsp:这一个解决方案展示了一个经常被忽略的功能:您可以非递归CTE(另外),即使使用递归声明
SELECT * FROM f_last_nonull();
cola | colb | colc
-----+------+------
 11  | 3    | 20