我有一个更复杂的情况,但我想我可以让这个例子更容易回答。假设我正在尝试查询那些在德克萨斯州并且只驾驶蓝色卡车的人。我正在使用Oracle数据库。
我有2个表(State table
)和(Truck table
)他们加入人员ID#
汽车表很大!这是最大的问题,因为我不希望查询挂起或运行很长时间。
州表
People State
------ -----
111 TX
222 TX
333 CA
卡车表
People Date Color
------ ---- ------
111 1995 Orange
111 1996 Blue
111 1997 White
111 2017 Blue
111 2017 Gold
222 2006 Blue
333 2007 Blue
我想要返回的只有222,因为他们没有任何其他颜色的卡车。
222 2006 Blue
如果有更好的方法来创建看起来像桌子的东西,我也想知道。
如何使用拥有。
select state.people, state, color, count(color)
from state, truck
where state.people = truck.people
and state.state = 'TX'
and color = 'Blue'
group by state.people, state, color
having count(color) = 1
这是小提琴
假设所有列都具有NOT NULL约束:
select State.People
from State
join Truck on Truck.People = State.People
where State.State = 'TX'
and Truck.Color = 'Blue'
and not exists (
select null
from Truck t2
where t2.People = Truck.People
and t2.Color != 'Blue'
);
Truck (People, Color)
的覆盖指数可能足以表现。
另一种考虑因素:
select State.People
from State
join Truck on Truck.People = State.People
where State.State = 'TX'
and Truck.Color = 'Blue'
minus
select Truck.People
from Truck
where Truck.People = Truck.People
and Truck.Color != 'Blue';
为了进行更多性能调优,我将首先查看执行计划和近似数据量。
ADDED(事后):下面的解决方案只返回people
标识符(本例中为222),而不是truck
表中那些人的行(或行!)。如果需要完整行而不是聚合查询,则可以使用分析函数。易于修改,但首先回答我在原始问题的评论中提出的问题。结束编辑。
with
state_table ( people, state ) as (
select 111, 'TX' from dual union all
select 222, 'TX' from dual union all
select 333, 'CA' from dual
),
truck_table ( people, dt, color ) as (
select 111, 1995, 'Orange' from dual union all
select 111, 1996, 'Blue' from dual union all
select 111, 1997, 'White' from dual union all
select 111, 2017, 'Blue' from dual union all
select 111, 2017, 'Gold' from dual union all
select 222, 2006, 'Blue' from dual union all
select 333, 2007, 'Blue' from dual
)
-- End of simulated inputs (for testing only, not part of the solution).
-- SQL query begins BELOW THIS LINE. Use your actual table and column names
select people
from truck_table
where people in ( select people
from state_table
where state = 'TX'
)
group by people
having count(case when color != 'Blue' or color is null then 1 end) = 0
;
PEOPLE
----------
222
如何尝试子查询如下:
select * from (select state.People, truck.Date, truck.Color,
count(truck.People) over (partition by state.People) Cnt from state
left join truck on state.People = truck.People and truck.Color = 'Blue'
where state.State = 'TX')
where cnt = 1
您可以首先使用JOIN查询表:
SELECT People, Date, Color
FROM Truck
INNER JOIN State ON Truck.People = State.People
WHERE State.State = 'TX'
AND Truck.Color = 'Blue'
如果查询的性能不足,那么您可能希望在任一表上添加适当的索引。例如,您可能希望在Color属性上向Truck表添加索引。