如何将LEFT JOIN限制为SQL Server中的第一个结果?

Jus*_*808 21 sql sql-server sql-server-2000 greatest-n-per-group

我有一点SQL几乎正在做我想要它做的事情.我正在使用三个表,一个是Users,UserPhoneNumbers和UserPhoneNumberTypes.我正在尝试获取一个用户列表,其中包含用于导出的电话号码.

数据库本身很旧并且存在一些完整性问题.我的问题是,数据库中每个电话号码应该只有1种类型,但事实并非如此.当我运行这个时,我得到每个人的多行结果,如果它们包含例如两个"Home"数字.

如何修改SQL以获取列出的第一个电话号码并忽略其余的号码?我在SQL Server中,我知道TOP语句.但是,如果我将"TOP 1"添加到LEFT JOIN select语句,它只是给我数据库中的第一个条目,而不是每个用户的第一个条目.

这适用于SQL Server 2000.

谢谢,

SELECT  Users.UserID, 
  Users.FirstName, Users.LastName,
  HomePhone, WorkPhone, FaxNumber

FROM Users

LEFT JOIN
 (SELECT UserID, PhoneNumber AS HomePhone
 FROM UserPhoneNumbers LEFT JOIN UserPhoneNumberTypes ON UserPhoneNumbers.UserPhoneNumberTypeID=UserPhoneNumberTypes.UserPhoneNumberTypeID
 WHERE UserPhoneNumberTypes.PhoneNumberType='Home') AS tmpHomePhone
 ON tmpHomePhone.UserID = Users.UserID
LEFT JOIN
 (SELECT UserID, PhoneNumber AS WorkPhone
 FROM UserPhoneNumbers LEFT JOIN UserPhoneNumberTypes ON UserPhoneNumbers.UserPhoneNumberTypeID=UserPhoneNumberTypes.UserPhoneNumberTypeID
 WHERE UserPhoneNumberTypes.PhoneNumberType='Work') AS tmpWorkPhone
 ON tmpWorkPhone.UserID = Users.UserID
LEFT JOIN
 (SELECT UserID, PhoneNumber AS FaxNumber
 FROM UserPhoneNumbers LEFT JOIN UserPhoneNumberTypes ON UserPhoneNumbers.UserPhoneNumberTypeID=UserPhoneNumberTypes.UserPhoneNumberTypeID
 WHERE UserPhoneNumberTypes.PhoneNumberType='Fax') AS tmpFaxNumber
 ON tmpFaxNumber.UserID = Users.UserID
Run Code Online (Sandbox Code Playgroud)

OMG*_*ies 7

假设SQL Server 2005+,请使用ROW_NUMBER:

LEFT JOIN (SELECT UserID, 
                  PhoneNumber AS HomePhone,
                  ROW_NUMBER() OVER (PARTITION BY userid ORDER BY what?) AS rank
             FROM UserPhoneNumbers  upn
        LEFT JOIN UserPhoneNumberTypes upnt ON upnt.UserPhoneNumberTypeID = upn.UserPhoneNumberTypeID
                                           AND upnt.PhoneNumberType='Home') AS tmpHomePhone
                ON tmpHomePhone.UserID = Users.UserID
               AND tmpHomePhone.rank = 1
Run Code Online (Sandbox Code Playgroud)

注意what?占位符以确定第一个数字.如果你根本不关心,请省略ORDER BY ...


Rem*_*anu 7

无论何时只想从左表中右表中的每一行选择一行,您应该考虑使用APPLY运算符而不是join,并在左连接移动连接条件:

SELECT  u.UserID, 
  u.FirstName, u.LastName,
  hn.PhoneNumber AS HomePhone
FROM Users u
OUTER APPLY (
 SELECT TOP(1) PhoneNumber 
 FROM UserPhoneNumbers upn
 LEFT JOIN UserPhoneNumberTypes upt 
   ON upn.UserPhoneNumberTypeID=upt.UserPhoneNumberTypeID
 WHERE upt.PhoneNumberType='Home'
 AND upn.UserID = u.UserID
 ORDER BY ...) as hn
...
Run Code Online (Sandbox Code Playgroud)


Dan*_*n J 6

由于它是SQL Server 2000和排名函数,你可以使你的子查询聚合:

SELECT UserID, MAX(PhoneNumber) AS HomePhone FROM [...] GROUP BY UserID
Run Code Online (Sandbox Code Playgroud)

如果您不在乎返回用户的主页号码...