如何使用条件互斥且不共享键的列创建Postgres报告?

问题描述 投票:0回答:1

背景

我有一个在RDS上运行的Postgres 11数据库。我有两个表ordersitems,如下所示:

CREATE TABLE schema.orders (
  order_number TEXT,
  order_date TIMESTAMPTZ,
  sales_channel_name TEXT
);

CREATE TABLE schema.items (
 order_number TEXT REFERENCES schema.orders(order_number),
 key TEXT
 quantity INT
);

我需要创建一个报告,在两个单独的列中显示行项目的count withkey中的一些字符串,withoutkey中的一些字符串],按关联的订单日期的日期分组。

所需的输出示例如下:

              day         |  double_items_count               |  normal_items_count
-----------------------------------------------------------------------------------------------
   2020-04-09 00:00:00    |        22                         |     13

每个所需的列都可以定义为以下查询之一:

SELECT 
     date_trunc('day', o.order_date AT TIME ZONE 'America/Los_Angeles') AS day,
    2*(count(*)) AS double_items_count
    FROM 
    schema.items i  
    INNER JOIN
    schema.orders o 
    ON i.order_number = o.order_number
    WHERE 
    i.key ILIKE '%some_string%'
    AND o.sales_channel_name = 'foo_sales_channel'
    GROUP BY day 
    ORDER BY day DESC
;

SELECT 
    date_trunc('day', o.order_date AT TIME ZONE 'America/Los_Angeles') AS day,
    count(*) AS normal_items_count
    FROM 
    schema.items  
    INNER JOIN
    schema.orders_new o 
    ON i.order_number = o.order_number
    WHERE 
    i.key NOT ILIKE '%some_string%'
    AND o.sales_channel_name = 'foo_sales_channel'
    GROUP BY day 
    ORDER BY day DESC
;

我还有一个视图schema.items_from_channel,该视图仅返回我感兴趣的那些记录:

CREATE VIEW schema.items_from_channel AS (
    SELECT 
    date_trunc('day', o.date at time zone 'America/Los_Angeles') as day,
    o.order_number,
    i.key,
    o.sales_channel
    FROM 
    schema.orders o 
    INNER JOIN
    schema.items i 
    ON 
    o.order_number = i.order_number 
    WHERE o.sales_channel = "foo_sales_channel"
    ORDER BY day DESC
);

问题

通常,我将通过针对视图的直接查询或将上述两个查询结合在一起来处理此类问题。

但是,由于所需的列取决于互斥的WHERE条件,我不知道如何构造一个会同时产生这两个查询的查询(例如,带有子查询)。

由于这两个查询除day之外均不共享其他任何键,因此我无法弄清楚如何以产生合理结果的方式来连接它们[在day上连接,这对我来说很有意义,会产生虚数]。

UNION不会产生所需的结果,因为它会返回所有所需的数据,但不会保留所需的列格式。

我很困惑。如何生成所需的报告?在一天中的大部分时间里,我一直在搜索和梳理相关的SE网站,但并未提出解决方案。所有指导深表感谢!

sql database postgresql report
1个回答
0
投票

具有以下数据:

select * from orders;
 order_number |     order_date      | sales_channel_name 
--------------+---------------------+--------------------
            1 | 2020-04-09 01:00:00 | foo_sales_channel
            2 | 2020-04-09 02:00:00 | foo_sales_channel
            3 | 2020-04-09 03:00:00 | foo_sales_channel
            4 | 2020-04-09 04:00:00 | foo_sales_channel
(4 rows)

select * from items;
 id |      key       | order_number 
----+----------------+--------------
  1 | some_string    |            1
  2 | some_string    |            2
  3 | another_string |            3
  4 | another_string |            4
(4 rows)

SELECT 
     date_trunc('day', o.order_date AT TIME ZONE 'America/Los_Angeles') AS day,
    2*(count(*)) AS double_items_count
    FROM 
    items i  
    INNER JOIN
    orders o 
    ON i.order_number = o.order_number
    WHERE 
    i.key ILIKE '%some_string%'
    AND o.sales_channel_name = 'foo_sales_channel'
    GROUP BY day 
    ORDER BY day DESC;
          day           | double_items_count 
------------------------+--------------------
 2020-04-09 00:00:00+02 |                  4
(1 row)

SELECT 
    date_trunc('day', o.order_date AT TIME ZONE 'America/Los_Angeles') AS day,
    count(*) AS normal_items_count
    FROM 
    items  i
    INNER JOIN
    orders o 
    ON i.order_number = o.order_number
    WHERE 
    i.key NOT ILIKE '%some_string%'
    AND o.sales_channel_name = 'foo_sales_channel'
    GROUP BY day 
    ORDER BY day DESC
;
          day           | normal_items_count 
------------------------+--------------------
 2020-04-09 00:00:00+02 |                  2
(1 row)

这里是解决方法:

SELECT
    date_trunc('day', o.order_date AT TIME ZONE 'America/Los_Angeles') AS day,
    2*count(*) FILTER (WHERE i.key ILIKE '%some_string%') AS double_items_count,
    count(*)   FILTER (WHERE i.key NOT ILIKE '%some_string%') AS normal_items_count
    FROM
    items  i
    INNER JOIN
    orders o
    ON i.order_number = o.order_number
    WHERE
    o.sales_channel_name = 'foo_sales_channel'
    GROUP BY day
    ORDER BY day DESC
;
          day           | double_items_count | normal_items_count 
------------------------+--------------------+--------------------
 2020-04-09 00:00:00+02 |                  4 |                  2
(1 row)
© www.soinside.com 2019 - 2024. All rights reserved.