如何加入一对多关系以确保左边只有一行回来?

时间:2009-10-16 18:10:31

标签: sql sql-server tsql sql-server-2000

对于一个模糊的标题感到抱歉,但这就是我想要做的。

我有以下两个表

TABLE_PERSON | TABLE_PHONE
             |
col_Name     | col_Name      col_phoneID    col_phoneNbr
--------     | --------      -----------    ------------
Clark Kent   | Clark Kent    1              111-111-1111
Bruce Wayne  | Clark Kent    2              222-222-2222
Peter Parker | Peter Parker  2              333-333-3333
             | Peter Parker  3              444-444-4444
             | Bruce Wayne   3              555-555-5555
             | Bruce Wayne   4              666-666-6666

col_Name实际上是一个ID字段,但我使用一个名称进行演示。这是我想通过一个SQL语句获得的东西

col_Name      col_phoneNbr
--------      ------------
Clark Kent    111-111-1111
Peter Parker  333-333-3333
Bruce Wayne   555-555-5555

phone_ID实际上是一种电话号码,如主电话号码,传真号码,免费电话等。所以在我的输出中我希望每个人都有一个电话号码,但是要选择这样的方式,如果类型“1”不可用,选择类型“2”,如果不存在类型“2”,选择类型“3”等。在我的情况下有6种类型,它们的优先级类似于4> 2> 1> 3> 5> 6,所以我希望能够只选择第一个可用的数字,如果两者都不存在则为NULL。

我在之前的项目中使用了一个非常复杂的方法,我会选择所有类型“1”然后所有类型“2”,同时使用“NOT IN”子句过滤类型“1”然后UNIONing两个集合在一起。实际上,它最终变成了4组,而对于1000多条记录我正在退出,它运行得非常慢。

我应该提到这是MS SQL Server 2000,所以我不能使用任何2005功能。

提前致谢!

3 个答案:

答案 0 :(得分:4)

SELECT
    pe.col_Name,
    (SELECT TOP (1) 
         ph.col_PhoneNbr
     FROM TABLE_PHONE ph
     WHERE pe.col_Name = ph.col_Name
     ORDER BY
         CASE col_phoneID
             WHEN 4 THEN 1
             WHEN 2 THEN 2
             WHEN 1 THEN 3
             WHEN 3 THEN 4
             WHEN 5 THEN 5
             WHEN 6 THEN 6
         END
    ) as col_phoneNbr
FROM TABLE_PERSON pe

答案 1 :(得分:2)

电话ID的优先级是其数值的简单情况:

select pers.col_Name, ph2.col_phoneNbr
from TABLE_PERSON pers
inner join (select col_Name, min(col_phoneID) from TABLE_PHONE group by col_Name) as ph1 on ph1.col_Name=pers.col_Name
inner join TABLE_PHONE ph2 on ph2.col_Name=pers.col_Name and ph2.col_PhoneID=ph1.col_PhoneID

现在,让我们创建一个映射来处理优先级< - > ID: 试试这个:

create table phone_prio (phone_ID int, prio int);

insert into phone_prio (phone_ID, prio) values (4, 1);
insert into phone_prio (phone_ID, prio) values (2, 2);
insert into phone_prio (phone_ID, prio) values (1, 3);
insert into phone_prio (phone_ID, prio) values (3, 4);
insert into phone_prio (phone_ID, prio) values (5, 5);
insert into phone_prio (phone_ID, prio) values (6, 6);

并更新天真的案例:

select pers.col_Name, ph2.col_phoneNbr
from TABLE_PERSON pers
inner join (
    select col_Name, min(pr.prio) as prio
    from TABLE_PHONE ph
    inner join phone_prio pr on pr.phone_ID=ph.col_phoneID
    group by col_Name
) as ph1 on ph1.col_Name=pers.col_Name
inner join phone_prio pr1 on pr.prio=ph1.prio
inner join TABLE_PHONE ph2 on ph2.col_Name=pers.col_Name and ph2.col_PhoneID=pr1.phoneID

答案 2 :(得分:1)

您想使用HAVING子句

GROUP by col_phoneID
HAVING col_phoneID = MAX(col_phoneID)

显然,MAX不是您想要的,因此您可能需要在查询中添加一些内容 但我希望它能指出你正确的方向。