web-dev-qa-db-fra.com

Création d'un tableau à partir de plusieurs colonnes sans éléments NULL

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);

Un exemple de PAS CE QUE JE VEUX

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?

8
Sathariel

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.

Créer des tableaux

Tableau PostgreSQL strictement typé

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}

Un tableau JSON

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)

Filtrage des null sans manuel coalesce

Tableau PostgreSQL strictement typé

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 | {}

Tableau JSON

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"]
11
Evan Carroll

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  ;
3
ypercubeᵀᴹ