如果记录存在于A中,则返回记录,否则,如果记录存在于B中,则返回记录,否则返回null

时间:2019-08-20 21:15:07

标签: sql sql-server

我正在尝试用SQL表达这种想法

If record exist in A then return record else if record exist in B return record ELSE NULL

示例:如果有队长,请选择队长,否则请选择队中年龄最大的球员

WITH Captains_CTE (TeamName, PlayerName)
AS (
    SELECT TeamName, PlayerName FROM TeamPlayer WHERE IsCaptain = 1
), 
OldestPlayer_CTE (TeamName, PlayerName)
AS (
    SELECT TeamName, PlayerName FROM TeamPlayer AS tp
    INNER JOIN ( 
        SELECT TeamName, MAX(PlayerAge) AS MaxAge
        FROM TeamPlayer 
        GROUP BY TeamName
    ) AS old ON old.TeamName = tp.TeamName AND old.MaxAge = tp.PlayerAge

)
SELECT  CASE 
            WHEN Captains_CTE.TeamName IS NULL THEN OldestPlayer_CTE.TeamName
            ELSE Captains_CTE.TeamName 
        END AS TeamName,
        CASE 
            WHEN Captains_CTE.PlayerName IS NULL THEN OldestPlayer_CTE.PlayerName
            ELSE Captains_CTE.PlayerName 
        END AS PlayerName
FROM Captains_CTE
FULL OUTER JOIN OldestPlayer_CTE ON Captains_CTE.TeamName = OldestPlayer_CTE.TeamName

我可以通过在A和B上进行外部联接,然后为我想返回的每一列建立一个CASE语句来做到这一点,但是必须有更好的方法。 (是的,我的示例查询对年龄的唯一性做出了一些可怕的假设)

2 个答案:

答案 0 :(得分:1)

使用not exists

select a.*
from a
union all
select b.*
from b
where not exists (select 1 from a where a.? = b.?);  -- "?" is for the column that specifies whether the record exists in A

答案 1 :(得分:1)

您可以使用APPLY进行此操作:

SELECT t.TeamName, coalsesce(captain.PlayerName,'') As Captain
FROM Teams t
OUTER APPLY (
   SELECT TOP 1 PlayerName
   FROM TeamPlayers tp
   WHERE tp.TeamID = t.TeamID
   ORDER BY CASE WHEN tp.IsCaptain = 1 THEN 1 ELSE 2 END,
        PlayerAge DESC
) captain

如果没有Teams表(如果对模式完全没有意义,但应该知道,则为应该),则可以派生一个:

SELECT t.TeamName, coalsesce(captain.PlayerName,'') As Captain
FROM (SELECT DISTINCT TeamName FROM TeamPlayers) t
OUTER APPLY (
   SELECT TOP 1 PlayerName
   FROM TeamPlayers tp
   WHERE tp.TeamName = t.TeamName 
   ORDER BY CASE WHEN tp.IsCaptain = 1 THEN 1 ELSE 2 END,
        PlayerAge DESC
) captain