查找未购买的产品

时间:2020-03-02 20:15:18

标签: sql oracle

我无法找到解决此问题的最佳方法:

我有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)

上面的声明仅告诉我根本没有客户购买哪种产品,而没有告诉我每个特定客户没有购买哪种产品。我希望结果显示对于不购买该产品的特定客户,该产品的购买日期为空白,如果他们购买了该产品,则购买日期字段为实际购买日期。

***更新

我希望看到的结果是:

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 个答案:

答案 0 :(得分:1)

这返回期望的结果,但是...我不太喜欢它。

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>

答案 1 :(得分:0)

我建议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

答案 2 :(得分:0)

此PIVOT可用于查看哪些客户购买了哪些产品

select *
  from (
select customer, product
  from test_a )
  pivot
  ( count(*)
    for product in ('P1', 'P2', 'P3')
  );