Tsql 需要T-SQL Pivot帮助(我认为)

Tsql 需要T-SQL Pivot帮助(我认为),tsql,pivot,unpivot,Tsql,Pivot,Unpivot,我希望从表中的1行中获取值,作为查询中的列名,其中列的数据来自第二个表。我认为这可以通过一个支点来实现,但我在努力解决这个问题上一事无成 具体而言,我们希望记录患者不同抗原的抗体水平。 每名患者将监测的实际抗原不同。 因此,我们有一个记录将被监测的抗原的表格,该表格称为reftblDSAColumnLabels。正如您在示例中看到的,有两行用于不同的人,由PersonCategoryId标识。此表对PersonCategoryId具有唯一的约束 (该表实际上最多有“Antigen12Label”

我希望从表中的1行中获取值,作为查询中的列名,其中列的数据来自第二个表。我认为这可以通过一个支点来实现,但我在努力解决这个问题上一事无成

具体而言,我们希望记录患者不同抗原的抗体水平。 每名患者将监测的实际抗原不同。 因此,我们有一个记录将被监测的抗原的表格,该表格称为reftblDSAColumnLabels。正如您在示例中看到的,有两行用于不同的人,由PersonCategoryId标识。此表对PersonCategoryId具有唯一的约束

(该表实际上最多有“Antigen12Label”,因此每个患者最多可以监测12种不同的抗原的抗体水平,但我在这里对其进行了简化)

包含数据的表格称为tblDSAData,您可以在下面看到PersonCategoryId=1的患者的一些代表行

我想要实现的是一个输出,它具有以下列标题,其中PersonCategoryId=1

PersonCategoryIdSampleDateA1Cw6DR15DR51

这里PersonCategoryId=2

个人类别样本A2A3B7B9


我觉得这应该相当容易,但我似乎有一个关于PIVOT的思维障碍,我看到的部分问题是,有两个表是非标准化的,这意味着基本上有两个表是设计为电子表格而不是表格的。这个问题的最佳解决方案是重新构造表

如果可能,我的建议是将表结构更改为以下内容:

CREATE TABLE reftblDSAColumnLabels
(
  [PersonCategoryId] int, 
  [AntigenNum] int, 
  [AntigenValue] varchar(4)
);

CREATE TABLE tblDSAData 
(
  [PersonCategoryId] int, 
  [SampleDate] datetime,
  [AntigenNum] int, 
  [AntigenValue] int
);
select personCategoryId, 
  replace(replace(col, 'Antigen', ''), 'Label', '') colNum,
  value l_value
from reftblDSAColumnLabels
unpivot
(
  value
  for col in ([Antigen1Label], [Antigen2Label], [Antigen3Label], [Antigen4Label])
) unpiv
where PersonCategoryId = 1;
通过这种方式,您可以将
personCategoryId
AntigenNum
(1、2、3等)上的表连接起来。你马上就会明白我为什么提出这个建议

由于您的表是非规范化的,因此很难通过传入
personCategoryId
动态生成结果集。您需要使用动态SQL根据提交给过程的id生成结果

为了得到这个结果,我建议同时应用UNPIVOT和PIVOT函数。UNPIVOT将获取多列中的表,并将它们转换为我上面建议的结构。这将使获得结果更加容易

UNPIVOT:

您需要取消PIVOT两个表,取消PIVOT的查询将类似于以下内容:

CREATE TABLE reftblDSAColumnLabels
(
  [PersonCategoryId] int, 
  [AntigenNum] int, 
  [AntigenValue] varchar(4)
);

CREATE TABLE tblDSAData 
(
  [PersonCategoryId] int, 
  [SampleDate] datetime,
  [AntigenNum] int, 
  [AntigenValue] int
);
select personCategoryId, 
  replace(replace(col, 'Antigen', ''), 'Label', '') colNum,
  value l_value
from reftblDSAColumnLabels
unpivot
(
  value
  for col in ([Antigen1Label], [Antigen2Label], [Antigen3Label], [Antigen4Label])
) unpiv
where PersonCategoryId = 1;

看。如果您运行这些查询,您会注意到您会得到与以下类似的结果:

| PERSONCATEGORYID | COLNUM | L_VALUE |
---------------------------------------
|                1 |      1 |      A1 |
|                1 |      2 |     Cw6 |
|                1 |      3 |    DR15 |
|                1 |      4 |    DR51 |

支点

一旦此数据采用这种多行格式,您就可以轻松地将
personCategoryId
colNum
上的结果合并在一起,并应用PIVOT函数来获得最终结果。带有连接和轴的代码将为:

select *
from
(
  select l.personCategoryId, l_value, d_value, SampleDate
  from
  (
    select personCategoryId, 
      replace(replace(col, 'Antigen', ''), 'Label', '') colNum,
      value l_value
    from reftblDSAColumnLabels
    unpivot
    (
      value
      for col in ([Antigen1Label], [Antigen2Label], [Antigen3Label], [Antigen4Label])
    ) unpiv
    where PersonCategoryId = 1
  ) l
  inner join
  (
    select personCategoryId,SampleDate,
      replace(replace(col, 'Antigen', ''), 'Value', '') colNum,
      value d_value
    from tblDSAData
    unpivot
    (
      value
      for col in ([Antigen1Value], [Antigen2Value], [Antigen3Value], [Antigen4Value])
    ) unpiv
  ) d
    on l.PersonCategoryId = d.PersonCategoryId
    and l.colNum = d.colNum
) src
pivot
(
  max(d_value)
  for l_value in (A1, Cw6, DR15, DR51)
) piv;

现在针对您当前的问题,您需要传入
personCategoryId
,这样每个id的列标题都会发生变化。由于列标题会发生变化,您需要使用动态SQL来获得结果。您可以轻松地将上述代码转换为动态SQL,脚本如下:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @personCategoryId int = 1

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(value) 
                    from
                    (
                      select value
                      from reftblDSAColumnLabels
                      unpivot
                      (
                        value
                        for col in ([Antigen1Label], [Antigen2Label], [Antigen3Label], [Antigen4Label])
                      ) unpiv
                      where PersonCategoryId = @personCategoryId
                    ) d
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT personCategoryId, SampleDate,' + @cols + '  
             from
              (
                select l.personCategoryId, l_value, d_value, SampleDate
                from
                (
                  select personCategoryId, 
                    replace(replace(col, ''Antigen'', ''''), ''Label'', '''') colNum,
                    value l_value
                  from reftblDSAColumnLabels
                  unpivot
                  (
                    value
                    for col in ([Antigen1Label], [Antigen2Label], [Antigen3Label], [Antigen4Label])
                  ) unpiv
                  where PersonCategoryId = '+cast(@personCategoryId as varchar(10))+'
                ) l
                inner join
                (
                  select personCategoryId,SampleDate,
                    replace(replace(col, ''Antigen'', ''''), ''Value'', '''') colNum,
                    value d_value
                  from tblDSAData
                  unpivot
                  (
                    value
                    for col in ([Antigen1Value], [Antigen2Value], [Antigen3Value], [Antigen4Value])
                  ) unpiv
                ) d
                  on l.PersonCategoryId = d.PersonCategoryId
                  and l.colNum = d.colNum
            ) src
            pivot 
            (
                max(d_value)
                for l_value in (' + @cols + ')
            ) p '


execute(@query)
看。所有版本将给出一个结果:

| PERSONCATEGORYID | SAMPLEDATE |   A1 |   CW6 |  DR15 | DR51 |
---------------------------------------------------------------
|                1 | 2013-02-08 | 1278 | 11272 |  6880 | 7544 |
|                1 | 2013-02-11 | 1711 |  9681 |  8437 | 8967 |
|                1 | 2013-02-13 | 2107 | 11516 |  8958 | 7884 |
|                1 | 2013-02-15 | 1947 | 13857 | 10352 | 8719 |
|                1 | 2013-02-18 | 1917 | 10026 |  9848 | 8493 |
编辑#1,如果要规范化这两个表,您仍然必须使用动态SQL获取每个
personCategoryId
的列标题,但是您可以删除这两个表的unpivot。守则如下:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @personCategoryId int = 1

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(AntigenValue) 
                    from reftblDSAColumnLabels
                    where PersonCategoryId = @personCategoryId
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT personCategoryId, SampleDate,' + @cols + '  
             from
              (
                select l.personCategoryId, d.SampleDate,
                    l.AntigenValue l_value, d.AntigenValue d_value
                from reftblDSAColumnLabels l
                inner join tblDSAData d
                  on l.PersonCategoryId = d.PersonCategoryId
                  and l.AntigenNum = d.AntigenNum
            ) src
            pivot 
            (
                max(d_value)
                for l_value in (' + @cols + ')
            ) p '


execute(@query)

请看

我看到的部分问题是,有两个表是非标准化的,这意味着基本上有两个表是设计为电子表格而不是表格的。这个问题的最佳解决方案是重新构造表

如果可能,我的建议是将表结构更改为以下内容:

CREATE TABLE reftblDSAColumnLabels
(
  [PersonCategoryId] int, 
  [AntigenNum] int, 
  [AntigenValue] varchar(4)
);

CREATE TABLE tblDSAData 
(
  [PersonCategoryId] int, 
  [SampleDate] datetime,
  [AntigenNum] int, 
  [AntigenValue] int
);
select personCategoryId, 
  replace(replace(col, 'Antigen', ''), 'Label', '') colNum,
  value l_value
from reftblDSAColumnLabels
unpivot
(
  value
  for col in ([Antigen1Label], [Antigen2Label], [Antigen3Label], [Antigen4Label])
) unpiv
where PersonCategoryId = 1;
通过这种方式,您可以将
personCategoryId
AntigenNum
(1、2、3等)上的表连接起来。你马上就会明白我为什么提出这个建议

由于您的表是非规范化的,因此很难通过传入
personCategoryId
动态生成结果集。您需要使用动态SQL根据提交给过程的id生成结果

为了得到这个结果,我建议同时应用UNPIVOT和PIVOT函数。UNPIVOT将获取多列中的表,并将它们转换为我上面建议的结构。这将使获得结果更加容易

UNPIVOT:

您需要取消PIVOT两个表,取消PIVOT的查询将类似于以下内容:

CREATE TABLE reftblDSAColumnLabels
(
  [PersonCategoryId] int, 
  [AntigenNum] int, 
  [AntigenValue] varchar(4)
);

CREATE TABLE tblDSAData 
(
  [PersonCategoryId] int, 
  [SampleDate] datetime,
  [AntigenNum] int, 
  [AntigenValue] int
);
select personCategoryId, 
  replace(replace(col, 'Antigen', ''), 'Label', '') colNum,
  value l_value
from reftblDSAColumnLabels
unpivot
(
  value
  for col in ([Antigen1Label], [Antigen2Label], [Antigen3Label], [Antigen4Label])
) unpiv
where PersonCategoryId = 1;

看。如果您运行这些查询,您会注意到您会得到与以下类似的结果:

| PERSONCATEGORYID | COLNUM | L_VALUE |
---------------------------------------
|                1 |      1 |      A1 |
|                1 |      2 |     Cw6 |
|                1 |      3 |    DR15 |
|                1 |      4 |    DR51 |

支点

一旦此数据采用这种多行格式,您就可以轻松地将
personCategoryId
colNum
上的结果合并在一起,并应用PIVOT函数来获得最终结果。带有连接和轴的代码将为:

select *
from
(
  select l.personCategoryId, l_value, d_value, SampleDate
  from
  (
    select personCategoryId, 
      replace(replace(col, 'Antigen', ''), 'Label', '') colNum,
      value l_value
    from reftblDSAColumnLabels
    unpivot
    (
      value
      for col in ([Antigen1Label], [Antigen2Label], [Antigen3Label], [Antigen4Label])
    ) unpiv
    where PersonCategoryId = 1
  ) l
  inner join
  (
    select personCategoryId,SampleDate,
      replace(replace(col, 'Antigen', ''), 'Value', '') colNum,
      value d_value
    from tblDSAData
    unpivot
    (
      value
      for col in ([Antigen1Value], [Antigen2Value], [Antigen3Value], [Antigen4Value])
    ) unpiv
  ) d
    on l.PersonCategoryId = d.PersonCategoryId
    and l.colNum = d.colNum
) src
pivot
(
  max(d_value)
  for l_value in (A1, Cw6, DR15, DR51)
) piv;

现在针对您当前的问题,您需要传入
personCategoryId
,这样每个id的列标题都会发生变化。由于列标题会发生变化,您需要使用动态SQL来获得结果。您可以轻松地将上述代码转换为动态SQL,脚本如下:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @personCategoryId int = 1

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(value) 
                    from
                    (
                      select value
                      from reftblDSAColumnLabels
                      unpivot
                      (
                        value
                        for col in ([Antigen1Label], [Antigen2Label], [Antigen3Label], [Antigen4Label])
                      ) unpiv
                      where PersonCategoryId = @personCategoryId
                    ) d
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT personCategoryId, SampleDate,' + @cols + '  
             from
              (
                select l.personCategoryId, l_value, d_value, SampleDate
                from
                (
                  select personCategoryId, 
                    replace(replace(col, ''Antigen'', ''''), ''Label'', '''') colNum,
                    value l_value
                  from reftblDSAColumnLabels
                  unpivot
                  (
                    value
                    for col in ([Antigen1Label], [Antigen2Label], [Antigen3Label], [Antigen4Label])
                  ) unpiv
                  where PersonCategoryId = '+cast(@personCategoryId as varchar(10))+'
                ) l
                inner join
                (
                  select personCategoryId,SampleDate,
                    replace(replace(col, ''Antigen'', ''''), ''Value'', '''') colNum,
                    value d_value
                  from tblDSAData
                  unpivot
                  (
                    value
                    for col in ([Antigen1Value], [Antigen2Value], [Antigen3Value], [Antigen4Value])
                  ) unpiv
                ) d
                  on l.PersonCategoryId = d.PersonCategoryId
                  and l.colNum = d.colNum
            ) src
            pivot 
            (
                max(d_value)
                for l_value in (' + @cols + ')
            ) p '


execute(@query)
看。所有版本将给出一个结果:

| PERSONCATEGORYID | SAMPLEDATE |   A1 |   CW6 |  DR15 | DR51 |
---------------------------------------------------------------
|                1 | 2013-02-08 | 1278 | 11272 |  6880 | 7544 |
|                1 | 2013-02-11 | 1711 |  9681 |  8437 | 8967 |
|                1 | 2013-02-13 | 2107 | 11516 |  8958 | 7884 |
|                1 | 2013-02-15 | 1947 | 13857 | 10352 | 8719 |
|                1 | 2013-02-18 | 1917 | 10026 |  9848 | 8493 |
编辑#1,如果要规范化这两个表,您仍然必须使用动态SQL获取每个
personCategoryId
的列标题,但是您可以删除这两个表的unpivot。守则如下:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @personCategoryId int = 1

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(AntigenValue) 
                    from reftblDSAColumnLabels
                    where PersonCategoryId = @personCategoryId
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT personCategoryId, SampleDate,' + @cols + '  
             from
              (
                select l.personCategoryId, d.SampleDate,
                    l.AntigenValue l_value, d.AntigenValue d_value
                from reftblDSAColumnLabels l
                inner join tblDSAData d
                  on l.PersonCategoryId = d.PersonCategoryId
                  and l.AntigenNum = d.AntigenNum
            ) src
            pivot 
            (
                max(d_value)
                for l_value in (' + @cols + ')
            ) p '


execute(@query)

请参见

是否希望这是一个动态解决方案?在此处输入
personCategoryId
和列