我试图做以下事情。我需要返回一个人记录,其中还包括该人最老的狗的名字(当一个人有> 1只狗的时候)。以下查询返回NULL
dogName
。 (我已经检查并且有有效数据)如果我删除了联接查询的Top 1
和Order by
部分,则会返回有效的dogName
,但不会返回&{39}。最古老的'狗。为什么添加TOP 1
和OrderBy
会导致它返回NULL?
SELECT
pt.firstName [FirstName],
pt.lastName [LastName],
joinQuery.dogName [dogName]
FROM dbo.PersonTable pt
LEFT OUTER JOIN
(
SELECT
TOP 1
dt.dogName [dogName],
dt.dogAge [dogAge]
FROM
DogTable dt
ORDER BY dt.dogAge
) joinQuery ON joinQuery.PersonId = pt.Id
WHERE
pt.firstName = 'john'
注意:这只是一个类似的查询,我不允许在论坛中发帖。
另外,我不是一个专家,所以我可能试图错误地解决这个问题。提前谢谢。
答案 0 :(得分:1)
您根本不需要加入:
SELECT pt.firstname [FirstName],
pt.lastname [LastName],
(SELECT TOP 1 dt.dogname
FROM dogtable dt
WHERE dt.personid = pt.id
ORDER BY dt.dogage DESC) AS [dogName]
FROM dbo.persontable pt
WHERE pt.firstname = 'john'
请注意,最老的狗是ORDER BY dt.dogage DESC
。
答案 1 :(得分:0)
您的ORDER BY
子句似乎需要有一个尾随的DESC
关键字;正如你所指出的,你想要找回“最老的狗”。
答案 2 :(得分:0)
对我来说没问题,虽然在这种情况下我可能会考虑Rank()Over()
虽然在这种情况下可能会慢一些
答案 3 :(得分:0)
您的查询无效,您要按DogTable
未选择的列加入,如果您想要最早的order by desc
或使用max
功能,也可以加入。
SELECT
pt.firstName [FirstName],
pt.lastName [LastName],
joinQuery.dogName [dogName]
FROM dbo.PersonTable pt
LEFT OUTER JOIN
(
SELECT
TOP 1
dt.PersonId,
dt.dogName [dogName],
dt.dogAge [dogAge]
FROM
DogTable dt
ORDER BY dt.dogAge
) joinQuery ON joinQuery.PersonId = pt.Id
WHERE
pt.firstName = 'john'
答案 4 :(得分:0)
你的查询返回NULL的原因是你从桌子上挑选了一只狗,而不是每人一只狗1只狗,所以如果'john'没有最年轻的狗(因为你没有按降序排序)狗表,你不会返回一个值。您首先需要每个PersonID的结果,然后才限制您感兴趣的人/人。
使用ROW_NUMBER()
或RANK()
是解决此类问题的好方法:
SELECT
pt.firstName [FirstName],
pt.lastName [LastName],
pet.dogName [dogName]
FROM dbo.PersonTable pt
LEFT JOIN
(
SELECT dogName [dogName],dogAge [dogAge], PersonID, ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY dogage DESC) DogRank
FROM DogTable
) pet ON pet.PersonId = pt.Id
AND pet.DogRank = 1
WHERE
pt.firstName = 'john'
如果一个人有多只6岁的狗,你可以使用RANK()
代替ROW_NUMBER()
来归还两只狗。如果您只想要其中一个,请坚持使用ROW_NUMBER()
。
答案 5 :(得分:0)
抛弃TOP
和ORDER BY
,不要使用任何奇特的SQL(PARTITIONS
,RANK
等等。)。只需使用普通的旧SQL,就像这样......
SELECT
pt.firstName [FirstName],
pt.lastName [LastName],
joinQuery.dogName [dogName]
FROM dbo.PersonTable pt
LEFT OUTER JOIN dbo.DogTable joinQuery ON joinQuery.PersonId = pt.id
WHERE joinQuery.dogAge = (SELECT MAX(dt.dogAge)
FROM DogTable dt WHERE dt.PersonId = pt.id)
AND pt.firstName = 'john'
答案 6 :(得分:0)
另一种方法是使用APPLY
。 OUTER APPLY
对应于外连接,CROSS APPLY
对应于内连接。见
http://www.mssqltips.com/sqlservertip/1958/sql-server-cross-apply-and-outer-apply/
和
http://technet.microsoft.com/en-us/library/ms175156%28v=sql.105%29.aspx
SELECT
pt.firstName [FirstName],
pt.lastName [LastName],
joinQuery.dogName [dogName]
FROM dbo.PersonTable pt
OUTER APPLY
(
SELECT
TOP 1
dt.dogName [dogName],
dt.dogAge [dogAge]
FROM
DogTable dt
WHERE dt.PersonId = pt.Id
ORDER BY dt.dogAge
) joinQuery
WHERE
pt.firstName = 'john'