我在这里已经阅读了几乎所有的问题,可以发现这是从子查询中获取最新记录,但是我无法弄清楚如何使其在我的情况下起作用。
我正在创建要在SQL Server 2008上使用的SSRS报告。
数据库中是联系人和DBSdata的表。我想从DBSdata表(将来最远的到期日期)中提取联系人列表和最新记录(该行中的许多字段)
Contacts
========
PKContactID ContactName
----------- -----------
1 JONES Chris
2 SMITH Mary
3 GREY Jean
DBSdata
=======
Ordinal FKContactID ExpiryDate IssueDate DBSType
------- ----------- ---------- --------- -------
3 1 2021-09-01 2019-09-01 Internal
2 1 2019-08-31 2017-08-31 External
1 1 2017-07-01 2015-07-01 Internal
2 2 2021-04-15 2019-04-15 Internal
1 2 2019-05-05 2017-05-06 External
1 3 2018-01-03 2016-03-02 External
我想要的结果是:
Latest DBS
==========
PKContactID ContactName ExpiryDate IssueDate DBSType
-------------------------------------------------------------------
3 GREY Jean 2018-01-03 2016-03-02 External
1 JONES Chris 2021-09-01 2019-09-01 Internal
2 SMITH Mary 2021-04-15 2019-04-15 Internal
[[DBSData表没有它自己的主键字段-不幸的是,这不是我可以控制的...而且每个联系人的顺序数增加,所以FKContactID + Ordinal是唯一的。...]
这是我必须使用的代码,但是它不起作用。我要上载SSRS的系统根本没有给我任何有用的错误消息,因此恐怕我无法更详细地说明哪些功能无效。我没有显示任何SSRS报告,只是一个错误,表明数据集源不起作用。
SELECT
c.PKContactID, c.ContactName, d.ExpiryDate, d.IssueDate, d.DBSType
FROM
Contacts c
LEFT JOIN (
SELECT TOP 1 FKContactID, ExpiryDate, IssueDate, DBSType
FROM DBSData
WHERE FKContactID = c.PKContactID
ORDER BY ExpiryDate DESC
) d ON c.PKContactID = d.FKContactID
ORDER BY
c.ContactName
我怀疑这与子查询中的WHERE
有关,但是如果我没有这个问题,则整个表正在使用WHOLE表并返回1行,而不是该联系人的前1行。
答案 0 :(得分:1)
您的方法将使用APPLY
而不是JOIN
:
SELECT c.PKContactID, c.ContactName,
d.ExpiryDate, d.IssueDate, d.DBSType
FROM Contacts c OUTER APPLY
(SELECT TOP 1 d.*
FROM DBSData d
WHERE d.FKContactID = c.PKContactID
ORDER BY d.ExpiryDate DESC
) d
ORDER BY c.ContactName;
从技术上讲APPLY
实现了称为“横向连接”的功能。这就像一个相关的子查询,但是它可以返回多行多列。横向联接非常强大,这是使用它们的一个很好的例子。
为了提高性能,您希望在DBSData(FKContactID, ExpiryDate DESC)
(可能还包括其他想要的列)和Contacts(ContactName)
上建立索引。
使用正确的索引,我希望它的性能至少与其他方法一样好。
另一种通常也具有良好性能的替代方法是使用相关子查询进行过滤:
SELECT c.PKContactID, c.ContactName,
d.ExpiryDate, d.IssueDate, d.DBSType
FROM Contacts c LEFT JOIN
DBSData d
ON d.FKContactID = c.PKContactID AND
d.ExpiryDate = (SELECT MAX(d2.ExpiryDate)
FROM DBSData d
WHERE d2.FKContactID = d.FKContactID
);
请注意,要匹配LEFT JOIN
,相关条件必须位于ON
子句中,而不是WHERE
子句中。
最后,如果您确实使用窗口函数,我建议您使用子查询来获取第一行:
SELECT c.PKContactID, c.ContactName,
d.ExpiryDate, d.IssueDate, d.DBSType
FROM Contacts c LEFT JOIN
(SELECT d.*,
ROW_NUMBER() OVER (PARTITION BY d.FKContactID ORDER BY d.PKContactID DESC) as seqnum
FROM DBSData d
) d
ON d.FKContactID = c.PKContactID AND
d.seqnum = 1;
在JOIN
之前执行子查询为优化器提供了更多机会来制定更好的执行计划。
答案 1 :(得分:0)
以下是使用row_number()
的一种选择:
SELECT *
FROM (
SELECT
c.PKContactID, c.ContactName, d.ExpiryDate, d.IssueDate, d.DBSType,
row_number() over (partition by c.PKContactID order by d.ExpiryDate desc) rn
FROM
Contacts c
LEFT JOIN DBSData d ON d.FKContactID = c.PKContactID
) t
WHERE rn = 1
ORDER BY ContactName
答案 2 :(得分:0)
此解决方案可以提供您所期望的结果,并且性能更高。
select c.PKContactID,c.ContactName,d.ExpiryDate, d.IssueDate, d.DBSType from Contacts c
inner join DBSdata d
on c.PKContactID=d.FKContactID
where d.Ordinal in (select max(d.Ordinal) from DBSdata d where d.FKContactID=c.PKContactID)
order by c.ContactName