Edw*_*own 5 postgresql null isnull postgresql-9.6
我想在不枚举列名的情况下计算表中每行存在的空值数。例如:
WITH t as (VALUES
(NULL ,'hi',2,NULL,'null'),
('' ,'hi',2,3,'test'),
(NULL ,'hi',2,3,'null')
)
SELECT countnulls(t)
FROM t;
Run Code Online (Sandbox Code Playgroud)
会导致:
numnulls
2
0
1
Run Code Online (Sandbox Code Playgroud)
我能得到的最接近的是以下黑客row_to_json():
select
(CHAR_LENGTH(row_to_json(t)::text)
- CHAR_LENGTH(REPLACE(row_to_json(t)::text, 'null', '')))/4 from t;
Run Code Online (Sandbox Code Playgroud)
这是......相当的黑客(不是很好)。它可以工作,有点,但是当它出现在实际数据或列名中时,它会将字符串 'null' 计为 NULL。所以在上述情况下是不正确的。
Erw*_*ter 10
对于 Postgres 9.6或更高版本,请使用num_nulls()
WITH t(a, b, c, d, e) AS (
VALUES
(NULL ,'hi',2,NULL,'null')
, ('' ,'hi',2,3,'test')
, (NULL ,'hi',2,3,'null')
)
SELECT num_nulls(a,b,c,d,e)
FROM t;
Run Code Online (Sandbox Code Playgroud)
准确返回您想要的结果,适用于任何数据类型的组合。
num_nulls(VARIADIC "any")...返回空参数的数量
对于 Postgres 9.5或更早版本,转换为text[],array_remove(arr, null)并使用剩余的数组长度进行精确计数:
SELECT 5 - cardinality(array_remove(ARRAY[a::text,b::text,c::text,d::text,e::text], null))
FROM t;
Run Code Online (Sandbox Code Playgroud)
任何类型都可以转换为text. text当然,对于列来说,演员表是多余的。
array_remove()需要 Postgres 9.3 或更高版本。
cardinality()需要 Postgres 9.4 或更高版本。替换为array_length(arr, 1)旧版本。
在实际表(或其他注册对象,如视图或物化视图)上构建时,我们可以从系统目录中检索列名,pg_attribute以使用动态 SQL 完全自动化。喜欢:
CREATE OR REPLACE FUNCTION f_num_nulls(_tbl regclass)
RETURNS SETOF int AS
$func$
BEGIN
RETURN QUERY EXECUTE format(
'SELECT num_nulls(%s) FROM %s'
, (SELECT string_agg(quote_ident(attname), ', ') -- column list
FROM pg_attribute
WHERE attrelid = _tbl
AND NOT attisdropped -- no dropped (dead) columns
AND attnum > 0) -- no system columns
, _tbl
);
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
称呼:
SELECT * FROM f_num_nulls('myschema.tbl');
Run Code Online (Sandbox Code Playgroud)
返回当前物理顺序中每一行的计数。没有别的,绝对是通用的。
有关的:
我们可以也通过每个行返回一个计数使用多态函数它。有关的:
在不太可能的情况下,即使 Postgres 也不知道列名(例如来自VALUES您示例中的表达式),请转换为文档类型(json, jsonb, xml, hstore)以获取句柄,如 ypercube (现在已删除评论)和Evan 所示。
但是匿名记录没有主键或每个定义的任何其他唯一属性。在每个LATERAL子查询中计数以防止错误聚合。演示jsonb:
SELECT *
FROM (
VALUES
(NULL ,'hi',2,NULL,'null')
, (NULL ,'hi',2,NULL,'null') -- duplicate row !!!
, ('' ,'hi',2,3,'test')
, (NULL ,'hi',2,3,'null')
) t -- column names unknown
, LATERAL (
SELECT count(*) FILTER (WHERE j.value = jsonb 'null') AS num_nulls
FROM jsonb_each(to_jsonb(t)) j
) c;
Run Code Online (Sandbox Code Playgroud)
或者使用json: 可能会快一点,因为转换更便宜。
演示 3 种不同的方式:
SELECT *
FROM (
VALUES
(NULL ,'hi',2,NULL,'null')
, (NULL ,'hi',2,NULL,'null')
, ('' ,'hi',2,3,'test')
, (NULL ,'hi',2,3,'null')
) t -- column names unknown
, to_json(t) j
, LATERAL (
SELECT count(*) FILTER (WHERE j1.value::text = 'null') AS num_nulls1
FROM json_each(to_json(t)) j1
) c1
, LATERAL (
SELECT count(*) FILTER (WHERE j->>k IS NULL) AS num_nulls2
FROM json_object_keys(j) k
) c2
, LATERAL (
SELECT count(*) - count(j->>k ) AS num_nulls3
FROM json_object_keys(j) k
) c3;
Run Code Online (Sandbox Code Playgroud)
db<>在这里摆弄
| 归档时间: |
|
| 查看次数: |
4531 次 |
| 最近记录: |