Как я могу объединить два запроса на выборку в одной таблице по горизонтали в Postgresql? - PullRequest
1 голос
/ 07 октября 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);
insert into sales values ('Emily', 'Soap', 2, 4, 2002, 'CT', 2549);
insert into sales values ('Bloom', 'Eggs', 30, 11, 2000, 'NJ', 559);

.... Всего 498 строк. Вот обзор этой таблицы:

enter image description here

Теперь я хочу вычислить максимальные и минимальные объемы продаж для каждого продукта вместе с их соответствующим клиентом (который приобрел продукт),даты (т. е. даты этих максимальных и минимальных объемов продаж) и состояние, в котором была совершена сделка продажи. И среднее количество продаж для соответствующих продуктов.

Объединенный должен выглядеть следующим образом:

enter image description here

Он должен состоять из 10 строк, поскольку в общей сложности имеется 10 различных продуктов.

Iпопробовал:

select prod,
       max(quant),
       cust as MAX_CUST
from sales
group by prod;

, но он вернул ошибку и сказал, что cust должен быть в группе. Но я хочу классифицировать только по типу продукта.

Более того, как я могу горизонтально объединить max_q и его клиента, дату, состояние с min_q и его клиентом,дата, штат , а также AVG_Q по их названию продукта ? Я чувствую себя действительно смущенным!

Ответы [ 2 ]

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

Вы можете использовать аналитическую функцию ROW_NUMBER для ранжирования записей путем увеличения / уменьшения продаж для каждого продукта в подзапросе, а затем выполнить условное агрегирование:

SELECT
    prod product,
    MAX(CASE WHEN rn2 = 1 THEN quant END) max_quant,
    MAX(CASE WHEN rn2 = 1 THEN cust END) max_cust,
    MAX(CASE WHEN rn2 = 1 THEN TO_DATE(year || '-' || month || '-' || day, 'YYYY-MM-DD') END) max_date,
    MAX(CASE WHEN rn2 = 1 THEN state END) max_state,
    MAX(CASE WHEN rn1 = 1 THEN quant END) min_quant,
    MAX(CASE WHEN rn1 = 1 THEN cust END) min_cust,
    MAX(CASE WHEN rn1 = 1 THEN TO_DATE(year || '-' || month || '-' || day, 'YYYY-MM-DD') END) min_date,
    MAX(CASE WHEN rn1 = 1 THEN state END) min_state,
    avg_quant
FROM (
    SELECT
        s.*,
        ROW_NUMBER() OVER(PARTITION BY prod ORDER BY quant) rn1,
        ROW_NUMBER() OVER(PARTITION BY prod ORDER BY quant DESC) rn2,
        AVG(quant) OVER(PARTITION BY prod) avg_quant
    FROM sales s
) x
WHERE rn1 = 1 OR rn2 = 1
GROUP BY prod, avg_quant
1 голос
/ 07 октября 2019

С двумя агрегатными функциями (мин, макс), примененными к столбцу, и выбор соответствующей строки не так прост. если вам нужна только одна агрегатная функция, вы можете сделать что-то вроде примера ниже с плотным рангом (оконная функция).

SELECT prod, quant cust,
    dense_rank() OVER (PARTITION BY prod ORDER BY quant DESC) AS c_rank
FROM sales WHERE c_rank < 2;

это даст вам строки для продукта с максимальным значением quant. Вы можете сделать то же самое для минимального количества. это будет сложнее сделать как в одном запросе, вы можете сделать это простым способом создания таблиц на лету для каждого случая и объединения их, как показано ниже.

with max_quant as (
SELECT prod, quant cust,
    dense_rank() OVER (PARTITION BY prod ORDER BY quant DESC) AS c_rank
FROM sales WHERE c_rank < 2
),
min_quant as (
SELECT prod, quant cust,
    dense_rank() OVER (PARTITION BY prod ORDER BY quant DESC) AS c_rank
FROM sales WHERE c_rank < 2
),
avg_quant as (
select prod, avg(quant) as avg_quant from sales group by prod
)

select mx.prod, mx.quant, mx.cust, mn.quant, mn.cust, ag.avg_quant
from max_quant mx 
join min_quant mn on mn.prod = mx.prod
join avg_quant ag on ag.prod = mx.prod;

вы не можете использовать group by, чтобы выбрать здесь мин / макс, так как вы хотите получить полную строку для минимального / максимального значения кванта, что невозможно напрямую с group by.

...