简体   繁体   English

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

[英]Need to select a JSON array element dynamically from a postgresql table

I have data as follows: 我的数据如下:

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

I want to write a query that selects the LAST element from the array, which does not equal the Name field. 我想编写一个查询,该查询从数组中选择LAST元素,这不等于Name字段。 For example, I want the query to return the following results: 例如,我希望查询返回以下结果:

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

I am getting close - I can select the last element with the following query: 我正在接近-我可以使用以下查询选择最后一个元素:

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

However, I need one more level - to evaluate the last item, and if it is the same as the name field, to try the next to last field, and so on. 但是,我还需要一个级别-评估最后一项,如果它与名称字段相同,则尝试倒数第二个字段,依此类推。

Any help or pointers would be most appreciated! 任何帮助或指针将不胜感激!

json in Postgres 9.3 Postgres 9.3中的json

This is hard in pg 9.3, because useful functionality is missing. 在9.3版中很难做到这一点,因为缺少有用的功能。

Method 1 方法1

Unnest in a LEFT JOIN LATERAL (clean and standard-conforming), trim double-quotes from json after casting to text . LEFT JOIN LATERAL (干净且符合标准)中嵌套,将json双引号修剪为强制转换为text See links below. 请参阅下面的链接。

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;

While this works, and I have never seen it fail, the order of unnested elements depends on undocumented behavior. 尽管这可行,但我从未见过失败,但未嵌套元素的顺序取决于未记录的行为。 See links below! 请参阅下面的链接!
Improved the conversion from json to text with the expression provided by @pozs in the comment . 使用@pozs在注释中提供的表达式,改进了从jsontext的转换。 Still hackish, but should be safe. 仍然有点破旧,但应该是安全的。

Method 2 方法2

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;
  • Unnest in the SELECT list (non-standard). 嵌套在SELECT列表中(非标准)。
  • Attach row number ( rn ) in parallel (more reliable). 并行附加行号( rn )(更可靠)。
  • Convert to text like above. 转换为上述text
  • The expression (last = name) in the ORDER BY clause sorts matching names last (but before NULL). ORDER BY子句中的表达式(last = name)对匹配的名称进行最后排序(但在NULL之前)。 So a matching name is only selected if no other name is available. 因此,仅当没有其他名称可用时,才选择匹配的名称。 Last link below. 下面的最后一个链接。 In the SELECT list, NULLIF replaces a matching name with NULL , arriving at the same result as above. SELECT列表中, NULLIF将匹配的名称替换为NULL ,得到与上述相同的结果。

SQL Fiddle. SQL提琴。

json or jsonb in Postgres 9.4 Postgres 9.4中的jsonjsonb

pg 9.4 ships all the necessary improvements: 第9.4页提供了所有必要的改进:

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;

Use jsonb_array_elements_text() for jsonb . jsonb_array_elements_text()用于jsonb All else the same. 其他都一样。

json / jsonb functions in the manual 手册中的json / jsonb函数

Related answers with more explanation: 相关答案以及更多说明:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM