Как можно сравнить полные группы в SQL без использования функции поворота в Redshift? - PullRequest
0 голосов
/ 21 апреля 2020

У меня есть таблица, см. Схему ниже:

CREATE TEMP TABLE merchants
(
  merchant_id varchar(15)
  ,product_id varchar(15)
);

INSERT INTO merchants VALUES ('Merchant A','Product 1');
INSERT INTO merchants VALUES ('Merchant A','Product 2');
INSERT INTO merchants VALUES ('Merchant A','Product 3');
INSERT INTO merchants VALUES ('Merchant B','Product 1');
INSERT INTO merchants VALUES ('Merchant B','Product 2');
INSERT INTO merchants VALUES ('Merchant B','Product 3');
INSERT INTO merchants VALUES ('Merchant B','Product 4');
INSERT INTO merchants VALUES ('Merchant C','Product 1');
INSERT INTO merchants VALUES ('Merchant C','Product 2');
INSERT INTO merchants VALUES ('Merchant C','Product 3');
INSERT INTO merchants VALUES ('Merchant D','Product 5');

SELECT *
FROM merchants;

Мне нужно найти торговые пары, которые продают 1) одинаковое количество товаров И 2) продают точно такие же продукты.

Ответ на приведенные выше данные будет:

Торговец A, Торговец C - та же строка.

Я нашел действительно плохое решение IMO, чтобы найти это, но я не думаю, что оно масштабируемое, поскольку, если продуктов больше, я не могу жестко закодировать их как столбцы. Также мой ответ в 2 ряда, а не в паре.

CREATE TEMP TABLE merchants_profile AS 
(
SELECT 
  merchant_id
  , COUNT(DISTINCT product_id) AS num_products
  , SUM(CASE WHEN product_id = 'Product 1' THEN 1 ELSE 0 END) AS num_1
  , SUM(CASE WHEN product_id = 'Product 2' THEN 1 ELSE 0 END) AS num_2
  , SUM(CASE WHEN product_id = 'Product 3' THEN 1 ELSE 0 END) AS num_3
  , SUM(CASE WHEN product_id = 'Product 4' THEN 1 ELSE 0 END) AS num_4
  , SUM(CASE WHEN product_id = 'Product 5' THEN 1 ELSE 0 END) AS num_5
FROM merchants
GROUP BY 1
);

SELECT A.merchant_id
FROM merchants_profile AS A 
INNER JOIN 
merchants_profile AS B 
ON A.merchant_id <> B.merchant_id
AND (A.num_products = B.num_products 
    AND A.num_1 = B.num_1 
    AND A.num_2= B.num_2 
    AND A.num_3 = B.num_3
    AND A.num_4 = B.num_4
    AND A.num_5 = B.num_5)

Ответ:

merchant_id Merchant C Merchant A

Может кто-нибудь придумать более креативного / эффективный способ сделать это, не используя сводную функциональность. Мне нужно решить это в красном смещении.

Как видно, мое решение неверно, и я не могу придумать способ найти пары.

Ответы [ 2 ]

0 голосов
/ 22 апреля 2020

Это отвечает вашим потребностям?

select distinct
       listagg(product_id,',') within group (order by product_id) as product_combos, 
       listagg(merchant_id,',') within group (order by merchant_id) over (partition by product_combos) as merchant_list,
       count(1) over (partition by product_combos) as count_of_merchants
from merchants
group by merchant_id
order by count_of_merchants desc;
0 голосов
/ 21 апреля 2020

Самый простой способ - использовать listagg(). Это создает списки продавцов для каждого набора продуктов:

select products, listagg(merchant_id) within group (order by merchant_id) as merchants
from (select merchant_id,
             listagg(product_id) within group (order by product_id) as products
      from merchants_profile
      group by merchant_id
     ) m
group by products
having count(*) > 1;

Вы можете сделать то же самое, не агрегируя на уровне продавца, но это проще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...