How to show the maximum number for each combination of customer and product in a specific state in Postgresql?

故事扮演 提交于 2019-12-20 06:26:27

问题


I just begin learning Postgresql recently. I have a table named '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);
......

It looks like this: And there are 500 rows in total.

Now I want to use the query to implement this:

For each combination of customer and product, output the maximum sales quantities for NY and minimum sales quantities for NJ and CT in 3 separate columns. Like the first report, display the corresponding dates (i.e., dates of those maximum and minimum sales quantities). Furthermore, for CT and NJ, include only the sales that occurred after 2000; for NY, include all sales.

It should be like this:

I have tried the following query:

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;

This is the result:

This is wrong because it shows me the maximum number and minimum number of all states, not of the specific state I want. And I have no idea how to deal with the year as the question as me to do.


回答1:


We can handle this using separate CTEs along with a calendar table:

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;

Note: You didn't provide comprehensive sample data, but the above seems to be working in the demo link below.

Demo



来源:https://stackoverflow.com/questions/58280347/how-to-show-the-maximum-number-for-each-combination-of-customer-and-product-in-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!