J'essaie de créer une requête pour agréger plusieurs colonnes dans une table héritée stockée dans une structure similaire à celle ci-dessous:
CREATE TEMPORARY TABLE foo AS
SELECT * FROM ( VALUES
(1,'Router','Networking','Sale',NULL),
(2,NULL,'Router','Networking','Sale'),
(3,NULL,NULL,'Networking','Sale'),
(4,NULL,NULL,NULL,NULL)
) AS t(id,tag_1,tag_2,tag_3,tag_4);
Voici un exemple de la requête que je veux construire:
SELECT ID, json_build_array(Tag_1, Tag_2, Tag_3, Tag_4) AS tags
FROM table
Le problème est que la requête ci-dessus ajoute les valeurs NULL des lignes au tableau:
ID Tags
--------------------------------------------------
1 ['Router', 'Networking', 'Sale', null]
2 [null, 'Router', 'Networking', 'Sale']
3 [null, null, 'Networking', 'Sale']
4 [null, null, null, null]
Je veux éviter d'avoir à écrire un _ trop compliqué CASE WHEN
instruction pour filtrer les valeurs NULL et je suis encore novice dans l'utilisation des types de données JSON de PostgreSQL. Existe-t-il de toute façon que je peux éviter d'inclure des valeurs NULL lors de la construction d'un tableau JSON dans Postgres?
Je suggérerais de ne pas utiliser un tableau JSON, et d'utiliser plutôt la syntaxe native du tableau SQL qui est probablement beaucoup plus rapide et plus efficacement stockée. Il est également plus typé. Le tableau JSON est "éventuellement de type hétérogène" par la documentation.
Je ne ferais pas non plus cela régulièrement. Je modifierais le schéma de la table pour avoir un ARRAY
(de préférence SQL) sur la table elle-même pour stocker les balises sans jamais stocker null dans les colonnes. Cela peut vous mettre sur la voie de la correction du schéma.
Utilisez simplement le constructeur littéral ARRAY.
SELECT id, ARRAY[tag_1,tag_2,tag_3,tag_4] FROM foo;
id | array
----+-------------------------------
1 | {Router,Networking,Sale,NULL}
2 | {NULL,Router,Networking,Sale}
3 | {NULL,NULL,Networking,Sale}
4 | {NULL,NULL,NULL,NULL}
SELECT id, json_build_array(tag_1,tag_2,tag_3,tag_4) FROM foo;
id | json_build_array
----+----------------------------------------
1 | ["Router", "Networking", "Sale", null]
2 | [null, "Router", "Networking", "Sale"]
3 | [null, null, "Networking", "Sale"]
4 | [null, null, null, null]
(4 rows)
coalesce
Vous pouvez facilement filtrer les valeurs nulles en une seule passe en enveloppant ce qui précède dans array_remove
.
SELECT id, array_remove(ARRAY[tag_1,tag_2,tag_3,tag_4], null)
FROM foo;
id | array_remove
----+--------------------------
1 | {Router,Networking,Sale}
2 | {Router,Networking,Sale}
3 | {Networking,Sale}
4 | {}
SELECT id,jsonb_agg(elem)
FROM (SELECT id, ARRAY[tag_1,tag_2,tag_3,tag_4] FROM foo) AS g
CROSS JOIN LATERAL unnest(g.array)
WITH ORDINALITY AS t(elem,ord)
WHERE elem IS NOT NULL
GROUP BY id
ORDER BY id;
id | jsonb_agg
----+----------------------------------
1 | ["Router", "Networking", "Sale"]
2 | ["Router", "Networking", "Sale"]
3 | ["Networking", "Sale"]
Cela devrait fonctionner:
SELECT
id,
( SELECT json_agg(tag ORDER BY no)
FROM
( SELECT 1, tag_1 UNION ALL
SELECT 2, tag_2 UNION ALL
SELECT 3, tag_3 UNION ALL
SELECT 4, tag_4
) AS x (no, tag)
WHERE tag IS NOT NULL
) AS tags
FROM t ;