我目前正在使用COALESCE
函数从字段列表中获取第一个NOT NULL值。例如:
COALESCE(header_to_node_13.subsetname, header_to_node_12.subsetname,
header_to_node_11.subsetname, header_to_node_10.subsetname,
header_to_node_9.subsetname, header_to_node_8.subsetname,
header_to_node_7.subsetname, header_to_node_6.subsetname,
header_to_node_5.subsetname, header_to_node_4.subsetname,
header_to_node_3.subsetname, header_to_node_2.subsetname,
header_to_node_1.subsetname,
header_to_node.subsetname, header_to_node.setname) AS prctr1
我需要修改逻辑,以便我也可以获取COALESCE
值右侧的值,这样就可以比较这两个值来填充新创建的字段。
例如,如果COALESCE
值为header_to_node_5.subsetname
,我还需要抓取header_to_node_4.subsetname
,因此可以在CASE
语句中使用这两个值。
如果第二个值(header_to_node_4.subsetname
)为空,我想要第一个值(header_to_node_5.subsetname
)。如果第二个值是NOT NULL,我想使用第二个值。
我很难知道如何获取第二个值。我正在使用Greenplum / PostgreSQL 8.2
答案 0 :(得分:3)
如果我正确理解了您的要求,那么您有一组有序的字段,可能来自将多个表连接在一起,并且您希望获得第一个非空字段和紧跟其后的字段。
在这种情况下,您可以使用LATERAL
:这允许您引用前面的FROM
项提供的字段:
SELECT id, COALESCE(t.b, t.a) AS result
FROM mytable,
LATERAL (
SELECT x.v, LEAD(x.v) OVER (ORDER BY x.i)
FROM (
VALUES (header_to_node_13, 1), (header_to_node_12, 2),
(header_to_node_11, 3), (header_to_node_10, 4),
(header_to_node_9, 5), (header_to_node_8, 6),
(header_to_node_7, 7), (header_to_node_6, 8),
(header_to_node_5, 9), (header_to_node_4, 10),
(header_to_node_3, 11), (header_to_node_2, 12),
(header_to_node_1, 13)) AS x(v,i)
ORDER BY
CASE WHEN x.v IS NULL THEN 1 ELSE 0 END,
x.i
LIMIT 1 ) AS t(a, b)
在VALUES
子查询中使用LATERAL
实质上构造了一个表,其中包含查询的COALESCE
函数引用的所有字段。订单字段x.i
也包含在VALUES
中,以便定义字段顺序。
设置此内联表后,您可以在所有字段上轻松执行ORDER BY
和LIMIT 1
,以便找到第一个非空字段。 LEAD
窗口函数用于获取下一个字段。
注意:为了简单起见,我重新命名了OP中的字段,例如: header_to_node_13.subsetname
到header_to_node_13
。我也省略了COALESCE
内的一些字段。
答案 1 :(得分:1)
这应该适用于Postgres 9.4及以上版本:
SELECT val, nextval
FROM
(
SELECT
val,
lag(val) OVER w as prevval,
lead(val) OVER w as nextval
FROM UNNEST(ARRAY[
header_to_node_13.subsetname, header_to_node_12.subsetname,
header_to_node_11.subsetname, header_to_node_10.subsetname,
header_to_node_9.subsetname, header_to_node_8.subsetname,
header_to_node_7.subsetname, header_to_node_6.subsetname,
header_to_node_5.subsetname, header_to_node_4.subsetname,
header_to_node_3.subsetname, header_to_node_2.subsetname,
header_to_node_1.subsetname,
header_to_node.subsetname, header_to_node.setname
]) WITH ORDINALITY AS u(val, pos)
WINDOW w AS (ORDER BY pos)
) t
WHERE
prevval IS NULL AND
val IS NOT NULL
答案 2 :(得分:1)
为了清楚起见,我简化了列名。
对于 任何输入类型 和 任意数量的值 ,请将其设为polymorphic函数采用可变数量的参数(VARIADIC
):
CREATE OR REPLACE FUNCTION coalesce2(VARIADIC ANYARRAY)
RETURNS ANYELEMENT AS
$func$
BEGIN
FOR i IN 1 .. array_upper($1, 1)
LOOP
IF $1[i] IS NOT NULL THEN
RETURN COALESCE($1[i+1], $1[i]);
END IF;
END LOOP;
RETURN NULL; -- we only come this far if all values are NULL
END
$func$ LANGUAGE plpgsql IMMUTABLE;
呼叫:
SELECT coalesce2(h13, h12, h11, h10, ...);
VARIADIC
参数作为函数内的一个数组可见,我们可以使用FOREACH
循环:
或者您可以使用普通的SQL函数来封装以下某个逻辑:
SELECT COALESCE(lead(elem) OVER (ORDER BY ord), elem) AS result
FROM unnest(ARRAY[h13, h12, h11, h10, ...]) WITH ORDINALITY u(elem, ord)
ORDER BY elem IS NULL, ord
LIMIT 1;
WITH ORDINALITY
(如@Nick already displayed)要求Postgres 9.4 或更高版本。此解决方案的工作方式与SQL标准相同。但是,并不是严格要求的。这也有效:
SELECT COALESCE(lead(elem) OVER (), elem) AS result
FROM unnest(ARRAY[h13, h12, h11, h10, ... ]) elem
ORDER BY elem IS NULL
LIMIT 1;
它依赖于保留数组元素顺序的unnest()
的Postgres实现,窗口函数lead()
使用此给定顺序,之前更晚{{ 1}}重新排序行。 SQL标准没有严格保证,但它适用于Postgres的所有可用版本。考虑:
您还可以使用带有手动编号的ORDER BY
表达式,以确保安全且符合标准,如@Giorgos demonstrated或简化查询:
VALUES
SQL Fiddle展示所有。