Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从sql查询postgres 9.4创建嵌套json_Sql_Json_Postgresql_Aggregate Functions_Postgresql 9.4 - Fatal编程技术网

从sql查询postgres 9.4创建嵌套json

从sql查询postgres 9.4创建嵌套json,sql,json,postgresql,aggregate-functions,postgresql-9.4,Sql,Json,Postgresql,Aggregate Functions,Postgresql 9.4,我需要从完全结构化的JSON查询中获取结果。 我可以在postgres中看到一些内置函数可能很有用 作为示例,我创建了一个结构,如下所示: -- Table: person -- DROP TABLE person; CREATE TABLE person ( id integer NOT NULL, name character varying(30), CONSTRAINT person_pk PRIMARY KEY (id) ) WITH ( OIDS=FALS

我需要从完全结构化的JSON查询中获取结果。 我可以在postgres中看到一些内置函数可能很有用

作为示例,我创建了一个结构,如下所示:

    -- 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
我想我遗漏了一些groupby和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
            }]
          }]
    }]
}

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

您希望在一个json对象中包含多个人,因此使用在json数组中收集个人。 类似地,一个人可以有多辆车,您应该将属于一个人的车放在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;

我想出了这个解决办法。它非常紧凑,在任何情况下都能工作。 但是,与更多使用json_build_对象的其他解决方案相比,不确定对性能有何影响。使用row_to_json而不是json_build_对象的优点是所有工作都是在后台完成的,这使得查询更具可读性

SELECT json_build_object('persons', json_agg(p)) persons
FROM (
       SELECT
         person.name person_name,
         (
           SELECT json_agg(row_to_json(c))
           FROM (
                  SELECT
                    id carid,
                    type,
                    (
                      SELECT json_agg(row_to_json(w))
                      FROM (
                             SELECT
                               whichone which,
                               serialnumber
                             FROM wheel
                             WHERE wheel.carid = car.id
                           ) w
                    )  wheels
                  FROM car
                  WHERE car.personid = person.id
                ) c
         ) AS        cars
       FROM person
) p

好的,让我们说,此外,汽车可能有0或1个引擎。如何将其嵌套为对象而不是对象数组?然后只需在子选择中的轮子旁边添加引擎,并使用to_json函数将其转换为json。从SELECT person.name person\u name中选择json\u build\u object'persons',从SELECT id carid中选择json\u aggrow\u to_jsonc,键入,从SELECT horspower FROM engine中选择to_jsone,其中engine.carid=car.id e engine,从SELECT whichone中选择json\u aggrow\u to_jsonw,serialnumber FROM wheel wheel.carid=car.id w wheel FROM car WHERE.personid=person.id c作为person的cars FROM person pAnd如果我想将结果仅限于db中的前10个人,该怎么办?您应该用派生表替换person,即,而不是person p使用select*FROM person。。。限制10便士。太好了!还有一件事,如果我确定所有人只有一辆车,并且我不想在结果中显示对象数组,而是对象,那会怎么样?如何轻松修改?简单:只需在第二个查询中删除json_agg和group by即可。从形式上讲,最好用两级而不是三级来构建查询。非常感谢,还有一个小问题,我想这样做,如果cars列表为空,那么结果不应该是cars:null,但它不应该出现在结果中