Well part of the problem that I see is you have two tables that are de-normalized, meaning you basically have two tables that are designed as spreadsheets and not tables. The best solution to this problem would be to restructure your tables.
If possible, my advice would be to change the table structure to the following:
CREATE TABLE reftblDSAColumnLabels
(
[PersonCategoryId] int,
[AntigenNum] int,
[AntigenValue] varchar(4)
);
CREATE TABLE tblDSAData
(
[PersonCategoryId] int,
[SampleDate] datetime,
[AntigenNum] int,
[AntigenValue] int
);
This way you could join the tables on both the personCategoryId
and the AntigenNum
(1, 2, 3, etc). You will see why I suggest this in a minute.
Since your tables are de-normalized it will be very difficult to generate the result set on the fly by passing in a personCategoryId
. You will need to use dynamic SQL to generate the result based on the id that is submitted to a procedure.
In order to get this result, I would suggest apply both the UNPIVOT and PIVOT functions. The UNPIVOT is going to take your tables that are in multiple columns and convert them into the structures that I suggested above. This will make getting the result much easier.
UNPIVOT:
You need to unpivot both tables, the queries to unpivot will be similar to the following:
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;
See SQL Fiddle with Demo
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;
See SQL Fiddle with Demo. If you run these queries you will notice that you get a result similar to this:
| PERSONCATEGORYID | COLNUM | L_VALUE |
---------------------------------------
| 1 | 1 | A1 |
| 1 | 2 | Cw6 |
| 1 | 3 | DR15 |
| 1 | 4 | DR51 |
and
| 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
Once this data is in this multiple row format, you can easily join the results on the personCategoryId
and the colNum
and apply the PIVOT function to get the final result. The code with the join and the PIVOT will be:
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;
See SQL Fiddle with Demo.
Now for your current problem, you need to pass in the personCategoryId
so the column headers will be changing for each id. Since the column headers will change you will need to use dynamic SQL to get the result. You can easily convert the above code into dynamic SQL and the script will be:
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)
See SQL Fiddle with Demo. All versions will give a result:
| 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 |
Edit #1, If you were to normalize the two tables you would still have to use dynamic SQL to get the column headers for each personCategoryId
, however you would be able to remove the unpivot of both tables. The code will be:
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)
See SQL Fiddle with Demo