Как показать максимальное количество для каждой комбинации клиента и продукта в определенном состоянии в Postgresql? - PullRequest
0 голосов
/ 08 октября 2019

Я только недавно начал изучать Postgresql. У меня есть таблица с именем 'sales':

create table sales
    (
        cust    varchar(20),
        prod    varchar(20),
        day integer,
        month   integer,
        year    integer,
        state   char(2),
        quant   integer
    )

insert into sales values ('Bloom', 'Pepsi', 2, 12, 2001, 'NY', 4232);
insert into sales values ('Knuth', 'Bread', 23, 5, 2005, 'PA', 4167);
insert into sales values ('Emily', 'Pepsi', 22, 1, 2006, 'CT', 4404);
insert into sales values ('Emily', 'Fruits', 11, 1, 2000, 'NJ', 4369);
insert into sales values ('Helen', 'Milk', 7, 11, 2006, 'CT', 210);
......

Это выглядит так: enter image description here И всего 500 строк.

Теперь я хочуиспользуйте запрос для реализации этого:

Для каждой комбинации клиента и продукта выведите максимальные объемы продаж для NY и минимальные объемы продаж для NJ и CT в 3 отдельных столбцах. Как и в первом отчете, отобразите соответствующие даты (т. Е. Даты этих максимальных и минимальных объемов продаж). Кроме того, для CT и NJ включайте только продажи, которые произошли после 2000 года;для Нью-Йорка включите все продажи.

Должно быть так: enter image description here

Я пробовал следующий запрос:

SELECT
    cust customer,
    prod product,
    MAX(CASE WHEN rn3 = 1 THEN quant END) NY_MAX,
    MAX(CASE WHEN rn3 = 1  THEN TO_DATE(year || '-' || month || '-' || day, 'YYYY-MM-DD') END) date,

    MIN(CASE WHEN rn2 = 1  THEN quant END) NJ_MIN,
    MIN(CASE WHEN rn2 = 1 THEN TO_DATE(year || '-' || month || '-' || day, 'YYYY-MM-DD') END) date,

    MIN(CASE WHEN rn1 = 1  THEN quant END) CT_MIN,
    MIN(CASE WHEN rn1 = 1 THEN TO_DATE(year || '-' || month || '-' || day, 'YYYY-MM-DD') END) date

FROM (
    SELECT
        *,
        ROW_NUMBER() OVER(PARTITION BY cust, prod ORDER BY quant) rn1,
        ROW_NUMBER() OVER(PARTITION BY cust, prod ORDER BY quant) rn2,
        ROW_NUMBER() OVER(PARTITION BY cust, prod ORDER BY quant DESC) rn3

    FROM sales 
) x
WHERE rn1 = 1   OR rn2 = 1   or rn3 = 1 
GROUP BY cust, prod;

Это результат: enter image description here

Это неверно, потому что показывает максимальное и минимальное количество всех состояний, а не того состояния, которое я хочу. И я понятия не имею, как поступить с годом как с вопросом, как со мной.

1 Ответ

1 голос
/ 08 октября 2019

Мы можем справиться с этим, используя отдельные CTE вместе с таблицей календаря:

WITH custprod AS (
    SELECT DISTINCT cust, prod
    FROM sales
),
ny_sales AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY cust, prod ORDER BY quant DESC) rn
    FROM sales
    WHERE state = 'NY'
),
nj_sales AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY cust, prod ORDER BY quant) rn
    FROM sales
    WHERE state = 'NJ'
),
ct_sales AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY cust, prod ORDER BY quant) rn
    FROM sales
    WHERE state = 'CT'
)

SELECT
    cp.cust,
    cp.prod,
    nys.quant AS ny_max,
    nys.year::text || '-' || nys.month::text || '-' || nys.day::text AS ny_date,
    njs.quant AS nj_max,
    njs.year::text || '-' || njs.month::text || '-' || njs.day::text AS nj_date,
    cts.quant AS ct_max,
    cts.year::text || '-' || cts.month::text || '-' || cts.day::text AS ct_date
FROM custprod cp
LEFT JOIN ny_sales nys
    ON cp.cust = nys.cust AND cp.prod = nys.prod AND nys.rn = 1
LEFT JOIN nj_sales njs
    ON cp.cust = njs.cust AND cp.prod = njs.prod AND njs.rn = 1
LEFT JOIN ct_sales cts
    ON cp.cust = cts.cust AND cp.prod = cts.prod AND cts.rn = 1
ORDER BY
    cp.cust,
    cp.prod;

Примечание. Вы не предоставили подробные примеры данных, но, похоже, вышеприведенное работает в демонстрационной ссылке ниже.

Демо

...