在我的选择结果上显示不匹配

时间:2016-07-14 14:42:33

标签: sql postgresql

我有这三个表:

广告活动

 id |    name     | campaign_strategy_id 
----+-------------+----------------------
  5 | Teste Diego |                    3

campaign_strategy_blocked_routes

 campaign_strategy_id | route_id 
----------------------+----------
                    3 |        2
                    3 |        6

路线:

      name       | id 
-----------------+----
 Vonex Teste     |  3
 Filial Total IP |  2
 Filial TotalIP  |  6
 Tellfree teste  |  5

我需要查看未在广告系列中屏蔽的路线。在这种情况下,请注意,广告系列ID 5有两个被阻止的路线:2和6,但我需要在我的选择中显示其他两条路线:3和5.

我有这样的事情:

select campaigns.name, routes.id as route_id from campaigns left join campaign_strategy_blocked_routes on campaigns.campaign_strategy_id = campaign_strategy_blocked_routes.campaign_strategy_id left join routes on campaign_strategy_blocked_routes.route_id = routes.id

但结果显然是:

    name     | route_id 
-------------+----------
 Teste Diego |        2
 Teste Diego |        6

而且,就像我说的,我需要的是:

    name     | route_id 
-------------+----------
 Teste Diego |        3
 Teste Diego |        5

是否可以这样做?

基本上,谁想玩:http://sqlfiddle.com/#!15/f1305/3

3 个答案:

答案 0 :(得分:2)

select c.name, r.id
from campaigns c 
inner join routes r 
on not exists(select 1 from campaign_strategy_blocked_routes 
                where route_id = r.id 
                and campaign_strategy_id = c.campaign_strategy_id)

<强>解释

如果子查询没有找到campaigns表中的任何匹配行,则routes表和campaign_strategy_blocked_routes表的行将被连接。

如果找到exists中的一个或多个匹配行,

true会返回campaign_strategy_blocked_routes,但由于我们关心的是没有匹配的情况,我们会否定表达式(即{{1} }})。

子查询基本上等同于

not exists(...)

因此它会找到广告系列的封锁路线 但是,不是在子查询中连接表,而是由外部查询提供值select 1 from campaigns c inner join campaign_strategy_blocked_routes csbr on csbr.campaign_strategy_id = c.campaign_strategy_id inner join routes r on csbr.route_id = r.id r.id作为常量。

使用c.campaign_strategy_id因为我们不关心从子查询返回任何特定数据,我们只想知道是否有任何行要返回。

Documentation about exists

答案 1 :(得分:0)

试试这个:

SELECT a.name, c.id AS route_id from campaigns a, campaign_strategy_blocked_routes b
FULL OUTER JOIN routes c
ON b.route_id = c.id
WHERE b.route_id is null
OR c.id is null

返回:

name         route_id
Teste Diego  3
Teste Diego  5

答案 2 :(得分:0)

这个问题相当棘手,需要棘手的解决方案。这样的事情。

--tables
declare @campaigns table(id int,    name varchar(20), campaign_strategy_id int)
insert @campaigns values ( 5, 'Teste Diego', 3),
( 6, 'Test 2', 4) --I added an extra test row

declare @campaign_strategy_blocked_routes table(id int,route_id int)
insert @campaign_strategy_blocked_routes values(3,2),(3,6),
(4,3) --extra test

declare @routes table(name varchar(10),id int)
insert @routes values ('a',3), ('a',2), ('a',6), ('a',5) --names are not used

select distinct c.name,t.route_id
from @campaigns c 
left join @campaign_strategy_blocked_routes x1 on c.campaign_strategy_id=x1.id
--here is the trick. non-existing rows
--cross apply -- MS SQL Server
left join lateral --PostgreSQL
(select id
from @routes r --all routes
except
--used routes
select route_id
from @campaign_strategy_blocked_routes x
where x.id=x1.id
) t(route_id)
on true -- PostgreSQL only
order by c.name

--Results
name          route_id
Test 2        2
Test 2        5
Test 2        6
Teste Diego   3
Teste Diego   5