PostgreSQL:计算一行中包含值的列数

Posted

技术标签:

【中文标题】PostgreSQL:计算一行中包含值的列数【英文标题】:PostgreSQL: Count number of columns in a row that contain a value 【发布时间】:2018-05-02 20:43:00 【问题描述】:

假设我有一个包含以下列的表格:

身份证

Col1

Col2

Col3

Col4

。 .

*请注意,我有 50 个这样的列 ('col1'...'col50')

对于每一行,我想计算以“col”开头的列数(例如 col1、col2 等),这些列还包含特定的整数值(例如 0)。

如果我的数据是:

Id, Col1, Col2, Col3, Col4
0, 0, 1, 2, 1
1, 1, 2, 0, 1
2, 1, 0, 5, 0
3, 0, 0, 0, 4

我的结果是:

Id, Count
0, 1
2, 1
2, 2
3, 3

显然这需要扩展到 50 列,所以我不想硬编码列名(我需要让它动态/循环)。我还将用我正在寻找的其他值重复这一点,问题的实质可以简化为上述结果。

我不知道如何做到这一点。我想到了一个函数,它接受一个列名、一个查找值和一个计数器,然后返回一个总的和当前的计数器位置或其他东西。我必须执行一个 WHILE 循环来调用该函数,直到达到结束计数器。

我们的目标是替换一些有效的东西,但是眼睛很痛并且不能重复使用(有 50 列):

case col1 when 0 then 1 else 0 end + case col col1 when 0 then 1 else 0 end...

【问题讨论】:

【参考方案1】:
with t(id, col1, col2, col3, col4) as (values
  (0,0,1,2,1),
  (3,0,0,0,4))
select * from t cross join lateral (
  select count(*) as cnt
  from json_each_text(to_json(t))
  where key like 'col%' and value = '0') as j;

Demolad2925 (c)

More about JSON functions.

【讨论】:

我真的很喜欢这种方法 :) Demo【参考方案2】:

你可以使用某种PIVOT

SELECT Id, cnt
FROM tab
JOIN LATERAL ( SELECT COUNT(*) AS cnt_0
               FROM (VALUES(col1),(col2),(col3),(col4)) s(c)
               WHERE s.c=0) AS sub ON true
ORDER BY id;

DBFiddle Demo

【讨论】:

【参考方案3】:

如果您事先知道列名,您可以构建一个数组、取消嵌套和聚合以获取行中零的计数。 示例:

WITH t (Id, Col1, Col2, Col3, Col4) AS (
VALUES
(0, 0, 1, 2, 1),
(1, 1, 2, 0, 1),
(2, 1, 0, 5, 0),
(3, 0, 0, 0, 4)
)
, unnested AS (
SELECT id, (UNNEST(ARRAY[Col1, Col2, Col3, Col4]) = 0)::INT is_zero
FROM t
)
SELECT id, SUM(is_zero) zeros
FROM unnested
GROUP BY 1

否则,使用json函数重塑表格,过滤列名(键)和值并聚合。

WITH t (Id, Col1, Col2, Col3, Col4) AS (
VALUES
(0, 0, 1, 2, 1),
(1, 1, 2, 0, 1),
(2, 1, 0, 5, 0),
(3, 0, 0, 0, 4)
)
SELECT id, COUNT(*)
FROM t, JSON_EACH(ROW_TO_JSON(t)) kv
WHERE kv.key ~ 'col\d+' 
  AND (kv.value::TEXT)::INT = 0
GROUP BY 1

【讨论】:

以上是关于PostgreSQL:计算一行中包含值的列数的主要内容,如果未能解决你的问题,请参考以下文章

为啥 distinct 不能与 Laravel + Postgresql 一起使用?

计算一行中空值的数量以除以(未知)列数

PHP MySQL:遍历每一行,并计算符合条件的列数

如何在R中通过分组变量统计有值的列数?

通过条件 (>) 计算每行的列数

如何过滤具有列表的列的数据框包含值[重复]