Найти товары не покупаются - PullRequest
0 голосов
/ 02 марта 2020

У меня проблемы с поиском оптимального решения этой проблемы:

У меня есть 2 таблицы: test_a и test_b.

Test_a хранит информацию о клиентах, покупающих продукты.

Test_b - это, в основном, таблица продуктов, в которой перечислены продукты, которые я хотел бы отслеживать. Клиенты могут купить много продуктов, но не все продукты находятся в test_b, только продукты, которые я хотел бы отследить, находятся в test_b.

Я бы хотел отследить, какие продукты не покупают отдельные клиенты.

Упрощенная таблица test_a и test_b будет выглядеть следующим образом:

test_a

enter image description here

Test_b

enter image description here

Я пробовал это утверждение:

select * from test_a a
right outer join test_b b
on trim(a.product) = trim(b.product)

Вышеприведенное утверждение только говорит мне, какой продукт ни один покупатель не купил вообще, но не говорит мне, какой продукт для каждого конкретного клиент не покупает. Мне бы хотелось, чтобы в результате было показано, что дата покупки этого продукта не указана для конкретного покупателя, который не покупает этот продукт, если он купил продукт, то поле dateofpurchase является фактической датой покупки.

** * Обновление

Результат, который я хотел бы видеть:

enter image description here

Существует ли чистый и эффективный способ достижения поставленной цели? над? Один из подходов, который я могу придумать, может состоять в том, чтобы выполнить полное внешнее объединение, а затем отфильтровать продукты, отсутствующие в test_b, но это не очень эффективно. Моя настоящая таблица test_a содержит пару миллионов записей, а test_b содержит около тысячи записей.

Прилагается скрипт примеров таблиц, о которых я упоминал выше:

  CREATE TABLE "TEST_A" 
   (    "ID" NUMBER(3,0), 
    "CUSTOMER" VARCHAR2(26 BYTE), 
    "PRODUCT" VARCHAR2(26 BYTE), 
    "DATEOFPURCHASE" DATE
   ) ;
Insert into  TEST_A (ID,CUSTOMER,PRODUCT,DATEOFPURCHASE) values (1,'A ','P1',to_date('12-DEC-19','DD-MON-RR'));
Insert into  TEST_A (ID,CUSTOMER,PRODUCT,DATEOFPURCHASE) values (2,'A ','P2',to_date('01-NOV-17','DD-MON-RR'));
Insert into  TEST_A (ID,CUSTOMER,PRODUCT,DATEOFPURCHASE) values (3,'A ','P3',to_date('01-JAN-20','DD-MON-RR'));
Insert into  TEST_A (ID,CUSTOMER,PRODUCT,DATEOFPURCHASE) values (4,'A ','P4',to_date('15-JUL-15','DD-MON-RR'));
Insert into  TEST_A (ID,CUSTOMER,PRODUCT,DATEOFPURCHASE) values (5,'B','P1',to_date('01-APR-16','DD-MON-RR'));
Insert into  TEST_A (ID,CUSTOMER,PRODUCT,DATEOFPURCHASE) values (6,'B','P3',to_date('12-AUG-18','DD-MON-RR'));
Insert into  TEST_A (ID,CUSTOMER,PRODUCT,DATEOFPURCHASE) values (7,'C','P3',to_date('15-JUN-12','DD-MON-RR'));


  CREATE TABLE "TEST_B" 
   (    "PRODUCT" VARCHAR2(26 BYTE), 
    "DEPARTMENT" NUMBER(3,0)
   ) ;
Insert into TEST_B (PRODUCT,DEPARTMENT) values ('P1',1);
Insert into TEST_B (PRODUCT,DEPARTMENT) values ('P2',2);

Ответы [ 3 ]

1 голос
/ 03 марта 2020

Это возвращает желаемый результат, но ... мне это не очень нравится.

SQL> alter session set nls_date_format = 'dd.mm.yyyy';

Session altered.

SQL> select distinct y.customer, b.product, x.dateofpurchase
  2  from test_b b cross join (select a.customer
  3                            from test_a a
  4                            where a.product in (select b.product from test_b b)
  5                           ) y
  6  left join test_a x on x.customer = y.customer and x.product = b.product
  7  order by y.customer, b.product;

CUSTOMER                   PRODUCT                    DATEOFPURC
-------------------------- -------------------------- ----------
A                          P1                         12.12.2019
A                          P2                         01.11.2017
B                          P1                         01.04.2016
B                          P2

SQL>
0 голосов
/ 02 марта 2020

Этот PIVOT может использоваться, чтобы увидеть, какие клиенты приобрели какие продукты

select *
  from (
select customer, product
  from test_a )
  pivot
  ( count(*)
    for product in ('P1', 'P2', 'P3')
  );
0 голосов
/ 02 марта 2020

Я рекомендую left join сверх right join, но для поиска несоответствий вам потребуется пункт where:

select b.*   -- why bring in columns from a when you know they are all NULL?
from test_b b left join
     test_a a
     on a.product = b.product
where a.product is null;

Я удалил trim(). Это может понадобиться только в том случае, если ваши данные загрязнены и у вас нет должным образом объявленных отношений с внешним ключом.

Лично я предпочитаю not exists для этого:

select b.*
from test_b b
where not exists (select 1 from test_a a where a.product = b.product);

РЕДАКТИРОВАТЬ:

Если вы хотите это для каждого клиента , тогда сделайте cross join клиентов и продуктов, чтобы получить все комбинации этих двух. Затем удалите те, которые существуют:

select c.customer, b.product
from (select distinct customer from test_a) c cross join
     test_b b left join
     test_a a
     on a.customer = c.customer and a.product = b.product
where a.customer is null;  -- no match
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...