SQL 有最新记录的子查询
SQL subquery with latest record
我已经阅读了这里的几乎所有问题,我发现它引用了从子查询中获取最新记录,但我不知道如何让它在我的情况下工作。
我正在创建用于 SQL Server 2008 的 SSRS 报告。
数据库中有 table 联系人和 DBS 数据。我想从 DBSdata table(最晚到期日)
中提取联系人列表和最新记录(该行的许多字段)
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 table 没有它自己的主键字段 - 不幸的是,这不是我可以控制的东西......而且每个联系人的序数增加,所以 FKContactID+Ordinal 是唯一的.. ..]
这是我必须使用的代码,但它不起作用。我将 SSRS 上传到的系统根本没有给我任何有用的错误消息,所以恐怕我不能更具体地说明什么不起作用。我得到 none 的 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
有关,但如果我没有,整个 table 正在使用整个 table 并返回 1行,而不是该联系人的前 1 位。
这是一个使用 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
此解决方案给出了您预期的结果,而且性能要高得多。
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
您的方法可以使用 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
实现了一种称为 横向连接 的东西。这就像一个相关子查询,但它可以 return 多行和多列。横向连接非常强大,这是使用它们的一个很好的例子。
为了性能,您需要 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
子句中。
最后,如果您使用 window 函数,我建议使用子查询来获取第一行:
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
之前执行子查询可以让优化器有更多机会生成更好的执行计划。
我已经阅读了这里的几乎所有问题,我发现它引用了从子查询中获取最新记录,但我不知道如何让它在我的情况下工作。
我正在创建用于 SQL Server 2008 的 SSRS 报告。
数据库中有 table 联系人和 DBS 数据。我想从 DBSdata table(最晚到期日)
中提取联系人列表和最新记录(该行的许多字段)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 table 没有它自己的主键字段 - 不幸的是,这不是我可以控制的东西......而且每个联系人的序数增加,所以 FKContactID+Ordinal 是唯一的.. ..]
这是我必须使用的代码,但它不起作用。我将 SSRS 上传到的系统根本没有给我任何有用的错误消息,所以恐怕我不能更具体地说明什么不起作用。我得到 none 的 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
有关,但如果我没有,整个 table 正在使用整个 table 并返回 1行,而不是该联系人的前 1 位。
这是一个使用 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
此解决方案给出了您预期的结果,而且性能要高得多。
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
您的方法可以使用 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
实现了一种称为 横向连接 的东西。这就像一个相关子查询,但它可以 return 多行和多列。横向连接非常强大,这是使用它们的一个很好的例子。
为了性能,您需要 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
子句中。
最后,如果您使用 window 函数,我建议使用子查询来获取第一行:
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
之前执行子查询可以让优化器有更多机会生成更好的执行计划。