使用自联接在 row_to_json() 中复制 JSON 元素

Posted

技术标签:

【中文标题】使用自联接在 row_to_json() 中复制 JSON 元素【英文标题】:Duplicate JSON element in row_to_json() with self-join 【发布时间】:2017-04-06 09:08:02 【问题描述】:

这是此精彩问答的后续:13227142。

我几乎必须做同样的事情(在 PostgreSQL 9.2 的约束下),但我只使用一张表。因此,查询使用自连接(为了生成正确的 JSON 格式),这会导致重复的 id 字段。我怎样才能避免这种情况?

例子:

CREATE TABLE books
(
  id serial primary key,
  isbn text,
  author text,
  title text,
  edition text,
  teaser text
);

SELECT row_to_json(row)
FROM
(
  SELECT id AS bookid,
  author,
  cover
  FROM books
  INNER JOIN 
  (
    SELECT id, title, edition, teaser
    FROM books
  ) cover(id, title, edition, teaser)
  USING (id)
) row;

结果:


  "bookid": 1,
  "author": "Bjarne Stroustrup",
  "cover": 
    "id": 1,
    "title": "Design and Evolution of C++",
    "edition": "1st edition",
    "teaser": "This book focuses on the principles, processes and decisions made during the development of the C++ programming language"
  

我想去掉“封面”中的“id”。

【问题讨论】:

【参考方案1】:

结果证明这是一项棘手的任务。据我所知,通过简单的查询是不可能实现的。 一种解决方案是使用预定义的数据类型:

CREATE TYPE bookcovertype AS (title text, edition text, teaser text);

SELECT row_to_json(row)
FROM
(
  SELECT books.id AS bookid, books.author, 
    row_to_json(row(books.title, books.edition, books.teaser)::bookcovertype) as cover
  FROM books
) row;

【讨论】:

此解决方案与 Postgres 9.2 兼容,谢谢 我再次查看了查询,发现JOIN 在这里绝对没有必要。我更新了查询。【参考方案2】:

你需要 id 才能加入,所以没有 id 你不能做这么短的查询。你需要构造它。喜欢:

select row_to_json(row,true)
FROM
(
with a as (select id,isbn,author,row_to_json((title,edition,teaser)) r from books
)
select a.id AS bookid,a.author, concat('"title":',r->'f1',',"edition":',r->'f2',',"teaser":',r->'f3','')::json as cover
  from a
) row;
                      row_to_json
--------------------------------------------------------
 "bookid":1,                                          +
  "author":"\"b\"",                                    +
  "cover":"title":"c","edition":"d","teaser":"\"b\""
(1 row)

同样,如果没有加入,您使用的资源会减少两倍

【讨论】:

如果值包含特殊字符,例如",它将失败 添加转义以避免它 很遗憾,to_json() 仅适用于 9.3 版 无论如何,实现自己的文本转义功能是可能的。所以这是一个可能的解决方案。 使用 row_to_json 进行转义【参考方案3】:

为了完整起见,我自己偶然发现了另一个答案:字符串函数可以消除附加字段。不过,我更喜欢 AlexM 的答案,因为它会更快并且仍然与 PostgreSQL 9.2 兼容。

SELECT regexp_replace(
  (
      SELECT row_to_json(row)
      FROM
      (
        SELECT id AS bookid,
        author,
        cover
        FROM books
        INNER JOIN 
        (
          SELECT id, title, edition, teaser
          FROM books
        ) cover(id, title, edition, teaser)
        USING (id)
      ) row
  )::text,
  '"id":\d+,',
  '')

【讨论】:

以上是关于使用自联接在 row_to_json() 中复制 JSON 元素的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy:在 MySQL 上使用自联接创建删除查询

在 row_to_json 函数中选择查询

SQL自联命名?

SQLAlchemy PostgreSQL row_to_json关系

postgreSql聚合函数row_to_json初使用

使用 row_to_json 的 Postgres 递归查询