在Join表达式中捕获所有记录

时间:2015-04-09 13:47:37

标签: sql tsql join sql-server-2008-r2 left-join

我有一个非常简单的(我认为这很简单,但我仍在努力!)问题。我有一张车的桌子。我有另一张车类表。我想加入一个到另一个去上车。

汽车桌很简单,有型号和品牌。类表还有一个模型,一个make和一个类的类。当我想将相同品牌的汽车组合在一起时,无论其型号如何,都会出现问题。

例如,我有两辆车:

id  vehiclemake vehiclemodel
1   AUDI            R8
2   AUDI            Quattro

我有两节课:

id  vehiclemake vehiclemodel    classtype
1   AUDI            R8          A
2   AUDI            NULL        B

AUDI R8将与A类相匹配。我希望所有其他AUDI不论其型号与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类记录

4 个答案:

答案 0 :(得分:2)

vehiclemodel的联接上使用COALESCE,这样当vehicleclass表上的模型为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);

答案 1 :(得分:0)

可能这就是你想要的:

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

我倾向于在这里使用UNION ALL,因为你真的有两个要求。

  1. 获取车辆中匹配记录的所有车辆的等级。
  2. 获取所有没有匹配类别的车型的默认等级。
  3. 尝试在单个查询中执行此操作是可能的,但通常会掩盖执行计划,因此索引不会以最佳方式使用。

    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;
    

    这将取决于您在每个表上的索引,哪些表现更好。没有索引后者有一个更好的执行计划,因为它只需要两次扫描,但如果我为每个表添加索引:

    CREATE NONCLUSTERED INDEX #IX_Vehicle__VehicleMake_VehicleClass ON #Vehicle (VehicleMake, VehicleModel) ;
    CREATE NONCLUSTERED INDEX #IX_VehicleClass__VehicleMake_VehicleClass ON #Vehicle (VehicleMake, VehicleModel);
    

    然后前者变得更有效率,因为它能够更好地利用指数。