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

How to create a Postgres report with columns whose conditions are mutually exclusive and share no keys?

背景

我在 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 行项目 列中的一些字符串 key,并且 没有 key 中的某些字符串,按 关联 order_date 的日期分组。

所需输出的示例如下:

              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 returns 只有那些我感兴趣的记录:

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 不会产生所需的结果,因为它 returns 所有所需的数据但不保持所需的列格式。

我难住了。如何生成所需的报告?在一天的大部分时间里,我一直在谷歌搜索和梳理相关的 SE 网站,但还没有找到解决方案。非常感谢所有指导!

具有以下数据:

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)