从没有 NULL 元素的多列创建数组

Sat*_*iel 9 postgresql array json postgresql-9.4

我正在尝试构建一个查询以将旧表中的多个列聚合在一起,该表存储在类似的结构中,如下所示:

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);
Run Code Online (Sandbox Code Playgroud)

不是我想要的一个例子

这是我要构建的查询的示例:

SELECT ID, json_build_array(Tag_1, Tag_2, Tag_3, Tag_4) AS tags
FROM table
Run Code Online (Sandbox Code Playgroud)

问题是上面的查询将行中的 NULL 值添加到数组中:

ID  Tags
--------------------------------------------------
1   ['Router', 'Networking', 'Sale', null]
2   [null, 'Router', 'Networking', 'Sale']
3   [null, null, 'Networking', 'Sale']
4   [null, null, null, null]
Run Code Online (Sandbox Code Playgroud)

我想避免编写过于复杂的CASE WHEN语句来过滤掉 NULL,而且我对使用 PostgreSQL 的 JSON 数据类型还是个新手。在 Postgres 中构建 JSON 数组时,是否可以避免包含 NULL?

Eva*_*oll 12

我建议不要使用 JSON 数组,而是使用本机 SQL 数组语法,这可能会更快、更有效地存储。它也是更强的类型。根据文档,JSON 数组是“可能的异构类型”

我也不会经常这样做。我会改变表的模式,ARRAY在表本身上有一个(最好是 SQL)来存储标签,而不会在列中存储空值。这可以让您走上更正模式的道路。

构建数组

严格类型的 PostgreSQL 数组

只需使用 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}
Run Code Online (Sandbox Code Playgroud)

一个 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)
Run Code Online (Sandbox Code Playgroud)

无需手动过滤空值 coalesce

严格类型的 PostgreSQL 数组

您可以通过将上述内容包装在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 | {}
Run Code Online (Sandbox Code Playgroud)

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"]
Run Code Online (Sandbox Code Playgroud)