聚合子查询键以构建复杂的对象

时间:2019-04-01 15:10:08

标签: json postgresql

我有一张表格,该表格描述了为给定订单生产的产品列表,在该表的每一行中,必须有产品ID以及购买原因,

我想构建一个json响应,该响应相当于订购产品所针对的位置数组,其中包含 unique 产品代码数组,并包含一系列原因为什么订购该独特产品。

我只能定义查询的最高部分,但是请求的联接和子选择性质实际上使我有些费解。在plpgsql中这种事情实际上可能吗?

此外,我想在product_order_reason.id上加入product_order.reason并检索与此行关联的表内的longform_text,但我认为更大的事情是获得全部收益,而这就是我被困的地方

product
id      |name                    |cost  |cost_rate|
--------|------------------------|------|---------|
WALLC   |Wall Clock              | 15.00|SINGLE   |
MIRR    |Mirror                  | 25.00|SINGLE   |
KEY     |Door Keys               |  5.00|SINGLE   |
KEYFOB  |Key Fob                 | 40.00|SINGLE   |



product_order
product_id|quantity|location  |quote_detail_quote_id               |is_primary_order|reason|
----------|--------|----------|------------------------------------|----------------|------|
MIRR      |       2|floor_0   |C7D33FED-CB15-5796-DC7D-A7BCEA8923C5|true            |     1|
KEYF      |       3|floor_0   |C7D33FED-CB15-5796-DC7D-A7BCEA8923C5|true            |     2|
WALLC     |       3|floor_1   |C7D33FED-CB15-5796-DC7D-A7BCEA8923C5|true            |     1|
WALLC     |       3|floor_1   |C7D33FED-CB15-5796-DC7D-A7BCEA8923C5|true            |     3|
product_order_reason
------------------------------------------------
id (varchar, pk) | shortform_text(varchar) | longform_text(varchar)
------------------------------------------------


id|shortform_text                       |longform_text                                        |
--|-------------------------------------|-----------------------------------------------------|
 1|Employee Room                        |Standard employee room with no window                |
 2|Meeting Room                         |Standard Meeting Room                            |
 3|Mirror                               |Additional Mirror Request         |


create
or replace
function get_breakdown_v1_0_0(p_quote_id character varying,
p_location character varying,
p_product_code character varying) returns json language plpgsql as $function$ declare row_count smallint := 0;
begin
raise notice 'Location: %',
p_location;

raise notice 'Product: %',
p_product_code;
-- Perform santiy check on quote_id so that the json does not include a null result.
 select
    count(*) into
        strict row_count
    from
        quote_detail
    where
        quote_id = p_quote_id;

if row_count = 0 then raise 'Quote ID % not found',
p_quote_id
    using ERRCODE = '02000';
-- SQL standard no_data
 elseif row_count > 1 then raise 'Too many rows returned for ID %',
p_quote_id
    using ERRCODE = 'P0003';
-- PL/pgSQL too_many_rows
end if;
-- Returns an object comprised of unique values for locations, where not null and their associated products
 return (
select
    jsonb_build_object ('locations',jsonb_agg( jsonb_build_object( 'area', location, 'items', items)))
from
    (
    select
        location,
        jsonb_agg(jsonb_build_object ('code', product_id, 'reasons', reason)) as items 
    from
        product_order
    where
        (quote_detail_quote_id = p_quote_id)
        and (location = p_location
        or p_location is null)
        and (product_id = p_product_code
        or p_product_code is null)
    group by
        location) a );
end $function$ ;

所需的响应;

        {
            "area": "floor_0",
            "items": [
                {
                    "code": "WALLC",
                    "reasons": [
                        {
                            "quantity": 2,
                            "reason_code": "Standard Employee Room"
                        },
                        {
                            "quantity": 2,
                            "reason_code": "Standard Cubicle"
                        }
                    ]
                },
                {
                    "code": "MIRR",
                    "reasons": [
                        {
                            "quantity": 3,
                            "reason_code": "Meeting Room"
                        }
                    ]
                }
            ]
        }]

1 个答案:

答案 0 :(得分:0)

好的,我想我有东西要给你。这个想法是一次构建一个数组,并将必要的剩余信息携带到外部查询中,以进一步构建数组。您可以将quote_detail_quote_idlocationproduct_id的约束添加到最内部查询的WHERE子句中。

SQLFiddle进行展示。

这可能需要一些研究:

SELECT json_build_object('area', t3.location, 'items', t3.code_json)
FROM
(
    SELECT t2.location
           , array_to_json(array_agg(jsonb_build_object('code', t2.product_id, 'reasons', t2.qty_reason_json))) AS code_json
    FROM
    (
      SELECT t.location
             , t.product_id
             , array_to_json(array_agg(jsonb_build_object('quantity', t.quantity, 'reason_code', t.longform_text))) AS qty_reason_json
      FROM
      (
          SELECT po.product_id
                 , po.quantity
                 , po.location
                 , po.reason
                 , por.longform_text
          FROM product_order po
          JOIN product_order_reason por ON (por.id = po.reason) 
          WHERE quote_detail_quote_id = 'C7D33FED'
      ) t
      GROUP BY t.location, t.product_id
    ) t2
    GROUP BY t2.location
) t3
;