在 Join 表达式中捕获所有记录
Catch All Record in a Join expression
我有一个很简单的(我觉得很简单,但我还在苦苦挣扎!)的问题。我有 table 辆汽车。我还有 table 辆 class 辆汽车。我想将一个连接到另一个以获得汽车的 class。
汽车 table 很简单,有型号和品牌。 class table 也有一个型号和一个品牌和一个类型 class。当我想将相同品牌的汽车归为一组而不考虑其型号时,问题就出现了。
例如,我有两辆车:
id vehiclemake vehiclemodel
1 AUDI R8
2 AUDI Quattro
我有两个 classes:
id vehiclemake vehiclemodel classtype
1 AUDI R8 A
2 AUDI NULL B
AUDI R8 将匹配 class A 型。我希望所有其他 AUDI,无论其型号如何,都匹配 class B 型。
我这里有一些示例代码,你可以玩一下!
create table #vehicle(id int, vehiclemake varchar(10), vehiclemodel varchar(10))
create table #vehicleclass(id int, vehiclemake varchar(10), vehiclemodel varchar(10), classtype varchar(1))
insert into #vehicle values(1, 'AUDI', 'R8')
insert into #vehicle values(2, 'AUDI', 'Quattro')
insert into #vehicleclass values(1, 'AUDI', 'R8', 'A')
insert into #vehicleclass values(2, 'AUDI', null, 'B')
select
*
from
#vehicle v
left join #vehicleclass vc on
(v.vehiclemake = vc.vehiclemake and v.vehiclemodel = vc.vehiclemodel)
drop table #vehicle
drop table #vehicleclass
上面的语句没有将 Quattro 记录加入 B class 记录
在 vehiclemodel
的连接上使用 COALESCE 以便当模型在 vehicleclass
table 上为 NULL 时,车辆将改为匹配自己的模型.
[编辑]:阅读用户评论后,试试这个:
SELECT *
FROM #vehicle v
INNER JOIN #vehicleclass vc
ON v.vehiclemake = vc.vehiclemake
AND v.vehiclemodel = vc.vehiclemodel
UNION
SELECT *
FROM #vehicle v
INNER JOIN #vehicleclass vc
ON v.vehiclemake = vc.vehiclemake
AND vc.vehiclemodel IS NULL
WHERE NOT EXISTS(SELECT 1
FROM #vehicleclass vc2
where vc2.vehiclemake = v.vehiclemake
and vc2.vehiclemodel = v.vehiclemodel);
可能这就是您想要的:
SELECT *
FROM #vehicle v
JOIN #vehicleclass vc ON v.vehiclemake = vc.vehiclemake
AND ( v.vehiclemodel = vc.vehiclemodel
OR ( vc.vehiclemodel IS NULL
AND v.vehiclemodel NOT IN (
SELECT vehiclemodel
FROM #vehicleclass
WHERE vehiclemodel IS NOT NULL )
)
)
输出:
id vehiclemake vehiclemodel id vehiclemake vehiclemodel classtype
1 AUDI R8 1 AUDI R8 A
2 AUDI Quattro 2 AUDI NULL B
SELECT *
FROM #vehicle v
LEFT JOIN #vehicleclass vc
ON (v.vehiclemake = vc.vehiclemake
AND v.vehiclemodel = COALESCE(vc.vehiclemodel, v.vehiclemodel))
WHERE v.Id = vc.id
输出:
id vehiclemake vehiclemodel id vehiclemake vehiclemodel classtype
1 AUDI R8 1 AUDI R8 A
2 AUDI Quattro 2 AUDI NULL B
这里我倾向于使用UNION ALL
,因为你确实有两个要求。
- 获取车辆中有匹配记录的所有车辆的class。
- 为没有匹配 class 的所有车型获取默认值 class。
尝试在单个查询中执行此操作是可能的,但通常会掩盖执行计划,因此无法以最佳方式使用索引。
SELECT *
FROM #Vehicle AS v
INNER JOIN #vehicleclass AS vc
ON vc.VehicleMake = v.VehicleMake
AND vc.VehicleModel = v.VehicleModel
UNION ALL
SELECT *
FROM #Vehicle AS v
INNER JOIN #vehicleclass AS vc
ON vc.VehicleMake = v.VehicleMake
AND vc.VehicleModel IS NULL
WHERE NOT EXISTS
( SELECT 1
FROM #vehicleclass AS vc2
WHERE vc2.VehicleMake = v.VehicleMake
AND vc2.VehicleModel = v.VehicleModel
);
要在没有联合的情况下执行此操作,您可以使用:
SELECT *
FROM #Vehicle AS v
CROSS APPLY
( SELECT TOP 1 *
FROM #vehicleclass AS vc
WHERE vc.VehicleMake = v.VehicleMake
ORDER BY CASE WHEN vc.VehicleModel = v.VehicleModel THEN 0 ELSE 1 END
) AS vc;
这将取决于您在每个 table 上拥有的索引,哪个会表现更好。没有索引后者有更好的执行计划,因为它只需要两次扫描,但是如果我为每个 table:
添加索引
CREATE NONCLUSTERED INDEX #IX_Vehicle__VehicleMake_VehicleClass ON #Vehicle (VehicleMake, VehicleModel) ;
CREATE NONCLUSTERED INDEX #IX_VehicleClass__VehicleMake_VehicleClass ON #Vehicle (VehicleMake, VehicleModel);
然后前者变得更有效率,因为它能够更好地利用索引搜索。
我有一个很简单的(我觉得很简单,但我还在苦苦挣扎!)的问题。我有 table 辆汽车。我还有 table 辆 class 辆汽车。我想将一个连接到另一个以获得汽车的 class。
汽车 table 很简单,有型号和品牌。 class table 也有一个型号和一个品牌和一个类型 class。当我想将相同品牌的汽车归为一组而不考虑其型号时,问题就出现了。
例如,我有两辆车:
id vehiclemake vehiclemodel
1 AUDI R8
2 AUDI Quattro
我有两个 classes:
id vehiclemake vehiclemodel classtype
1 AUDI R8 A
2 AUDI NULL B
AUDI R8 将匹配 class A 型。我希望所有其他 AUDI,无论其型号如何,都匹配 class B 型。
我这里有一些示例代码,你可以玩一下!
create table #vehicle(id int, vehiclemake varchar(10), vehiclemodel varchar(10))
create table #vehicleclass(id int, vehiclemake varchar(10), vehiclemodel varchar(10), classtype varchar(1))
insert into #vehicle values(1, 'AUDI', 'R8')
insert into #vehicle values(2, 'AUDI', 'Quattro')
insert into #vehicleclass values(1, 'AUDI', 'R8', 'A')
insert into #vehicleclass values(2, 'AUDI', null, 'B')
select
*
from
#vehicle v
left join #vehicleclass vc on
(v.vehiclemake = vc.vehiclemake and v.vehiclemodel = vc.vehiclemodel)
drop table #vehicle
drop table #vehicleclass
上面的语句没有将 Quattro 记录加入 B class 记录
在 vehiclemodel
的连接上使用 COALESCE 以便当模型在 vehicleclass
table 上为 NULL 时,车辆将改为匹配自己的模型.
[编辑]:阅读用户评论后,试试这个:
SELECT *
FROM #vehicle v
INNER JOIN #vehicleclass vc
ON v.vehiclemake = vc.vehiclemake
AND v.vehiclemodel = vc.vehiclemodel
UNION
SELECT *
FROM #vehicle v
INNER JOIN #vehicleclass vc
ON v.vehiclemake = vc.vehiclemake
AND vc.vehiclemodel IS NULL
WHERE NOT EXISTS(SELECT 1
FROM #vehicleclass vc2
where vc2.vehiclemake = v.vehiclemake
and vc2.vehiclemodel = v.vehiclemodel);
可能这就是您想要的:
SELECT *
FROM #vehicle v
JOIN #vehicleclass vc ON v.vehiclemake = vc.vehiclemake
AND ( v.vehiclemodel = vc.vehiclemodel
OR ( vc.vehiclemodel IS NULL
AND v.vehiclemodel NOT IN (
SELECT vehiclemodel
FROM #vehicleclass
WHERE vehiclemodel IS NOT NULL )
)
)
输出:
id vehiclemake vehiclemodel id vehiclemake vehiclemodel classtype
1 AUDI R8 1 AUDI R8 A
2 AUDI Quattro 2 AUDI NULL B
SELECT *
FROM #vehicle v
LEFT JOIN #vehicleclass vc
ON (v.vehiclemake = vc.vehiclemake
AND v.vehiclemodel = COALESCE(vc.vehiclemodel, v.vehiclemodel))
WHERE v.Id = vc.id
输出:
id vehiclemake vehiclemodel id vehiclemake vehiclemodel classtype
1 AUDI R8 1 AUDI R8 A
2 AUDI Quattro 2 AUDI NULL B
这里我倾向于使用UNION ALL
,因为你确实有两个要求。
- 获取车辆中有匹配记录的所有车辆的class。
- 为没有匹配 class 的所有车型获取默认值 class。
尝试在单个查询中执行此操作是可能的,但通常会掩盖执行计划,因此无法以最佳方式使用索引。
SELECT *
FROM #Vehicle AS v
INNER JOIN #vehicleclass AS vc
ON vc.VehicleMake = v.VehicleMake
AND vc.VehicleModel = v.VehicleModel
UNION ALL
SELECT *
FROM #Vehicle AS v
INNER JOIN #vehicleclass AS vc
ON vc.VehicleMake = v.VehicleMake
AND vc.VehicleModel IS NULL
WHERE NOT EXISTS
( SELECT 1
FROM #vehicleclass AS vc2
WHERE vc2.VehicleMake = v.VehicleMake
AND vc2.VehicleModel = v.VehicleModel
);
要在没有联合的情况下执行此操作,您可以使用:
SELECT *
FROM #Vehicle AS v
CROSS APPLY
( SELECT TOP 1 *
FROM #vehicleclass AS vc
WHERE vc.VehicleMake = v.VehicleMake
ORDER BY CASE WHEN vc.VehicleModel = v.VehicleModel THEN 0 ELSE 1 END
) AS vc;
这将取决于您在每个 table 上拥有的索引,哪个会表现更好。没有索引后者有更好的执行计划,因为它只需要两次扫描,但是如果我为每个 table:
添加索引CREATE NONCLUSTERED INDEX #IX_Vehicle__VehicleMake_VehicleClass ON #Vehicle (VehicleMake, VehicleModel) ;
CREATE NONCLUSTERED INDEX #IX_VehicleClass__VehicleMake_VehicleClass ON #Vehicle (VehicleMake, VehicleModel);
然后前者变得更有效率,因为它能够更好地利用索引搜索。