需要从postgresql表中动态选择JSON数组元素

时间:2015-01-15 04:43:17

标签: sql arrays json postgresql

我的数据如下:

ID   Name    Data
1    Joe     ["Mary","Joe"]
2    Mary    ["Sarah","Mary","Mary"]
3    Bill    ["Bill","Joe"]
4    James   ["James","James","James"]

我想编写一个从数组中选择LAST元素的查询,该查询不等于Name字段。例如,我希望查询返回以下结果:

ID   Name   Last
1    Joe    Mary
2    Mary   Sarah
3    Bill   Joe
4    James  (NULL)

我越来越近 - 我可以使用以下查询选择最后一个元素:

SELECT ID, Name,
(Data::json->(json_array_length(Data::json)-1))::text AS Last
FROM table;

ID    Name    Last
1     Joe     Joe
2     Mary    Mary
3     Bill    Joe
4     James   James

但是,我还需要一个级别 - 评估最后一个项目,如果它与名称字段相同,则尝试倒数第二个字段,依此类推。

任何帮助或指示都会非常感激!

1 个答案:

答案 0 :(得分:2)

Postgres 9.3中的

json

这在第9.3页很难,因为缺少有用的功能。

方法1

LEFT JOIN LATERAL中的json(干净且符合标准),在text投射到SELECT DISTINCT ON (1) t.id, t.name, d.last FROM tbl t LEFT JOIN LATERAL ( SELECT ('[' || d::text || ']')::json->>0 AS last FROM json_array_elements(t.data) d ) d ON d.last <> t.name ORDER BY 1, row_number() OVER () DESC; 之后修剪双引号。请参阅以下链接。

json

虽然这有效,而且我从未见过它失败,但是unnested元素的顺序取决于未记录的行为。见下面的链接!
使用表达式provided by @pozs in the comment改进了从textSELECT DISTINCT ON (1) id, name, NULLIF(last, name) AS last FROM ( SELECT t.id, t.name ,('[' || json_array_elements(t.data)::text || ']')::json->>0 AS last , row_number() OVER () AS rn FROM tbl t ) sub ORDER BY 1, (last = name), rn DESC; 的转换。仍然是hackish,但应该是安全的。

方法2

SELECT
  • rn列表中的Unnest(非标准)。
  • 并行连接行号(text)(更可靠)。
  • 如上所述转换为(last = name)
  • ORDER BY子句中的表达式SELECT最后对匹配的名称进行排序(但在NULL之前)。因此,只有在没有其他可用名称时才会选择匹配名称。最后一个链接如下 在NULLIF列表中,NULL将匹配的名称替换为json,并获得与上述相同的结果。

SQL Fiddle.

Postgres 9.4 中的

jsonbSELECT DISTINCT ON (1) t.id, t.name, d.last FROM tbl t LEFT JOIN LATERAL json_array_elements_text(data) WITH ORDINALITY d(last, rn) ON d.last <> t.name ORDER BY d.rn DESC;

第9.4页提供了所有必要的改进:

jsonb_array_elements_text()

jsonb使用{{1}}。其他一切都一样。

json / jsonb functions in the manual

相关答案以及更多解释: