我需要从完全 struct 化的JSON查询中获取结果.

作为一个例子,我创建了如下 struct :

    -- Table: person

-- DROP TABLE person;

CREATE TABLE person
(
  id integer NOT NULL,
  name character varying(30),
  CONSTRAINT person_pk PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE person
  OWNER TO postgres;

  -- Table: car

-- DROP TABLE car;

CREATE TABLE car
(
  id integer NOT NULL,
  type character varying(30),
  personid integer,
  CONSTRAINT car_pk PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE car
  OWNER TO postgres;

  -- Table: wheel

-- DROP TABLE wheel;

CREATE TABLE wheel
(
  id integer NOT NULL,
  whichone character varying(30),
  serialnumber integer,
  carid integer,
  CONSTRAINT "Wheel_PK" PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE wheel
  OWNER TO postgres;

还有一些数据:

INSERT INTO person(id, name)
VALUES (1, 'Johny'),
       (2, 'Freddy');

INSERT INTO car(id, type, personid)
VALUES (1, 'Toyota', 1),
       (2, 'Fiat', 1),    
       (3, 'Opel', 2);     

INSERT INTO wheel(id, whichone, serialnumber, carid)
VALUES (1, 'front', '11', 1),
       (2, 'back', '12', 1),
       (3, 'front', '21', 2),
       (4, 'back', '22', 2),
       (5, 'front', '3', 3);

因此,我希望有一个JSON对象,其中包含人员列表,每个人都有汽车列表和车轮列表.

我试过这样的东西,但不是我想要的:

select json_build_object(
    'Persons', json_build_object(
    'person_name', person.name,
    'cars', json_build_object(
        'carid', car.id,    
        'type', car.type,
        'comment', 'nice car', -- this is constant
        'wheels', json_build_object(
            'which', wheel.whichone,
            'serial number', wheel.serialnumber
        )

    ))
)

from
person 
left join car on car.personid = person.id
left join wheel on wheel.carid = car.id

我想我错过了一些group by和json_agg,但我不知道该怎么做.

因此,我想要这样的东西:

{ "persons": [   
    {
      "person_name": "Johny",
      "cars": [
          {
            "carid": 1,
            "type": "Toyota",
            "comment": "nice car",
            "wheels": [{
              "which": "Front",
              "serial number": 11
            },
            {
              "which": "Back",
              "serial number": 12
            }]
          },
          {
            "carid": 2,
            "type": "Fiat",
            "comment": "nice car",
            "wheels": [{
              "which": "Front",
              "serial number": 21
            },{
              "which": "Back",
              "serial number": 22
            }]
          }
        ]
    },
    {
      "person_name": "Freddy",
      "cars": [
          {
            "carid": 3,
            "type": "Opel",
            "comment": "nice car",
            "wheels": [{
              "which": "Front",
              "serial number": 33
            }]
          }]
    }]
}

http://www.jsoneditoronline.org/?id=7792a0a2bf11be724c29bb86c4b14577

推荐答案

您应该构建一个分层查询,以获得结果的分层 struct .

你想在一个json对象中有很多人,所以用json_agg()来收集json数组中的人.

select
    json_build_object(
        'persons', json_agg(
            json_build_object(
                'person_name', p.name,
                'cars', cars
            )
        )
    ) persons
from person p
left join (
    select 
        personid,
        json_agg(
            json_build_object(
                'carid', c.id,    
                'type', c.type,
                'comment', 'nice car', -- this is constant
                'wheels', wheels
                )
            ) cars
    from
        car c
        left join (
            select 
                carid, 
                json_agg(
                    json_build_object(
                        'which', w.whichone,
                        'serial number', w.serialnumber
                    )
                ) wheels
            from wheel w
            group by 1
        ) w on c.id = w.carid
    group by personid
) c on p.id = c.personid;

(格式化)结果:

{
    "persons": [
        {
            "person_name": "Johny",
            "cars": [
                {
                    "carid": 1,
                    "type": "Toyota",
                    "comment": "nice car",
                    "wheels": [
                        {
                            "which": "front",
                            "serial number": 11
                        },
                        {
                            "which": "back",
                            "serial number": 12
                        }
                    ]
                },
                {
                    "carid": 2,
                    "type": "Fiat",
                    "comment": "nice car",
                    "wheels": [
                        {
                            "which": "front",
                            "serial number": 21
                        },
                        {
                            "which": "back",
                            "serial number": 22
                        }
                    ]
                }
            ]
        },
        {
            "person_name": "Freddy",
            "cars": [
                {
                    "carid": 3,
                    "type": "Opel",
                    "comment": "nice car",
                    "wheels": [
                        {
                            "which": "front",
                            "serial number": 3
                        }
                    ]
                }
            ]
        }
    ]
}

如果不熟悉嵌套的派生表,可以使用公共表表达式.

with wheels as (
    select 
        carid, 
        json_agg(
            json_build_object(
                'which', w.whichone,
                'serial number', w.serialnumber
            )
        ) wheels
    from wheel w
    group by 1
),
cars as (
    select 
        personid,
        json_agg(
            json_build_object(
                'carid', c.id,    
                'type', c.type,
                'comment', 'nice car', -- this is constant
                'wheels', wheels
                )
            ) cars
    from car c
    left join wheels w on c.id = w.carid
    group by c.personid
)
select
    json_build_object(
        'persons', json_agg(
            json_build_object(
                'person_name', p.name,
                'cars', cars
            )
        )
    ) persons
from person p
left join cars c on p.id = c.personid;

Postgresql相关问答推荐

Postgs密码重置问题

带有regex表达式的Postgres SQL

在Docker Compose中获取CSV文件数据?

使用pg_repack从PostgreSQL中的表中删除OID

在PostGreSQL中获取最近日期的项目

PostgreSQL 不删除旧的 WAL 档案

使用 pgAdmin 4 v7.4 在 Windows 11 上全新安装 PostgreSQL 15.3-3 无法启动 - 卡在正在加载 pgAdmin 4 v7.4...

JOOQ:数据库版本早于 COCKROACHDB 支持的方言:13.0.0

空表上的 Postgres 意外行为

Upper() 不会大写重音字符

为什么这里的默认格式不同? (ISO 8601 的两种不同实现)

Windows上的psql:错误:编码UTF8的字节序列无效:0xc8 0x20

如何在 postgresql 上使用 sqlalchemy 进行正确的 upsert?

PostgreSQL - jsonb_each

从 PostgreSQL 中的字段中提取数字

大型查询后 psycopg2 泄漏内存

null 计算结果为 false 的情况

PostgreSQL/JDBC 和 TIMESTAMP 与 TIMESTAMPTZ

没有函数匹配给定的名称和参数类型

PostgreSQL regexp_replace() 只保留一个空格