Je voudrais compter le nombre de présents par rangées de NULL dans une table sans énumérer les noms de colonnes. Par exemple:
WITH t as (VALUES
(NULL ,'hi',2,NULL,'null'),
('' ,'hi',2,3,'test'),
(NULL ,'hi',2,3,'null')
)
SELECT countnulls(t)
FROM t;
Aboutirait à:
numnulls
2
0
1
Le plus proche que je puisse obtenir est avec le piratage suivant de row_to_json()
:
select
(CHAR_LENGTH(row_to_json(t)::text)
- CHAR_LENGTH(REPLACE(row_to_json(t)::text, 'null', '')))/4 from t;
Ce qui est ... tout le piratage (pas de bonne manière). Cela fonctionne, en quelque sorte, mais il compte la chaîne 'null' comme une null lorsqu'il est présent dans les données réelles ou dans les noms de colonne. Donc, il est incorrect dans le cas ci-dessus.
Vous pouvez faire quelque chose comme ceci à l'aide de Fonctions JSONB , mais c'est une idée très horrible.
SELECT t,
count(*) FILTER (WHERE jsonb_typeof(jrow->key) = 'null')
FROM ( VALUES
(NULL ,'hi',2,NULL,'null'),
('' ,'hi',2,3,'test'),
(NULL ,'hi',2,3,'null')
) AS t(a,b,c,d,e)
CROSS JOIN LATERAL to_jsonb(t) AS j1(jrow)
CROSS JOIN LATERAL jsonb_object_keys(jrow) AS j2(key)
GROUP BY t;
t | count
------------------+-------
("",hi,2,3,test) | 0
(,hi,2,3,null) | 1
(,hi,2,,null) | 2
(3 rows)
Vous pouvez également développer qu'il soit tout exécuté dans une instruction case
à l'intérieur d'un sum()
qui serait rapide,
SELECT t,
SUM(
CASE WHEN a IS NULL THEN 1 ELSE 0 END
+
CASE WHEN b IS NULL THEN 1 ELSE 0 END
+
CASE WHEN c IS NULL THEN 1 ELSE 0 END
+
CASE WHEN d IS NULL THEN 1 ELSE 0 END
+
CASE WHEN e IS NULL THEN 1 ELSE 0 END
)
FROM ( VALUES
(NULL ,'hi',2,NULL,'null'),
('' ,'hi',2,3,'test'),
(NULL ,'hi',2,3,'null')
) AS t(a,b,c,d,e)
GROUP BY t;
t | sum
------------------+-----
("",hi,2,3,test) | 0
(,hi,2,3,null) | 1
(,hi,2,,null) | 2
(3 rows)