在以下问题中 Filtering based on Joining Multiple Tables in SQL
我设法确定发帖人问题是因为他正在从外部查询访问派生表。
我不明白为什么会这样。
因此,如果您运行以下内容
create table salesperson (
id int, name varchar(40)
)
create table customer (
id int, name varchar(40)
)
create table orders (
number int, cust_id int, salesperson_id int
)
insert into salesperson values (1, 'abe'); insert into salesperson values (2, 'bob');
insert into salesperson values (5, 'chris'); insert into salesperson values (7, 'dan');
insert into salesperson values (8, 'ken'); insert into salesperson values (11, 'joe');
insert into customer values (4, 'Samsonic'); insert into customer values (6, 'panasung');
insert into customer values (7, 'samony'); insert into customer values (9, 'orange');
insert into orders values (10, 4, 2); insert into orders values (20, 4, 8);
insert into orders values (30, 9, 1); insert into orders values (40, 7, 2);
insert into orders values (50, 6, 7); insert into orders values (60, 6, 7);
insert into orders values (70, 9, 7);
SELECT *
FROM salesperson s
INNER JOIN orders o ON s.id = o.salesperson_id
INNER JOIN customer c ON o.cust_id = c.id
WHERE s.name NOT IN (
select s.name where c.name='Samsonic'
)
SELECT *
FROM salesperson s
INNER JOIN orders o ON s.id = o.salesperson_id
INNER JOIN customer c ON o.cust_id = c.id
WHERE s.name NOT IN (
SELECT s.name
FROM salesperson s
INNER JOIN orders o ON s.id = o.salesperson_id
INNER JOIN customer c ON o.cust_id = c.id
WHERE c.name = 'Samsonic'
)
第一个select语句访问外部查询中的派生表,而另一个则创建自己的联接并派生自己的表。
为什么第一个选择包含bob而另一个则不包含bob?
答案 0 :(得分:1)
在您的第一个查询中,您仅删除客户名称为Samsonic的行,因为Bob记录了一个输出的谐音记录。
在第二个中,您得到了一个具有客户名称Samsonic的销售人员,在这种情况下,您同时获得了Bob和Ken,然后您使用“ not in”删除了Bob和Ken的所有记录,因此鲍勃被移走了,所以你什么也没得到。
答案 1 :(得分:1)
区别在于,在您的第一个查询中,您仅删除涉及Samsonic的订单,因为排除项仅查看当前行中的数据。鉴于它的声音,您想删除曾经销售过Samsonic的任何销售人员。您可以在以下查询的结果中看到与的区别:
SELECT *, s.name, c.name
, case when s.name NOT IN (
select s.name where c.name='Samsonic'
) then 1 else 0 end /* Order not Samsonic */
, case when not exists (
select 1
from Orders O1
inner join Customer C1 on o1.cust_id = c1.id
where C1.Name = 'Samsonic' and o1.salesperson_id = O.salesperson_id
) then 1 else 0 end /* Salesperson never sold a Samsonic */
FROM salesperson s
INNER JOIN orders o ON s.id = o.salesperson_id
INNER JOIN customer c ON o.cust_id = c.id
答案 2 :(得分:1)
您的第一个查询的select
中没有from
子句。因此where
等效于:
WHERE s.name NOT IN (CASE WHEN c.name = 'Samsonic' THEN s.name END)
或更简单地说:
WHERE c.name <> 'Samsonic'
Bob的订单不与'Samsonic'
匹配,因此Bob在结果集中。换句话说,逻辑是分别查看每一行。
第二个版本正在查看已下订单的所有名称。鲍勃是这些名字之一,因此这适用于鲍勃发出的所有订单。
如果要排除曾经向'Samsonic'
下订单的所有销售人员,那么我建议使用窗口函数而不是复杂的逻辑:
SELECT *
FROM (SELECT s.id as salesperson_id, s.name as salesperson_name, c.id as customer_id, c.name as customer_name, o.number,
SUM(CASE WHEN c.name = 'Samsonic' THEN 1 ELSE 0 END) OVER (PARTITION BY s.id) as num_samsonic
FROM salesperson s INNER JOIN
orders o
ON s.id = o.salesperson_id INNER JOIN
customer c
ON o.cust_id = c.id
WHERE c.name <> 'Samsonic'
) soc
WHERE num_samsonic = 0