我希望将表中1行的值作为查询中的列名,其中列的数据来自第二个表。我认为这可以通过PIVOT来实现,但我无法尝试解决这个问题
具体而言,我们希望记录患者随时间推移的不同抗原的抗体水平。 每个患者将监测的实际抗原会有所不同。 因此,我们有一个记录将要监控的抗原的表,该表称为reftblDSAColumnLabels。正如您在示例中所看到的,由PersonCategoryId标识的不同人员有两行。此表对PersonCategoryId
具有唯一约束(该表实际上具有'Antigen12Label',因此每位患者最多可以监测12种不同抗原的抗体水平,但我已将其简化了)
包含数据的表名为tblDSAData,您可以在下面看到患者PersonCategoryId = 1的一些代表性行
我想要实现的是具有以下列标题的输出,其中PersonCategoryId = 1
PersonCategoryId SampleDate A1 CW6 DR15 DR51
这是PersonCategoryId = 2
的地方PersonCategoryId SampleDate A2 A3 B7 B9
我觉得它应该相当容易,但我似乎对PIVOT感到心理障碍
答案 0 :(得分:1)
我看到的问题的一部分是你有两个表被去规范化,这意味着你基本上有两个表被设计为电子表格而不是表格。解决这个问题的最佳方法是重组你的表格。
如果可能,我的建议是将表格结构更改为以下内容:
CREATE TABLE reftblDSAColumnLabels
(
[PersonCategoryId] int,
[AntigenNum] int,
[AntigenValue] varchar(4)
);
CREATE TABLE tblDSAData
(
[PersonCategoryId] int,
[SampleDate] datetime,
[AntigenNum] int,
[AntigenValue] int
);
这样您就可以在personCategoryId
和AntigenNum
(1,2,3等)上加入表格。你会明白为什么我会在一分钟内提出这个建议。
由于您的表被去规范化,因此通过传入personCategoryId
来动态生成结果集将非常困难。您将需要使用动态SQL根据提交给过程的id生成结果。
为了得到这个结果,我建议同时应用UNPIVOT和PIVOT函数。 UNPIVOT将采用多列中的表格并将其转换为我上面建议的结构。这将使得结果更容易。
<强> UNPIVOT:强>
您需要对两个表进行取消转换,对于unpivot的查询将类似于以下内容:
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;
select personCategoryId,SampleDate,
replace(replace(col, 'Antigen', ''), 'Value', '') colNum,
value d_value
from tblDSAData
unpivot
(
value
for col in ([Antigen1Value], [Antigen2Value], [Antigen3 Value], [Antigen4Value])
) unpiv;
见SQL Fiddle with Demo。如果您运行这些查询,您会注意到您得到的结果与此类似:
| PERSONCATEGORYID | COLNUM | L_VALUE |
---------------------------------------
| 1 | 1 | A1 |
| 1 | 2 | Cw6 |
| 1 | 3 | DR15 |
| 1 | 4 | DR51 |
和
| PERSONCATEGORYID | SAMPLEDATE | COLNUM | D_VALUE |
-------------------------------------------------------------------------
| 1 | February, 08 2013 00:00:00+0000 | 1 | 1278 |
| 1 | February, 08 2013 00:00:00+0000 | 2 | 11272 |
| 1 | February, 08 2013 00:00:00+0000 | 3 | 6880 |
| 1 | February, 08 2013 00:00:00+0000 | 4 | 7544 |
| 1 | February, 11 2013 00:00:00+0000 | 1 | 1711 |
| 1 | February, 11 2013 00:00:00+0000 | 2 | 9681 |
| 1 | February, 11 2013 00:00:00+0000 | 3 | 8437 |
| 1 | February, 11 2013 00:00:00+0000 | 4 | 8967 |
<强> PIVOT 强>
一旦此数据采用此多行格式,您就可以轻松地将结果加入personCategoryId
和colNum
并应用PIVOT函数以获得最终结果。具有连接和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)
见SQL Fiddle with Demo。所有版本都会给出结果:
| 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 两个表的em>代码将是:
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)