Как создать отчет Postgres со столбцами, условия которых являются взаимоисключающими и не имеют общих ключей? - PullRequest
0 голосов
/ 17 апреля 2020

Фон

У меня есть база данных Postgres 11, работающая на RDS. У меня есть две таблицы, orders и items, вот так:

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
);

Мне нужно создать отчет, в котором в двух отдельных столбцах будет показано количество позиций с некоторой строкой в ​​столбце 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, которое возвращает только те записи, которые меня интересуют:

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 большую часть дня, но не нашел решения. Все рекомендации очень ценятся!

1 Ответ

1 голос
/ 17 апреля 2020

Со следующими данными:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...