【问题标题】:PosgresSQL - sql to generate Json from multiple tablesPostgreSQL - 从多个表生成 Json 的 sql
【发布时间】:2022-01-27 22:18:00
【问题描述】:

Postgres V13

试图了解如何在 PS(简单表)中生成 Json 基础关系数据, 我正在编写一个生成 SQL 的工具,用于基于关系数据生成 Json, 用户提供映射规则 - 将每个 Json 字段映射到 table.field 和工具构建 SQL 以提供所需的 json 格式的数据。

例如对于我需要在 Ps 上创建的非常相似的 json, 在 Oracle 数据库上(Oracle 版本 >12.2) 我通过运行得到它:

SELECT JSON_OBJECT ('FIRST_NAME' VALUE TO_CHAR(CUSTOMER.FIRST_NAME),
'concatDeails' VALUE  JSON_OBJECT ('conctant_name' VALUE TO_CHAR(CUSTOMER.FIRST_NAME) || TO_CHAR(CUSTOMER.LAST_NAME)),
'Payments' VALUE (SELECT JSON_ARRAYAGG  ( JSON_OBJECT ('payment_id' VALUE PAYMENT.payment_id, 
'amount' VALUE payment.amount
)
 RETURNING VARCHAR2(32000) )
FROM PAYMENT WHERE PAYMENT.CUSTOMER_ID = CUSTOMER.CUSTOMER_ID )format  json )  JSON_OUT 
FROM CUSTOMER

而且有一个--> 客户与付款表之间的许多关系, 所以对于 Postgres,我有 3 个表: 客户(address_id 是唯一键) 地址(address_id 为 pk) 付款(客户可以多次付款)

json 应该如下所示:

{
  "first_name": "Jared", 
  "last_name": "Ely", 
  "concatDeails":{ "conctant_name": "Jared Ely"},
  "Address":{"city": "NY" ,"Zip": 123123},
  "Payments":[{"payment_id": 1,"amount":100 , "credit": null }]
 
}

我知道如何创建每个块,但出于某种原因, 无法在单个查询中获取所有这些。

用于获取 first_name 和 concatDeails:

select json_build_object('first_name'  , customer.first_name ,'concatDeails' ,json_build_object('last_nam1e' , customer.last_name||customer.last_name)) 
                         from customer

地址字典:

select   
    json_build_object('address' ,json_build_object('city_id' , address.city_id, 'postal_code' ,address.postal_code) )
                         from address ;

支付列表对象:

select jsonb_build_array(json_build_object('payment_id'  , payment.payment_id ,'amount' , payment.amount ,"credit" , payment.credit)) from payment ;

当我尝试将它们组合成单个查询时, 失败:

elect json_build_object('first_name'  , customer.first_name ,'concatDeails' ,json_build_object('last_nam1e' , customer.last_name||customer.last_name),
                            (select     json_build_object('address' ,json_build_object('city_id' , address.city_id, 'postal_code' ,address.postal_code) )
                             from address where address.address_id=customer.address_id),
                             (select jsonb_build_array(json_build_object('payment_id'  , payment.payment_id ,'amount' , payment.amount))
                             from payment where payment.customer_id=customer.customer_id)               
                             )
                             from customer;

ERROR:  more than one row returned by a subquery used as an expression
SQL state: 21000

实际上,即使我尝试将地址和客户结合起来,我也会遇到错误: https://sqlize.online/sql/psql13/c495c4468aa8a9af897f28c5762c9035/

能否解释一下我如何将它们全部组合为单个查询 以最简单的方式? 第二,如何在没有返回值的json中显示“null”(参见示例Paymnet-->credit)?

【问题讨论】:

标签: sql postgresql


【解决方案1】:

请看下一个解决方案:

select 
    json_build_object(
      'first_name', customer.first_name ,
      'concatDeails', json_build_object(
            'conctant_name', customer.first_name || ' ' || customer.last_name
      ),
      'Address', json_build_object(
            'city', address.city,
            'Zip',  address.Zip
        ),
      'Payments', payment
    ) 
 from customer
 left join address on address.customer_id = customer.id
 left join (
    select 
        customer_id, 
        array_agg(json_build_object(
            'payment_id', payment_id, 'amount', amount, 'credit', credit
        )) 
    from payment 
    group by customer_id
 ) payment on payment.customer_id = customer.id;

Look here PostgreSQL fiddle

【讨论】:

  • 感谢 Slava,我了解您的解决方案,但我正在寻找实现这一目标的简单解决方案,原因是我正在编写一个动态生成用于生成 json 的 sql 的工具 - 用户提供一些映射规则和工具构建 SQL,是否有替代方法编写该查询?没有那些左加入(我将在帖子中提供更多详细信息)
  • 帖子更新了一个例子,我在 Oracle 上做了同样的事情
【解决方案2】:

经过多次试验,我设法完成了这项工作, 对我来说,它看起来更连贯, 此外,找到不止一种方法来管理空值

因此,如果您来到这里并需要构建一个具有特定结构和来自不同表的数据的 json,这会有所帮助:


select row_to_json(customer) as customer_json
from (
  select customer.first_name "first_name" ,null as "test_null",
    ( json_build_object('concatDeails' , customer.first_name||customer.last_name)  ) as "concatDeails",
    (select json_agg(payment)
     from (
         select payment.payment_id "payment_id" ,payment.amount  "amount" from payment 
         where payment.customer_id=customer.customer_id
     ) payment
     ) as payment ,
    (select row_to_json(address)
     from (
         select address.address "address_details",CASE WHEN address.phone IS  NULL THEN 'NO_PHONE' ELSE address.phone  END as "phone_no_null",
          address.phone as "phone", COALESCE(address.phone, 'NO_PHONE') as "phone_coalesce"          
         from address  where address.address_id=customer.address_id
      ) address
    ) as address
    from customer as customer where customer_id=2 ) customer;

【讨论】:

    猜你喜欢
    • 2015-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-25
    • 1970-01-01
    • 2016-02-14
    • 1970-01-01
    相关资源
    最近更新 更多