【问题标题】:SQL one to many on one rowSQL 一对多在一行
【发布时间】:2013-12-11 12:48:25
【问题描述】:

我有一张表格,记录每次就诊的患者诊断情况。患者可以有不止一种诊断。

我希望每个出勤人员在一行中包含所有诊断(最多 12 个诊断)。下面带回不止一行。

select
    dg.AttendanceID
    , dg.PatientNumber
    , dg.DiagnosisDate
    , dg.Diagnosis
from
    Diagnosis dg


AttendanceID    PatientNumber   DiagnosisDate   Diagnosis
10001           123456          01-Oct-13   A
10001           123456          01-Oct-13   B
10002           123456          20-Oct-13   D

结果应该是这样的:

AttendanceID    PatientNumber   DiagnosisDate   Diagnosis 1 Diagnosis 2 Diagnosis 3
10001           123456          01-Oct-13   A            B       
10002           123456          20-Oct-13   D   

有人可以帮忙吗?

【问题讨论】:

  • 我相信 PIVOT 可以在这里完成这项工作?

标签: sql sql-server sql-server-2005 pivot


【解决方案1】:

您可以通过实现 PIVOT 函数来获得结果,但我也建议使用窗口函数row_number() 来生成每个attendanceidpatientnumber 的诊断数:

select attendanceid, patientnumber,
  diagnosisdate,
  Diagnosis1, Diagnosis2, Diagnosis3
from
(
  select attendanceid, patientnumber,
    diagnosisdate, diagnosis,
    'diagnosis'+
      cast(row_number() over(partition by attendanceid, patientnumber
                              order by diagnosis) as varchar(2)) seq
  from diagnosis
) d
pivot
(
  max(diagnosis)
  for seq in (Diagnosis1, Diagnosis2, Diagnosis3)
) piv;

SQL Fiddle with Demo。由于您知道每位患者/就诊最多会有 12 个诊断,因此您可以轻松地对查询进行硬编码以添加其他列。

但如果您需要代码的动态版本,那么您可以使用类似于以下内容的代码:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(seq) 
                    from
                    (
                       select 'diagnosis'+
                          cast(row_number() over(partition by attendanceid, patientnumber
                               order by diagnosis) as varchar(2)) seq
                       from diagnosis
                    ) d
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT attendanceid, patientnumber,
               diagnosisdate,' + @cols + ' 
            from 
            (
              select attendanceid, patientnumber,
                diagnosisdate, diagnosis,
                ''diagnosis''+
                  cast(row_number() over(partition by attendanceid, patientnumber
                                          order by diagnosis) as varchar(2)) seq
              from diagnosis
            ) x
            pivot 
            (
                max(diagnosis)
                for seq in (' + @cols + ')
            ) p '

execute sp_executesql @query;

SQL Fiddle with Demo

两个版本都给出了结果:

| ATTENDANCEID | PATIENTNUMBER |                  DIAGNOSISDATE | DIAGNOSIS1 | DIAGNOSIS2 | DIAGNOSIS3 |
|--------------|---------------|--------------------------------|------------|------------|------------|
|        10001 |        123456 | October, 01 2013 00:00:00+0000 |          A |          B |     (null) |
|        10002 |        123456 | October, 20 2013 00:00:00+0000 |          D |     (null) |     (null) |

【讨论】:

    【解决方案2】:

    我不是 100% 确定,但应该是这样的。

    ;with cte as(
    select
    dg.AttendanceID
    , dg.PatientNumber
    , dg.DiagnosisDate
    , dg.Diagnosis
    ,ROW_NUMBER() over (partition by dg.attendanceID order by attendanceID) as seq1
    ,ROW_NUMBER() over (partition by dg.attendanceID, patient_no order by diagnosis) as seq2
    from
    Diagnosis dg
    )
    
     select
     t1.attendanceID
     ,t1.patientNumber
     ,t1.diagnosisDate
     ,(select Diagnosis from cte t2 where t1.attendanceID=t2.attendanceID and             t1.patientNumber=t2.patientNumber and t2.seq2='1') as diag1
     ,(select Diagnosis from cte t2 where t1.attendanceID=t2.attendanceID and    t1.patientNumber=t2.patientNumber and t2.seq2='2') as diag2
     ,(select Diagnosis from cte t2 where t1.attendanceID=t2.attendanceID and t1.patientNumber=t2.patientNumber and t2.seq2='3') as diag3
     ,(select Diagnosis from cte t2 where t1.attendanceID=t2.attendanceID and t1.patientNumber=t2.patientNumber and t2.seq2='4') as diag4
     ,(select Diagnosis from cte t2 where t1.attendanceID=t2.attendanceID and t1.patientNumber=t2.patientNumber and t2.seq2='5') as diag5
      from cte t1
      where seq1= 1
    

    【讨论】:

    • 你不认为你需要分组吗?
    • 这行得通,但我不明白复杂的语法。谢谢,
    【解决方案3】:

    以下是使用光标的可能解决方案

    DECLARE @combinedString VARCHAR(MAX),
    @id int,
    @Diagnosis VARCHAR(MAX)
    
    
    Declare @CONCATRESULT TABLE (AttendanceID int, Question VARCHAR(MAX) )
    
    Declare Dia cursor for 
    SELECT  AttendanceID FROM  Diagnosis 
    
    open Dia 
    Fetch next from Dia into @id
    while @@FETCH_STATUS=0 
    begin
    
    SELECT   @combinedString = COALESCE(@combinedString + ', ', '') + Diagnosis,         
    @id=AttendanceID  FROM [Prod_PostData].[dbo].[KMSFPostDataDenorm] d
    WHERE AttendanceID = @id
    
    insert into @CONCATRESULT values (  @id ,@combinedString )
    
    SET @combinedString = null
    
    Fetch next from Dia into @id
    end
    close Dia
    deallocate Dia
    
    
    select
    dg.AttendanceID
    , dg.PatientNumber
    , dg.DiagnosisDate
    , dg.Diagnosis
    from
    Diagnosis dg join (select * from @CONCATRESULT) Y on dg.AttendanceID=Y.AttendanceID 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-11
      • 1970-01-01
      • 2013-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多