sql - 需要从 postgresql 表中动态选择一个 JSON 数组元素

标签 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"]

我想编写一个查询,从数组中选择最后一个元素,该元素不等于 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

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

如有任何帮助或指点,我们将不胜感激!

最佳答案

Postgres 9.3 中的

json

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

方法一

LEFT JOIN LATERAL 中取消嵌套(干净且符合标准),在转换为 text 后修剪 json 中的双引号。请参阅下面的链接。

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;

虽然这行得通,而且我从未见过它失败,但未嵌套元素的顺序取决于未记录的行为。请参阅下面的链接!
使用表达式 provided by @pozs in the comment 改进了从 jsontext 的转换.仍然很黑,但应该是安全的。

方法二

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;
  • 取消嵌套在 SELECT 列表中(非标准)。
  • 并行附加行号(rn)(更可靠)。
  • 像上面那样转换为文本
  • ORDER BY 子句中的表达式 (last = name) 对匹配的名称最后(但在 NULL 之前)进行排序。因此只有在没有其他名称可用时才会选择匹配的名称。最后一个链接在下面。 在 SELECT 列表中,NULLIF 将匹配名称替换为 NULL,得到与上述相同的结果。

SQL Fiddle.

Postgres 9.4 中的

jsonjsonb

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

jsonb 使用jsonb_array_elements_text()。其他都一样。

json / jsonb functions in the manual

更多解释的相关答案:

关于sql - 需要从 postgresql 表中动态选择一个 JSON 数组元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27956926/

相关文章:

mysql - mysql 的多个大小写值

c++ - 在全局变量头文件 C++ 中初始化数组时出现问题

json - 接收 NPM 错误 : Unexpected string in JSON at position 20938 within an ionic 3 project

javascript - IE 7 或 Opera 10.01 无法识别 JSON2.js

sql - 如何在 SQL 中同时发送更新批处理和语句

SQL 查询 - 匹配日期时间与匹配整数

sql - 指定哪一列在前 SQL

arrays - 在一个有 N 个元素的整数数组中,找到最少的 k 个元素?

python - 更新使用具有重复索引的叉积索引的 2D NumPy 数组

javascript - 在 Javascript 中将字符串转换为二维数组