我有两个表: TableA (ID [int, pk], Name [string])
和 TableB (ID [int, pk], TableA_ID [int, fk], Name [string], DateStamp [datetime (dd/mm/yyyy hh:MM:ss)])
。TableA和TableB之间存在一对多的关系
两个表上的内部联接将给出以下结果:
TableA.ID, TableA.Name, TableB.Name, TableB.DateStamp 1, 'File A', 'Version 1', 01/01/2009 15:00:00 1, 'File A', 'Version 2', 05/01/2009 08:15:00 1, 'File A', 'Version 3', 06/01/2009 19:33:00 2, 'File B', 'Version 1', 03/01/2009 09:10:00 2, 'File B', 'Version 2', 20/01/2009 20:00:00 3, 'File C', 'Version 1', 01/01/2009 17:00:00
我真正想要的是以下内容(TableA中的每一行和TableB中的最后一个匹配行):
TableA.ID, TableA.Name, TableB.Name, TableB.DateStamp 1, 'File A', 'Version 3', 06/01/2009 19:33:00 2, 'File B', 'Version 2', 20/01/2009 20:00:00 3, 'File C', 'Version 1', 01/01/2009 17:00:00
这是我用来实现此目的的查询:
SELECT ta.ID, ta.Name, tb.Name, tb.DateStamp
FROM TableA ta INNER JOIN TableB tb ON ta.ID = tb.TableA_ID
WHERE tb.ID IN (
SELECT TOP 1 tb2.ID
FROM TableB tb2
WHERE tb2.TableA_ID = ta.ID
ORDER BY tb2.DateStamp DESC)
这有效,但我的直觉是,我不是以“最好的方式”做到这一点。看起来它是聚合查询(即groupby)的候选者,但我没有任何运气。最后,我总是不得不使用子查询来获取我在TableB中的行。
任何帮助都非常感激。
答案 0 :(得分:5)
不,这里不需要进行GROUP BY,这应该通过相关的子查询来解决:
SELECT
TableA.ID,
TableA.Name,
TableB.Name,
TableB.DateStamp
FROM
TableA
INNER JOIN TableB ON
TableA.ID = TableB.TableA_ID
AND TableB.DateStamp = (
SELECT MAX(DateStamp)
FROM TableB
WHERE TableA_ID = TableA.ID
)
只有TableB
中的多条记录与TableA_ID
相等且等于DateStamp
时,才需要额外的GROUP BY。
对于您显示的具体示例,GROUP BY查询恰好产生正确的结果。这仍然是错误的,因为在这种情况下,正确的结果更具副作用。
SELECT
TableA.ID,
TableA.Name,
MAX(TableB.Name) Max_TableBName,
MAX(TableB.DateStamp) Max_TableBDateStamp
FROM
TableA
INNER JOIN TableB ON TableA.ID = TableB.TableA_ID
GROUP BY
TableA.ID,
TableA.Name
这取决于MAX(TableB.Name)
实际上是您想要获得的值的巧合,并且它与MAX(TableB.DateStamp)
对齐。但由于这种相关性仅仅是偶然事件,因此GROUP BY查询是错误的。
答案 1 :(得分:3)
你也可以尝试RANK()OVER功能:
-- Test data
DECLARE @TableA TABLE (ID INT, Name VARCHAR(20))
INSERT INTO @TableA
SELECT 1, 'File A' UNION
SELECT 2, 'File B' UNION
SELECT 3, 'File C'
DECLARE @TableB TABLE (ID INT, TableAID INT, Name VARCHAR(20),
DateStamp DATETIME)
INSERT INTO @TableB
SELECT 1, 1, 'Version 1', '01/01/2009 15:00:00' UNION
SELECT 2, 1, 'Version 2', '01/05/2009 08:15:00' UNION
SELECT 3, 1, 'Version 3', '01/06/2009 19:33:00' UNION
SELECT 4, 2, 'Version 1', '01/03/2009 09:10:00' UNION
SELECT 5, 2, 'Version 2', '01/20/2009 20:00:00' UNION
SELECT 6, 3, 'Version 1', '01/01/2009 17:00:00'
-- Actually answer
SELECT M.ID, M.AName, M.BName, M.DateStamp FROM
( SELECT RANK() OVER(PARTITION BY A.ID ORDER BY B.DateStamp DESC) AS N,
A.ID, A.Name AS AName, B.Name AS BName, B.DateStamp
FROM @TableA A INNER JOIN @TableB B ON A.ID = B.TableAID
) M WHERE M.N = 1
答案 2 :(得分:1)
您还可以使用分析功能进行查询。在Oracle中,您可以这样做:
select distinct
A.Id
, A.Name
, first_value(B.Name) over (partition by B.id
order by B.DateStamp desc) BName
, first_value(B.DateStamp) over (partition by B.id
order by B.DateStamp desc) DateStamp
from TableA A inner join TableB B on A.id = B.id
答案 3 :(得分:0)
如果你想使用group by,你可以使用:
select
ta.id, ta.name, tb.name, tb.dateStamp
from
tableA ta
inner join tableB tb on ta.id = tb.tablea_id
inner join (
select tablea_id, max(DateStamp) as maxDateStamp from tableB
group by tablea_id
) latestB
on tb.tablea_id = latestB.tablea_id
and tb.DateStamp = latestB.maxDateStamp
但是如果tableB中有多个条目,并且在tableA中引用相同行的DateStamp值相同,我将返回多个记录
答案 4 :(得分:0)
您无法在分组中从B表中可靠地获取多个字段,但您可以根据结果加入B表以获取其他字段:
select x.ID, x.Name, b.Name, b.DateStamp
from (
select a.ID, a.Name, max(b.DateStamp) as DateStamp
from TableA a
inner join TableB b on b.TableA_ID = a.ID
group by a.ID, a.Name
) x
inner join TableB b on b.TableA_ID = x.ID and b.DateStamp = x.DateStamp