Sql server 如何在CASE语句中使用CROSS-APPLY重用T-SQL子查询以避免重复
我有一个SELECT查询,在CASE语句中有不同的子查询。 我需要重新使用它们来获取同一个general SELECT中的其他列 两个主要表格是:Sql server 如何在CASE语句中使用CROSS-APPLY重用T-SQL子查询以避免重复,sql-server,tsql,sql-server-2008,Sql Server,Tsql,Sql Server 2008,我有一个SELECT查询,在CASE语句中有不同的子查询。 我需要重新使用它们来获取同一个general SELECT中的其他列 两个主要表格是: Event +------------+----------------------------+-------------+-----------------------------+ | Id | EventTypeId | PersonId | Name |DateEvent +-----
Event
+------------+----------------------------+-------------+-----------------------------+
| Id | EventTypeId | PersonId | Name |DateEvent
+------------+----------------------------+-------------+-----------------------------+
| 2307 | 4 | 2189 | Migrated | 1900-01-01 00:00:00.6780000 |
| 2308 | 15 | 2189 | Birthday | 2020-09-18 16:48:32.6870000 |
| 2309 | 15 | 2190 | Birthday | 2012-01-01 00:00:00.0000000 |
| 3401 | 6 | 2190 | Moved | 2013-03-12 00:00:00.0000000 |
| 3402 | 15 | 3001 | Birthday | 2020-08-21 16:48:32.6870000 |
| 3410 | 6 | 3001 | Moved | 1900-01-01 00:00:00.0000000 |
| 3440 | 6 | 2190 | Moved | 2016-03-12 00:00:00.0000000 |
| 4000 | 3 | 3001 | Transfer | 2021-01-10 00:00:00.0000000 |
| 4020 | 3 | 4020 | Transfer | 2016-03-12 00:00:00.0000000 |
Person
+------------+----------------+-------------------+-----------+-------------------------------+
| Id | UCNumber | Name |LastName | Birth |
+------------+----------------+-------------------+-----------+-------------------------------+
| 2189 | 004947 | John | Smith | 1900-01-01 00:00:00.0000000 |
| 2190 | 006857 | Alice | Timo | 1982-02-20 00:00:00.0000000 |
| 3001 | 006594 | Tom | Zigo | 1981-03-21 00:00:00.0000000 |
| 4020 | 007263 | Alice | Bilani | 1973-04-03 00:00:00.0000000 |
一个人可以关联多个事件
查询是:
Select
[UC_Number] = A.UCNumber,
[Name] = ltrim(rtrim(A.FirstName + ' ' + A.LastName)),
[Stat_Code] = case
when A.Id in (select P.Id from db.dbo.Person as P
cross apply
(select top 1 id, Name, DateEvent, EventTypeId
from db.dbo.Event
where PersonId = P.Id and EventTypeId not in (8, 14, 17)
order by DateEvent desc) le
where le.EventTypeId = 5) then 'AR'
when A.Id in (select P.Id from db.dbo.Person as P
cross apply
(select top 1 id, Name, DateEvent, EventTypeId
from db.dbo.Event
where PersonId = P.Id and EventTypeId not in (8, 14, 17)
order by DateEvent desc) le
where le.EventTypeId = 4) then 'AW'
when A.DateB is not null then 'ABC'
when A.Id in (select P.Id from db.dbo.Person as P
cross apply
(select top 1 id, Name, DateEvent, EventTypeId
from db.dbo.Event
where PersonId = P.Id and EventTypeId not in (8, 14, 17)
order by DateEvent desc) as le
where le.EventTypeId = 15) then 'AT'
when A.Id in (select P.Id from db.dbo.Person as P
cross apply
(select top 1 id, Name, DateEvent, EventTypeId
from db.dbo.Event
where PersonId = P.Id and EventTypeId not in (8, 14, 17)
order by DateEvent desc) le
where le.EventTypeId = 6) then 'ASPEC'
when A.Id in (select P.Id from db.dbo.Person as P
cross apply
(select top 1 id, Name, DateEvent, EventTypeId
from db.dbo.Event
where PersonId = P.Id and EventTypeId not in (8, 14, 17)
order by DateEvent desc) le
left join db.dbo.Address B on P.AddressResidenceId = B.Id
where le.EventTypeId = 3 and B.PostCode is null) then 'AK'
else 'OK'
end,
[Status] = case
when A.Id in (select P.Id from db.dbo.Person as P
cross apply
(select top 1 id, Name, DateEvent, EventTypeId
from db.dbo.Event
where PersonId = P.Id and EventTypeId not in (8, 14, 17)
order by DateEvent desc) le
where le.EventTypeId = 4) then 'OtherD'
when A.Id in (select P.Id from db.dbo.Person as P
cross apply
(select top 1 id, Name, DateEvent, EventTypeId
from db.dbo.Event
where PersonId = P.Id and EventTypeId not in (8, 14, 17)
order by DateEvent desc) as le
where le.EventTypeId = 6) then 'OtherE'
when A.Id in (select P.Id from db.dbo.Person as P
cross apply
(select top 1 id, Name, DateEvent, EventTypeId
from db.dbo.Event
where PersonId = P.Id and EventTypeId not in (8, 14, 17)
order by DateEvent desc) le
left join db.dbo.Address B on P.AddressResidenceId = B.Id
where le.EventTypeId = 3 and B.PostCode is null) then 'OtherW'
when A.Id in (select P.Id from db.dbo.Person as P
cross apply
(select top 1 id, Name, DateEvent, EventTypeId
from db.dbo.Event
where PersonId = P.Id and EventTypeId not in (8, 14, 17)
order by DateEvent desc) as le
where le.EventTypeId = 15) then 'OtherB'
else 'NO'
End
From db.dbo.Person A ...
left join Address B on A.AddressResidenceId = B.Id
...
预期结果:
+-----------+--------------+-----------+--------+
| UC_Number | Name | Stat_Code | Status |
+-----------+--------------+-----------+--------+
| 004947 | John Smith | AT | OtherB |
+-----------+--------------+-----------+--------+
| 006857 | Alice Timo | ASPEC | OtherE |
+-----------+--------------+-----------+--------+
| 006594 | Tom Zigo | AK | OtherW |
+-----------+--------------+-----------+--------+
| 007263 | Alice Bilani | AK | OtherW |
+-----------+--------------+-----------+--------+
如果您选中状态列,我将重复使用相同的子查询。是否有其他方法使脚本部分不重复?这是对我的评论的扩展。您可以通过将IN切换到EXISTS来提高性能。在每次检查现有行时,使用IN返回整个子查询 我不完全理解您的数据,因此您需要仔细检查我的逻辑,但下面是一个如何完成此更改的示例:
SELECT
[Stat_Code] = CASE
WHEN A.Birth IS NOT NULL THEN 'BD'
WHEN EXISTS (
SELECT * FROM db.dbo.Person AS P
CROSS APPLY (
SELECT TOP 1 id, Name, DateEvent, EventTypeId FROM db.dbo.Event
WHERE
PersonId = P.Id
AND EventTypeId NOT IN ( 8, 14, 17 )
ORDER BY DateEvent DESC
) AS le
WHERE
P.Id = A.ID -- A.ID comparison happens here instead of looking for IN.
AND le.EventTypeId = 5
) THEN 'AR'
...
假设您询问的是避免代码重复而不是提高性能 SQLServer非常擅长展开内联表值函数,并将它们的主体放在调用查询中 您很可能能够做到: 创建函数dbo。HelpfulNameHere@EventTypeIdint 返回表 像 回来 选择 P.Id,P.AddressResidenceId,le.EventId,le.EventName,le.DateEvent 从…起 db.dbo.Person作为P 交叉应用选择前1个id作为EventId,名称作为EventName,DateEvent,EventTypeId 从db.dbo.Event 其中PersonId=P.Id,EventTypeId不在8、14、17中 按日期事件描述排序 哪里 le.EventTypeId=@EventTypeId ; 选择 [统计代码]=案例 当A.Id在中时,从dbo.helpfulnamehere中选择P.Id 5 P,然后选择“AR” 当A.Id在中时,从dbo.helpfulnamehere中选择P.Id 4 P,然后选择“AW” 当A.DateB不为空时,则为“ABC” 当A.Id在中时,请从dbo.helpfulnamehere中选择P.Id 15 P,然后选择“AT” 当A.Id在中时,从dbo.helpfulnamehere中选择P.Id 6 P,然后选择“ASPEC” 当A.Id在选择P.Id时 来自dbo.helpfulnamehere 3 P 左连接P.AddressResidence=B.Id上的db.dbo.Address B 如果B.邮政编码为空,则为“AK” 还有“好的” 终止 [状态]=案例 当A.Id在中时,从dbo.helpfulnamehere中选择P.Id 4 P,然后选择“OtherD” 当A.Id在中时,从dbo.helpfulname中选择P.Id,然后选择“OtherB” ...
性能应该相同。CASE Expression,SQL Server不支持CASE Switch语句。您不能在SELECT中引用子查询,否则在SELECT中,您必须重复它。然而,事实上,似乎您应该在您的“从这里开始”中使用连接或应用程序。可能您应该看看条件聚合。如果没有样本数据和预期的结果,很难了解。没有发布其他WHEN语句,这些语句是上述子查询的重复。示例数据和预期结果如何?可以提高性能的一个地方是将INs切换为EXISTS,这样SQL Server不会每次都回拉整个子查询。我稍微更改了查询,以便预期结果有意义..哇,谢谢分享@GSerg。虽然这里没有提到SQL Server的版本,但我仍然坚持更正…谢谢。我正在使用SQL Server 2008谢谢。非常有用。但我们倾向于不使用功能和SP进行维护。