我的数据如下:
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
但是,我还需要一个级别 - 评估最后一个项目,如果它与名称字段相同,则尝试倒数第二个字段,依此类推。
任何帮助或指示都会非常感激!
答案 0 :(得分:2)
json
这在第9.3页很难,因为缺少有用的功能。
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改进了从text
到SELECT 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,但应该是安全的。
SELECT
rn
列表中的Unnest(非标准)。text
)(更可靠)。(last = name)
。ORDER BY
子句中的表达式SELECT
最后对匹配的名称进行排序(但在NULL之前)。因此,只有在没有其他可用名称时才会选择匹配名称。最后一个链接如下
在NULLIF
列表中,NULL
将匹配的名称替换为json
,并获得与上述相同的结果。jsonb
或SELECT 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
相关答案以及更多解释: