Postgres CrossTab用于具有可变列数的查询

时间:2017-04-25 07:21:46

标签: postgresql crosstab

上下文

我正在为网站运行车辆路径问题的变体。布局就是这样。你有接送点,卡车和被拾取的物品。真正的诀窍是客户在一天内不会运行相同数量的班次,因此可以自定义。所以我会在运行时但不提前知道这一点。我正在尝试创建一个返回结果的查询,每个公交站点的行,每个班次的列和每个项目的ID的json数组,如下所示:

id  |     address      |   city    | postalcode |  shift1  | shift2 | shift3
-----+------------------+-----------+------------+----------+--------+--------
 220 | 1471 N Lymestone | Anytown  | 12345      | [14, 16] | [12]   | [14]
 221 | 108 D Ave        | Anytown  | 12345      | [15, 17] |        | [15,16]
 222 | 1434 Bryan Ave   | Anytown  | 12345      | [16]     | [1,19] |

表格结构

我这里有三张相关的表格;只有停靠点地理位置的stops表,包含拾取项ID的items表,包含班次的shifts表和itemstopassignemnt表(请原谅命名,我继承了它,它有一个stop_id shift_iditem_id分配一个项目,在该站点为该班次选择。

查询

所以在SO上钓鱼之后,我提出了以下问题:

SELECT * FROM crosstab(
     $$SELECT stop_id, 
              'shift' || shift_id, 
              json_agg(item_id) 
       FROM itemstopassignemnt 
       GROUP BY stop_id, shift_id 
       ORDER BY 1,2$$
) AS (stop_id INTEGER, shift1 JSON, shift2 JSON, shift3 JSON);

这适用于三班制案例。我可以把它放在函数中以编程方式生成sql所以它动态地构造它,无论用户添加了多少班次。然后,我认为该函数必须返回setof recordtable()。以下是我的问题:

  1. 这是解决问题的最佳方法吗?
  2. 这可以单独使用交叉表而不是动态生成的sql吗?
  3. 如果没有,那么设置功能的最佳方法是什么?具体来说我应该使用哪种返回类型,因为我可以在没有交叉表的情况下以编程方式完成此操作(循环移位表和创建子选择),这里使用交叉表是否有优势?

1 个答案:

答案 0 :(得分:1)

http://rextester.com/RPV59686

select
    stop_id,
    jsonb_object_agg('shift' || shift_id, items) as shift_items
from (
    select
        stop_id,
        shift_id, 
        coalesce (
            array_agg (item_id) filter (where item_id is not null),
            array[]::int[]
        ) as items
    from
        itemstopassignemnt
        right join
        (
            select shift_id, stop_id
            from
                (select distinct shift_id from itemStopAssignemnt) a
                cross join
                (select distinct stop_id from itemStopAssignemnt) b
        ) r using (stop_id, shift_id)
    group by 1,2 
) s
group by 1
;
 stop_id |                      shift_items                       
---------+--------------------------------------------------------
     220 | {"shift1": [14, 16], "shift2": [12], "shift3": [14]}
     221 | {"shift1": [15, 17], "shift2": [], "shift3": [15, 16]}
     222 | {"shift1": [16], "shift2": [1, 9], "shift3": []}

我没有加入stops来缩短它,但应该是微不足道的。