Sql server 如何在CASE语句中使用CROSS-APPLY重用T-SQL子查询以避免重复

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 +-----

我有一个SELECT查询,在CASE语句中有不同的子查询。 我需要重新使用它们来获取同一个general SELECT中的其他列

两个主要表格是:

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进行维护。