Sql 选择查询中的查找和条件联接

Sql 选择查询中的查找和条件联接,sql,sql-server,join,if-statement,Sql,Sql Server,Join,If Statement,我有一个包含三条患者信息的表格 Diagnosis_ID Patient_ID Diagnosis_Code ==================================================== 1 Jenkins, Sam A743 2 Smith, Fred D638 3 Doe, John

我有一个包含三条患者信息的表格

Diagnosis_ID      Patient_ID        Diagnosis_Code
====================================================
1                 Jenkins, Sam          A743
2                 Smith, Fred           D638
3                 Doe, John             G732
我想查询此表,但还要添加第三列“诊断说明”,该列链接到另一个表中的诊断代码

Diagnosis_ID      Patient_ID        Diagnosis_Code     Diagnosis_Description
=============================================================================
1                 Jenkins, Sam          A743             Sleep Apnea
2                 Smith, Fred           D638             High Blood Pressure
3                 Doe, John             G732             Dislocated Joint
通常情况下,我可以加入将诊断代码与诊断描述联系起来的表,我很乐意加入。然而,这并不是那么容易。诊断描述值位于三个可能的表格之一。确定我需要加入哪个表取决于诊断ID是什么

所以我现在要做的是,对于每个诊断ID,我必须查询另一个表,根据诊断级别,告诉我需要在哪个表上加入诊断代码,然后一旦我有了诊断ID,我就可以得到诊断描述。下面是一些伪代码,我希望它们能描述这个过程

SELECT DiagnosisLevel FROM DiagnosisDetail WHERE Diagnosis_ID = 1

If DiagnosisLevel = "DiagnosisTable1" Then
  SELECT Diagnosis_Description FROM DiagnosisTable1 WHERE Diagnosis_Code = 'A743'
ElseIf DiagnosisLevel = "DiagnosisTable2" Then
  SELECT Diagnosis_Description FROM DiagnosisTable2 WHERE Diagnosis_Code = 'A743'
ElseIf
  SELECT Diagnosis_Description FROM DiagnosisTable3 WHERE Diagnosis_Code = 'A743'
End If
我不知道如何在SQL中完成这一切。这是可能的,还是我必须用代码I.e.C来完成这一切


我道歉,如果这似乎含糊不清。我尽了最大努力创建了一个简单的示例来演示这个问题。我没有设计这个数据库,但必须在它的结构内工作。

实际上,您已经非常接近了

在您的选择中,只需执行此操作

Select 
    Diagnosis_ID,
    Patient_ID,
    Diagnosis_Code,
    (Case
     When Level.DiagnosisLevel = "DiagnosisTable1" Then
        SELECT Diagnosis_Description FROM DiagnosisTable1 
     When Level.DiagnosisLevel = "DiagnosisTable2" Then
        SELECT Diagnosis_Description FROM DiagnosisTable2 
     When Level.DiagnosisLebel = "DiagnosisTable3" Then
     --Or you could just do an Else
        SELECT Diagnosis_Description FROM DiagnosisTable3 
     End) As Diagnosis_Description
    From MainTable
    Join TableThatHasLevels As Level ON Level.Diagnosis_Code = Diagnosis_Code

您应该能够加入获取诊断表信息的查询,并这样做

您实际上已经非常接近了

在您的选择中,只需执行此操作

Select 
    Diagnosis_ID,
    Patient_ID,
    Diagnosis_Code,
    (Case
     When Level.DiagnosisLevel = "DiagnosisTable1" Then
        SELECT Diagnosis_Description FROM DiagnosisTable1 
     When Level.DiagnosisLevel = "DiagnosisTable2" Then
        SELECT Diagnosis_Description FROM DiagnosisTable2 
     When Level.DiagnosisLebel = "DiagnosisTable3" Then
     --Or you could just do an Else
        SELECT Diagnosis_Description FROM DiagnosisTable3 
     End) As Diagnosis_Description
    From MainTable
    Join TableThatHasLevels As Level ON Level.Diagnosis_Code = Diagnosis_Code

您应该只能够加入获取诊断表信息的查询,并执行多个左联接?对于主表中的每一行,这将选择适当的左连接到正确的诊断表

SELECT
    T.*, 
    COALESCE(D1.Diagnosis_Description, D2.Diagnosis_Description, D3.Diagnosis_Description)
FROM 
    MyTable T
    LEFT JOIN
    DiagnosisTable1 D1 ON T.Diagnosis_Code = D1.Diagnosis_Code
                   AND T.DiagnosisLevel = 'DiagnosisTable1'
    LEFT JOIN
    DiagnosisTable2 D2 ON T.Diagnosis_Code = D2.Diagnosis_Code
                   AND T.DiagnosisLevel = 'DiagnosisTable2'
    LEFT JOIN
    DiagnosisTable3 D3 ON T.Diagnosis_Code = D3.Diagnosis_Code
                   AND T.DiagnosisLevel = 'DiagnosisTable3'

多个左连接?对于主表中的每一行,这将选择适当的左连接到正确的诊断表

SELECT
    T.*, 
    COALESCE(D1.Diagnosis_Description, D2.Diagnosis_Description, D3.Diagnosis_Description)
FROM 
    MyTable T
    LEFT JOIN
    DiagnosisTable1 D1 ON T.Diagnosis_Code = D1.Diagnosis_Code
                   AND T.DiagnosisLevel = 'DiagnosisTable1'
    LEFT JOIN
    DiagnosisTable2 D2 ON T.Diagnosis_Code = D2.Diagnosis_Code
                   AND T.DiagnosisLevel = 'DiagnosisTable2'
    LEFT JOIN
    DiagnosisTable3 D3 ON T.Diagnosis_Code = D3.Diagnosis_Code
                   AND T.DiagnosisLevel = 'DiagnosisTable3'

让我们打电话给您的第一个诊断表。有两种方法,如果诊断代码只出现在三个诊断表中的一个表中,我将采用第一种方法

select
  aa.Diagnosis_ID,
  aa.Patient_ID,
  aa.Diagnosis_Code,
  coalesce(bb.Diagnosis_Description,    cc.Diagnosis_Description,  
    dd.Diagnosis_Description)     as    Diagnosis_Description
from
  patient_diagnosis as aa
left join
  DiagnosisTable1 as bb on aa.Diagnosis_Code = bb.Diagnosis_Code
left join
  DiagnosisTable2 as cc on aa.Diagnosis_Code = cc.Diagnosis_Code
left join
  DiagnosisTable3 as dd on aa.Diagnosis_Code = dd.Diagnosis_Code
第二个类似,但实际上使用查找表

select
  aa.Diagnosis_ID,
  aa.Patient_ID,
  aa.Diagnosis_Code,
  case when ee.Diagnosis_Level = 1 then bb.Diagnosis_Description
  when ee.Diagnosis_Level = 2 then cc.Diagnosis_Description
  when ee.Diagnosis_Level = 3 then dd.Diagnosis_Description
  else 'Error' end as    Diagnosis_Description
from
  patient_diagnosis as aa
left join
  DiagnosisTable1 as bb on aa.Diagnosis_Code = bb.Diagnosis_Code
left join
  DiagnosisTable2 as cc on aa.Diagnosis_Code = cc.Diagnosis_Code
left join
  DiagnosisTable3 as dd on aa.Diagnosis_Code = dd.Diagnosis_Code
join
  DiagnosisDetail as ee on aa.Diagnosis_ID = ee.Diagnosis_ID

让我们打电话给您的第一个诊断表。有两种方法,如果诊断代码只出现在三个诊断表中的一个表中,我将采用第一种方法

select
  aa.Diagnosis_ID,
  aa.Patient_ID,
  aa.Diagnosis_Code,
  coalesce(bb.Diagnosis_Description,    cc.Diagnosis_Description,  
    dd.Diagnosis_Description)     as    Diagnosis_Description
from
  patient_diagnosis as aa
left join
  DiagnosisTable1 as bb on aa.Diagnosis_Code = bb.Diagnosis_Code
left join
  DiagnosisTable2 as cc on aa.Diagnosis_Code = cc.Diagnosis_Code
left join
  DiagnosisTable3 as dd on aa.Diagnosis_Code = dd.Diagnosis_Code
第二个类似,但实际上使用查找表

select
  aa.Diagnosis_ID,
  aa.Patient_ID,
  aa.Diagnosis_Code,
  case when ee.Diagnosis_Level = 1 then bb.Diagnosis_Description
  when ee.Diagnosis_Level = 2 then cc.Diagnosis_Description
  when ee.Diagnosis_Level = 3 then dd.Diagnosis_Description
  else 'Error' end as    Diagnosis_Description
from
  patient_diagnosis as aa
left join
  DiagnosisTable1 as bb on aa.Diagnosis_Code = bb.Diagnosis_Code
left join
  DiagnosisTable2 as cc on aa.Diagnosis_Code = cc.Diagnosis_Code
left join
  DiagnosisTable3 as dd on aa.Diagnosis_Code = dd.Diagnosis_Code
join
  DiagnosisDetail as ee on aa.Diagnosis_ID = ee.Diagnosis_ID

实际上,您可以合并所有3个诊断级别表,然后加入其中。若你们必须有匹配项,那个么将左连接改为内连接,否则左连接并没有什么坏处

SELECT A.Diagnosis_ID, A.Patient_ID, A.Diagnosis_Code, B.Diagnosis_Description
FROM Diagnosis A
left join
(
    SELECT DiagnosisLevel = 'DiagnosisTable1', Diagnosis_Code, Diagnosis_Description
    FROM DiagnosisTable1
    UNION ALL
    SELECT DiagnosisLevel = 'DiagnosisTable2', Diagnosis_Code, Diagnosis_Description
    FROM DiagnosisTable2
    UNION ALL
    SELECT DiagnosisLevel = 'DiagnosisTable3', Diagnosis_Code, Diagnosis_Description
    FROM DiagnosisTable3
) B on A.Diagnosis_Level = B.DiagnosisLevel and A.Diagnosis_Code = B.Diagnosis_Code
虽然这看起来像是一个昂贵的操作,但实际上非常有效。带有拆分器列DiagnosisLevel的UNIONALL表单是一种分区策略,SQL Server仅使用它从需要查看的表中进行选择。例如,这里有一个测试

create table Diagnosis(
    Diagnosis_ID int primary key, 
    Patient_ID varchar(100), 
    Diagnosis_Code varchar(10), 
    Diagnosis_Level varchar(100))
insert Diagnosis select
    '1' ,'Jenkins, Sam' ,'A743','DiagnosisTable1' union all select
    '2' ,'Smith, Fred' ,'D638','DiagnosisTable2' union all select
    '3' ,'Doe, John' ,'G732','DiagnosisTable3'
create table DiagnosisTable1(id int identity primary key,Diagnosis_Code varchar(10),Diagnosis_Description varchar(100))
create index ix_DiagnosisTable1 on DiagnosisTable1(Diagnosis_Code) include (Diagnosis_Description)
insert DiagnosisTable1 select
    'A748', 'Sleep Apnea 1' union all select
    'A745', 'Sleep Apnea 2' union all select
    'A746', 'Sleep Apnea 3' union all select
    'A743', 'Sleep Apnea'
insert DiagnosisTable1 select top 1000
    Diagnosis_Code + left(CONVERT(varchar(max), newid()),3),
    Diagnosis_Description + CONVERT(varchar(max), newid())
from DiagnosisTable1 cross join master..spt_values
create table DiagnosisTable2(id int identity primary key,Diagnosis_Code varchar(10),Diagnosis_Description varchar(100))
create index ix_DiagnosisTable2 on DiagnosisTable2(Diagnosis_Code) include (Diagnosis_Description)
insert DiagnosisTable2 select
    'D6381', 'High Blood Pressure 1' union all select
    'D638', 'High Blood Pressure 3' union all select
    'D6384', 'High Blood Pressure'
insert DiagnosisTable2 select top 1000
    Diagnosis_Code + left(CONVERT(varchar(max), newid()),3),
    Diagnosis_Description + CONVERT(varchar(max), newid())
from DiagnosisTable2 cross join master..spt_values
create table DiagnosisTable3(id int identity primary key,Diagnosis_Code varchar(10),Diagnosis_Description varchar(100))
create index ix_DiagnosisTable3 on DiagnosisTable3(Diagnosis_Code) include (Diagnosis_Description)
insert DiagnosisTable3 select
    'G732', 'HDislocated Jointe 1' union all select
    'D6X8', 'HDislocated Joint 3' union all select
    'GGG84', 'Dislocated Joint'
insert DiagnosisTable3 select top 1000
    Diagnosis_Code + left(CONVERT(varchar(max), newid()),3),
    Diagnosis_Description + CONVERT(varchar(max), newid())
from DiagnosisTable3 cross join master..spt_values

==========
Summary
==========
3x diagnosis records
4000, 3000 and 3000 records in each of the level 1,2,3 tables
查询从上面重复

SELECT A.Diagnosis_ID, A.Patient_ID, A.Diagnosis_Code, B.Diagnosis_Description
FROM Diagnosis A
left join
(
    SELECT DiagnosisLevel = 'DiagnosisTable1', Diagnosis_Code, Diagnosis_Description
    FROM DiagnosisTable1
    UNION ALL
    SELECT DiagnosisLevel = 'DiagnosisTable2', Diagnosis_Code, Diagnosis_Description
    FROM DiagnosisTable2
    UNION ALL
    SELECT DiagnosisLevel = 'DiagnosisTable3', Diagnosis_Code, Diagnosis_Description
    FROM DiagnosisTable3
) B on A.Diagnosis_Level = B.DiagnosisLevel and A.Diagnosis_Code = B.Diagnosis_Code
执行计划


您可以虚拟地合并所有3个诊断级别表,然后加入其中。若你们必须有匹配项,那个么将左连接改为内连接,否则左连接并没有什么坏处

SELECT A.Diagnosis_ID, A.Patient_ID, A.Diagnosis_Code, B.Diagnosis_Description
FROM Diagnosis A
left join
(
    SELECT DiagnosisLevel = 'DiagnosisTable1', Diagnosis_Code, Diagnosis_Description
    FROM DiagnosisTable1
    UNION ALL
    SELECT DiagnosisLevel = 'DiagnosisTable2', Diagnosis_Code, Diagnosis_Description
    FROM DiagnosisTable2
    UNION ALL
    SELECT DiagnosisLevel = 'DiagnosisTable3', Diagnosis_Code, Diagnosis_Description
    FROM DiagnosisTable3
) B on A.Diagnosis_Level = B.DiagnosisLevel and A.Diagnosis_Code = B.Diagnosis_Code
虽然这看起来像是一个昂贵的操作,但实际上非常有效。带有拆分器列DiagnosisLevel的UNIONALL表单是一种分区策略,SQL Server仅使用它从需要查看的表中进行选择。例如,这里有一个测试

create table Diagnosis(
    Diagnosis_ID int primary key, 
    Patient_ID varchar(100), 
    Diagnosis_Code varchar(10), 
    Diagnosis_Level varchar(100))
insert Diagnosis select
    '1' ,'Jenkins, Sam' ,'A743','DiagnosisTable1' union all select
    '2' ,'Smith, Fred' ,'D638','DiagnosisTable2' union all select
    '3' ,'Doe, John' ,'G732','DiagnosisTable3'
create table DiagnosisTable1(id int identity primary key,Diagnosis_Code varchar(10),Diagnosis_Description varchar(100))
create index ix_DiagnosisTable1 on DiagnosisTable1(Diagnosis_Code) include (Diagnosis_Description)
insert DiagnosisTable1 select
    'A748', 'Sleep Apnea 1' union all select
    'A745', 'Sleep Apnea 2' union all select
    'A746', 'Sleep Apnea 3' union all select
    'A743', 'Sleep Apnea'
insert DiagnosisTable1 select top 1000
    Diagnosis_Code + left(CONVERT(varchar(max), newid()),3),
    Diagnosis_Description + CONVERT(varchar(max), newid())
from DiagnosisTable1 cross join master..spt_values
create table DiagnosisTable2(id int identity primary key,Diagnosis_Code varchar(10),Diagnosis_Description varchar(100))
create index ix_DiagnosisTable2 on DiagnosisTable2(Diagnosis_Code) include (Diagnosis_Description)
insert DiagnosisTable2 select
    'D6381', 'High Blood Pressure 1' union all select
    'D638', 'High Blood Pressure 3' union all select
    'D6384', 'High Blood Pressure'
insert DiagnosisTable2 select top 1000
    Diagnosis_Code + left(CONVERT(varchar(max), newid()),3),
    Diagnosis_Description + CONVERT(varchar(max), newid())
from DiagnosisTable2 cross join master..spt_values
create table DiagnosisTable3(id int identity primary key,Diagnosis_Code varchar(10),Diagnosis_Description varchar(100))
create index ix_DiagnosisTable3 on DiagnosisTable3(Diagnosis_Code) include (Diagnosis_Description)
insert DiagnosisTable3 select
    'G732', 'HDislocated Jointe 1' union all select
    'D6X8', 'HDislocated Joint 3' union all select
    'GGG84', 'Dislocated Joint'
insert DiagnosisTable3 select top 1000
    Diagnosis_Code + left(CONVERT(varchar(max), newid()),3),
    Diagnosis_Description + CONVERT(varchar(max), newid())
from DiagnosisTable3 cross join master..spt_values

==========
Summary
==========
3x diagnosis records
4000, 3000 and 3000 records in each of the level 1,2,3 tables
查询从上面重复

SELECT A.Diagnosis_ID, A.Patient_ID, A.Diagnosis_Code, B.Diagnosis_Description
FROM Diagnosis A
left join
(
    SELECT DiagnosisLevel = 'DiagnosisTable1', Diagnosis_Code, Diagnosis_Description
    FROM DiagnosisTable1
    UNION ALL
    SELECT DiagnosisLevel = 'DiagnosisTable2', Diagnosis_Code, Diagnosis_Description
    FROM DiagnosisTable2
    UNION ALL
    SELECT DiagnosisLevel = 'DiagnosisTable3', Diagnosis_Code, Diagnosis_Description
    FROM DiagnosisTable3
) B on A.Diagnosis_Level = B.DiagnosisLevel and A.Diagnosis_Code = B.Diagnosis_Code
执行计划


谢谢您的样品。我想我明白你的意思了,但是,我应该把查找DiagnosisLevel值的SELECT语句放在哪里?另外,我可以用顶级SELECT语句中诊断代码的值替换硬编码的“A743”值吗?@webworm:我会比较两种解决方案的性能。当修复此问题以关联诊断代码时,您会发现它运行得非常糟糕。CASE语句无法执行代码,它返回一个文本值,因此此查询将不会运行。感谢您提供的示例。我想我明白你的意思了,但是,我应该把查找DiagnosisLevel值的SELECT语句放在哪里?另外,我可以用顶级SELECT语句中诊断代码的值替换硬编码的“A743”值吗?@webworm:我会比较两种解决方案的性能。当修复此问题以关联诊断代码时,您会发现它运行得非常糟糕。CASE语句无法执行代码,它会返回一个文本值,因此此查询不会运行。@SQLNEMAGE:视图当然是一个宏,因此除非索引,否则不会添加任何值。但是我们有外部连接…我在考虑分区视图,假设表DDL是可用的,应该可以正常工作identical@SQLmenace:视图当然是一个宏,因此除非索引,否则不会添加任何值。但是我们有外部连接…我在考虑分区视图,假设表DDL是相同的,应该可以正常工作