【问题标题】:SQL Server : left outer joins and return Y or N if a value existsSQL Server:如果存在值,则左外连接并返回 Y 或 N
【发布时间】:2013-08-01 15:49:36
【问题描述】:

我有一个查询,它显示一堆关于人员的信息,以及他们是否曾经存在过一组 dxcode。每一列都是对同一张表中另一组 dxcode 的不同检查:

示例输出:

pid . . . .HTN . . .DM  
123 . . . Y . . . . .N  
456 . . . N . . . . .N  

查询:

select  
    p.pid
    ,CASE WHEN HTN.pid is not null THEN 'Y' ELSE 'N' END AS HTN   
    ,... (other case statements)
from p

left outer join (  
    SELECT dx.pid, max(create_timestamp) as maxdate  
    FROM pdx  
    WHERE pdx.dxcode IN ('401','401.0','401.1','401.9')  
    group by dx.pid  
    ) as HTN on p.pid = HTN.pid

...同一个 pdx 表上的其他连接以查询其他 dx 代码是否存在

我的查询有效,但我认为它没有达到应有的效率。我真的不需要 maxdate 来做任何事情,但它确实有效。在此之前,我使用的是 select distinct person,但意识到它必须做多少后处理,并且查询性能已经大大提高。对于最佳实践,我认为使用 max 仅返回一个结果的额外计算仍然是不必要的计算。

我尝试使用exists、left join、top 1 1 和case 语句的变体来做同样的事情,但我只是没有正确执行代码。

谢谢。我知道这必须是一个简单的答案。我一直在寻找的术语没有得到我希望的答案。

【问题讨论】:

  • Nice Q - 据我所见,max() 似乎在查询计划中被忽略,因此嵌套选择与SELECT pdx.pid .. GROUP BY pdx.pid 相同。我不能 100% 确定,但我想 SQL 会在发现该人的至少一个诊断后停止评估。

标签: sql-server join unique case max


【解决方案1】:

不确定这是否更有效,但看起来更简单。

SELECT
 p.pid,
 MAX(CASE WHEN pdx.dxcode IN ('401','401.0','401.1','401.9') THEN 'Y' ELSE 'N' END) AS HTN,
 MAX(CASE WHEN pdx.dxcode IN ('501','501.0','501.1','501.9') THEN 'Y' ELSE 'N' END) AS DM,
 MAX(CASE WHEN pdx.dxcode IN ('601') THEN 'Y' ELSE 'N' END) AS XN
FROM p
LEFT OUTER JOIN pdx ON p.pid = pdx.pid
GROUP BY
 p.pid

SQL Fiddle

更新:

如果您希望摆脱 MAX 以使其在第一个正匹配时停止,那么试试这个。

SELECT
 DISTINCT
 p.pid,
 CASE WHEN EXISTS (SELECT 1 FROM pdx WHERE p.pid = pdx.pid AND pdx.dxcode IN ('401','401.0','401.1','401.9')) THEN 'Y' ELSE 'N' END AS HTN,
 CASE WHEN EXISTS (SELECT 1 FROM pdx WHERE p.pid = pdx.pid AND pdx.dxcode IN ('501','501.0','501.1','501.9')) THEN 'Y' ELSE 'N' END AS DM,
 CASE WHEN EXISTS (SELECT 1 FROM pdx WHERE p.pid = pdx.pid AND pdx.dxcode IN ('601')) THEN 'Y' ELSE 'N' END AS XN
FROM p
;

你可以试试这个,它会先得到不同的pid,然后为每个pid找到第一个正匹配。

WITH pd AS (SELECT DISTINCT p.pid FROM p)
SELECT
 pd.pid,
 CASE WHEN EXISTS (SELECT 1 FROM pdx WHERE pd.pid = pdx.pid AND pdx.dxcode IN ('401','401.0','401.1','401.9')) THEN 'Y' ELSE 'N' END AS HTN,
 CASE WHEN EXISTS (SELECT 1 FROM pdx WHERE pd.pid = pdx.pid AND pdx.dxcode IN ('501','501.0','501.1','501.9')) THEN 'Y' ELSE 'N' END AS DM,
 CASE WHEN EXISTS (SELECT 1 FROM pdx WHERE pd.pid = pdx.pid AND pdx.dxcode IN ('601')) THEN 'Y' ELSE 'N' END AS XN
FROM pd 
GROUP BY
 pd.pid
;

SQL Fiddle for those 2

【讨论】:

  • 我们所有 3 个示例的问题是它们使用最大值或总和。必须有一种方法可以做到这一点,而无需对表格进行全面审查。我只假设 top 或 exist 在第一次出现时停止。我喜欢你的设计,因为它绝对更干净。
  • 我更新了我的答案,以包含更多可能有帮助的示例。当然,您必须根据您的数据集对它们进行测试,看看它们的实际表现如何。
  • +1 - 虽然更新后的答案可以简化,假设 p.pid 是主键,由于我们不再在外循环中加入 pdx,因此可以删除 distinct 和 group。在此处更新 SqlFiddle:sqlfiddle.com/#!6/118c8/20 奇怪的是,SqlFiddle 的计划表明这 4 个查询都有相同的查询计划,成本为 0.0144,即除了提高可读性之外,对原始查询没有真正的改进。
【解决方案2】:

也许将您的 CASE 语句更改为 WHEN HTN.pid IS NOT NULL THEN 1 ELSE 0 END 之类的东西,对每个案例求和,然后将最终的 SELECT 包裹在整个事情上?那么,例如,当 HTN > 0 THEN Y ELSE N?

select
    pid,
    case when HTN > 0 then 'Y' else 'N' end AS 'HTN',
    case when DM > 0 then 'Y' else 'N' end AS 'DM',
    case when CBG > 0 then 'Y' else 'N' end AS 'CBG',
    case when XYZ > 0 then 'Y' else 'N' end AS 'XYZ',
    case when DB > 0 then 'Y' else 'N' end AS 'DB'
from (  
        select
            p.pid,
            sum(case when pdx.dxcode in ('409', '409.1', '409.3') then 1 else 0 end) as 'HTN',
            sum(case when pdx.dxcode in ('899', '899.1', '892.2') then 1 else 0 end) as 'DM',
            sum(case when pdx.dxcode in ('410.0', '419.1', '419.3') then 1 else 0 end) as 'CBG',
            sum(case when pdx.dxcode in ('250', '250.1', '250.3') then 1 else 0 end) as 'XYZ',
            sum(case when pdx.dxcode in ('58.0', '58.1', '58.3') then 1 else 0 end) as 'DB'
        from
            person p left join
            pdx on
                p.pid = pdx.pid
        group by p.pid
    ) as dx

【讨论】:

  • 我们所有 3 个示例的问题是它们使用最大值或总和。必须有一种方法可以做到这一点,而无需对表格进行全面审查。我只假设 top 或 exist 在第一次出现时停止。我认为您的会稍微快一些,因为它在处理表格时会对其进行总结,并且不会产生临时表格(猜测)。这很有趣,因为它们都非常有效。我猜你的会快一点。
猜你喜欢
  • 2019-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-15
  • 2014-10-10
  • 2014-09-09
相关资源
最近更新 更多