need help in pivoting a data? - sql

First of all, I am new to SQL. Here is the sample (for both table1 and table2, I have created a SNO as primary key and it's also identity column)
Table1:
PID PNAME PartID
--- ----- ------
0 Length 1
1 Breadth 1
2 Height 1
0 Area 2
1 Volume 2
Table2:
SampleID PID Pvalue PartID ModifiedDate Operator
-------- --- ------ ------ ------------ --------
0 0 10 1 10-Mar-14 Test
0 1 10 1 10-Mar-14 Test
0 2 Fail 1 10-Mar-14 Test
1 0 20 1 12-Mar-14 Test
1 1 Fail 1 12-Mar-14 Test
1 2 Fail 1 12-Mar-14 Test
0 0 10 2 13-Mar-14 Test1
0 1 10 2 13-Mar-14 Test1
Depending upon the PartID, I must get the following results
PARTID: 1
PNAME 0 1
------------ --------- ---------
Length 10 20
Breadth 10 Fail
Height Fail Fail
ModifiedDate 10-Mar-14 12-Mar-14
Operator Test Test
PARTID: 2
PNAME 0
------------ ---------
Area 10
Volume 10
ModifiedDate 13-Mar-14
Operator Test1
How to achieve the desired output as mentioned above in SQL Server 2008?

You can use PIVOT to get the result but you will also need to unpivot the ModifiedDate and Operator columns so you can display them in a single column with the PName. Your final result will need a dynamic solution but it would be much easier to write this static first, then convert to dynamic sql.
The basic syntax will be:
select pname, [0], [1]
from
(
select t2.sampleid, pname = c.col, c.value
from table1 t1
inner join table2 t2
on t1.partid = t2.partid
and t1.pid = t2.pid
cross apply
(
select Pname, pvalue union all
select 'ModifiedDate', convert(varchar(10), ModifiedDate, 120) union all
select 'Operator', Operator
) c (col, value)
where t1.partid = 1
) d
pivot
(
max(value)
for sampleid in ([0], [1])
) p;
See SQL Fiddle with Demo. You'll see that I used CROSS APPLY to convert the 3 columns PName, ModifiedDate and Operator into a single column. This is necessary so you can easily get to the values for each SampleId. The above version is a static version meaning you are hard-coding the values for the final columns, but if you want to have this adjust based on the PartId, you will need to use dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#partid int,
#paramdef nvarchar(max)
set #partid = 1
set #paramdef = '#partid int'
select #cols = STUFF((SELECT ',' + QUOTENAME(sampleid)
from Table2
where partid = #partid
group by sampleid
order by sampleid
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT pname,' + #cols + '
from
(
select t2.sampleid, pname = c.col, c.value
from table1 t1
inner join table2 t2
on t1.partid = t2.partid
and t1.pid = t2.pid
cross apply
(
select Pname, pvalue union all
select ''ModifiedDate'', convert(varchar(10), ModifiedDate, 120) union all
select ''Operator'', Operator
) c (col, value)
where t1.partid = #partid
) x
pivot
(
max(value)
for sampleid in (' + #cols + ')
) p '
exec sp_executesql #query, #paramdef, #partid = #partid;
See SQL Fiddle with Demo. Both give a result:
| PNAME | 0 | 1 |
|--------------|------------|------------|
| Breadth | 10 | Fail |
| Height | Fail | Fail |
| Length | 10 | 20 |
| ModifiedDate | 2014-03-10 | 2014-03-12 |
| Operator | Test | Test |

Related

Columns to rows and rows to column conversion without pivot/unpivot

All I need is convert Column(A1/A2) into rows and rows(1 into Jan) into columns.
Input:
Here A1/A2 belongs to say A and they are calculated as A1/A2 for each month.
Month A1 A2 B1 B2 C1 C2
1 120 60 40 80 120 120
2 50 50 40 20 60 30
3 50 25 40 10 90 30
I need below o/p without using pivot and unpivot
O/P:
X Jan(1 is denoting Jan) Feb Mar
A 120/60(calculation:A1/A2) 40/80 120/120
B 50/50 40/20 60/30
C 50/25 40/10 90/30
I tried but my query is too long as I am using case and Union All three times each For A1 A2,B1 B2,C1 C2 etc.
Using cross apply(values ...) and conditional aggregation:
select
v.X
, Jan = max(case when t.month=1 then v.Value end)
, Feb = max(case when t.month=2 then v.Value end)
, Mar = max(case when t.month=3 then v.Value end)
from t
cross apply(values
('A',convert(varchar(3),A1)+'/'+convert(varchar(3),A2))
,('B',convert(varchar(3),B1)+'/'+convert(varchar(3),B2))
,('C',convert(varchar(3),C1)+'/'+convert(varchar(3),C2))
) v (X,Value)
group by v.X
rextester demo: http://rextester.com/XICI74484
returns:
+---+---------+-------+-------+
| X | Jan | Feb | Mar |
+---+---------+-------+-------+
| A | 120/60 | 50/50 | 50/25 |
| B | 40/80 | 40/20 | 40/10 |
| C | 120/120 | 60/30 | 90/30 |
+---+---------+-------+-------+
For the evaluation of the expressions:
select
v.X
, Jan = max(case when t.month=1 then v.Value end)
, Feb = max(case when t.month=2 then v.Value end)
, Mar = max(case when t.month=3 then v.Value end)
from t
cross apply(values
('A',(A1*1.0)/A2)
,('B',(B1*1.0)/B2)
,('C',(C1*1.0)/C2)
) v (X,Value)
group by v.X
returns:
+---+------+------+------+
| X | Jan | Feb | Mar |
+---+------+------+------+
| A | 2.00 | 1.00 | 2.00 |
| B | 0.50 | 2.00 | 4.00 |
| C | 1.00 | 2.00 | 3.00 |
+---+------+------+------+
You can use XML. This snippet may be more than you want but it shows how
--------------------------------------------------
-----------------Begin TRANSPOSE-----------------
--------------------------------------------------
DECLARE #xml XML
,#RowCount BIGINT
DECLARE #sSQl NVARCHAR(MAX)= 'SELECT (SELECT DISTINCT ColumnName FROM #TempTable WHERE CellId=Cell.CellId) as ColumnName,'
---------------------------------------------------
--Set up #table Here or outside the code... but #TABLE WILL BE DROPPED AT FINISH
---------------------------------------------------
--#############################################################################
-- the temp table #Table will contain what you want to Transpose
--#############################################################################
--SELECT * INTO #Table FROM Widgets W WHERE WidgetId IN (1096,803)
---------------------------------------------------
---------------- End #Table Setup ---------------
---------------------------------------------------
SET #xml = (SELECT *
,ROW_NUMBER() OVER (ORDER BY (SELECT 1
)) Rn
FROM #Table Row
FOR
XML AUTO
,ROOT('Root')
,ELEMENTS XSINIL
);
WITH RC AS
(SELECT COUNT(Row.value('.', 'nvarchar(MAX)')) [RowCount]
FROM #xml.nodes('Root/Row') AS WTable(Row))
,c AS(
SELECT b.value('local-name(.)','nvarchar(max)') ColumnName,
b.value('.[not(#xsi:nil = "true")]','nvarchar(max)') Value,
b.value('../Rn[1]','nvarchar(max)') Rn,
ROW_NUMBER() OVER (PARTITION BY b.value('../Rn[1]','nvarchar(max)') ORDER BY (SELECT 1)) Cell
FROM
#xml.nodes('//Root/Row/*[local-name(.)!="Rn"]') a(b)
),Cols AS (
SELECT DISTINCT c.ColumnName,
c.Cell
FROM c
)
INSERT INTO #TempTable (CellId,RowID,Value,ColumnName)
SELECT Cell,Rn,Value,REPLACE(c.ColumnName,'_x0023_','#')
FROM c
SELECT #sSQL = #sSQl + '(SELECT T2.Value FROM #Temptable T2 WHERE T2.CellId=Cell.CellID AND T2.Rowid=' + CAST(T.RowId AS NVARCHAR) + ') AS __________________Value____________________'
+ CAST(T.RowID AS NVARCHAR) + ','
FROM (SELECT DISTINCT
RowId
FROM #TempTable
) T
SET #sSQl = LEFT(#sSQL, LEN(#sSQL) - 1) + ' FROM (SELECT DISTINCT CellId FROM #TempTable) Cell order by columnname'
EXECUTE sp_Executesql #sSQl
--here you will have your output
-- PRINT #sSQl
DROP TABLE #Table
DROP TABLE #TempTable
--------------------------------------------------
-----------------END TRANSPOSE-------------------
--------------------------------------------------

extend current query, calculated columns

My table looks for example like this:
Name date result
A 2012-01-01 1
A 2012-02-01 2
B 2013-01-01 1
...
For a full example: http://sqlfiddle.com/#!3/0226b/1
At the moment I have a working query that counts the rows by person and year: http://sqlfiddle.com/#!3/0226b/3
This is perfect, but what I want is some extra information for 2014. i need to count how many rows I have for every result.
something like this:
NAME 1 2 3 2014 2013 2012 TOTAL
Person B 4 0 2 6 2 2 10
Person A 2 1 1 4 3 4 11
Person C 1 1 1 3 1 0 4
Even better would be that I give the result-columns a good name (1 = lost, 2= draw, 3=won):
NAME lost draw won 2014 2013 2012 TOTAL
Person B 4 0 2 6 2 2 10
Person A 2 1 1 4 3 4 11
Person C 1 1 1 3 1 0 4
I tried to add some extra code, like:
select #colsResult
= STUFF((SELECT ',' + QUOTENAME(result)
from list
group by result
order by result
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
I have as result:
,[1]
,[2]
,[3]
But if I run the whole code I get an error, invallid column name...
Since you have two columns that you now want to PIVOT, you'll first have to unpivot those columns and then convert those values into the new columns.
Starting in SQL Server 2005, you could use CROSS APPLY to unpivot the columns. The basic syntax will be similar to:
select
name,
new_col,
total
from
(
select name,
dt = year(date),
result,
total = count(*) over(partition by name)
from list
) d
cross apply
(
select 'dt', dt union all
select 'result', result
) c (old_col_name, new_col)
See SQL Fiddle with Demo. This query gets you a list of names, with the "new columns" and then the Total entries for each name.
| NAME | NEW_COL | TOTAL |
|----------|---------|-------|
| Person A | 2012 | 11 |
| Person A | 1 | 11 |
| Person A | 2012 | 11 |
| Person A | 2 | 11 |
You'll see that the dates and the results are now both stored in "new_col". These values will now be used as the new column names. If you have a limited number of columns, then you would simply hard-code the query:
select name, lost = [1],
draw=[2], won = [3],
[2014], [2013], [2012], Total
from
(
select
name,
new_col,
total
from
(
select name,
dt = year(date),
result,
total = count(*) over(partition by name)
from list
) d
cross apply
(
select 'dt', dt union all
select 'result', result
) c (old_col_name, new_col)
) src
pivot
(
count(new_col)
for new_col in([1], [2], [3], [2014], [2013], [2012])
) piv
order by [2014];
See SQL Fiddle with Demo
Now since your years are dynamic, then you'll need to use dynamic sql. But it appears that you have 3 results and potentially multiple years - so I'd use a combination of static/dynamic sql to make this easier:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#orderby nvarchar(max)
select #cols
= STUFF((SELECT ',' + QUOTENAME(year(date))
from list
group by year(date)
order by year(date) desc
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #orderby = 'ORDER BY ['+cast(year(getdate()) as varchar(4)) + '] desc'
set #query = 'SELECT name, lost = [1],
draw=[2], won = [3],' + #cols + ', Total
from
(
select
name,
new_col,
total
from
(
select name,
dt = year(date),
result,
total = count(*) over(partition by name)
from list
) d
cross apply
(
select ''dt'', dt union all
select ''result'', result
) c (old_col_name, new_col)
) x
pivot
(
count(new_col)
for new_col in ([1], [2], [3],' + #cols + ')
) p '+ #orderby
exec sp_executesql #query;
See SQL Fiddle with Demo. This gives a result:
| NAME | LOST | DRAW | WON | 2014 | 2013 | 2012 | TOTAL |
|----------|------|------|-----|------|------|------|-------|
| Person B | 7 | 1 | 2 | 6 | 2 | 2 | 10 |
| Person A | 5 | 3 | 3 | 4 | 3 | 4 | 11 |
| Person C | 2 | 1 | 1 | 3 | 1 | 0 | 4 |
If you want to only filter the result columns for the current year, then you can perform this filtering a variety of ways but the easiest you be to include a filter in the unpivot. The hard-coded version would be:
select name, lost = [1],
draw=[2], won = [3],
[2014], [2013], [2012], Total
from
(
select
name,
new_col,
total
from
(
select name,
dt = year(date),
result,
total = count(*) over(partition by name)
from list
) d
cross apply
(
select 'dt', dt union all
select 'result', case when dt = 2014 then result end
) c (old_col_name, new_col)
) src
pivot
(
count(new_col)
for new_col in([1], [2], [3], [2014], [2013], [2012])
) piv
order by [2014] desc;
See SQL Fiddle with Demo. Then the dynamic sql version would be:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#orderby nvarchar(max),
#currentYear varchar(4)
select #currentYear = cast(year(getdate()) as varchar(4))
select #cols
= STUFF((SELECT ',' + QUOTENAME(year(date))
from list
group by year(date)
order by year(date) desc
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #orderby = 'ORDER BY ['+ #currentYear + '] desc'
set #query = 'SELECT name, lost = [1],
draw=[2], won = [3],' + #cols + ', Total
from
(
select
name,
new_col,
total
from
(
select name,
dt = year(date),
result,
total = count(*) over(partition by name)
from list
) d
cross apply
(
select ''dt'', dt union all
select ''result'', case when dt = '+#currentYear+' then result end
) c (old_col_name, new_col)
) x
pivot
(
count(new_col)
for new_col in ([1], [2], [3],' + #cols + ')
) p '+ #orderby
exec sp_executesql #query;
See SQL Fiddle with Demo. This version will give a result:
| NAME | LOST | DRAW | WON | 2014 | 2013 | 2012 | TOTAL |
|----------|------|------|-----|------|------|------|-------|
| Person B | 4 | 0 | 2 | 6 | 2 | 2 | 10 |
| Person A | 2 | 1 | 1 | 4 | 3 | 4 | 11 |
| Person C | 1 | 1 | 1 | 3 | 1 | 0 | 4 |

Pivot table to turn rows into columns

I currently run the query
SELECT [PriceAttributeID]
,[PriceID]
,[AttributeID]
,[PriceAttributeComparator]
,[PriceAttributeMin]
,[PriceAttributeMax]
FROM [PriceAttribute]
Which gives the output
1 2 1 1 S NULL
2 3 1 1 M NULL
3 4 1 1 L NULL
4 5 1 1 L NULL
5 5 2 1 Black NULL
I would like to get the output (where _Comp, _Min and _Max relate to PriceAttributeComparator, PriceAttributeMin and PriceAttributeMax)
PriceID 1_Comp 1_Min 1_Max 2_Comp 2_Min 2_Max
2 1 S NULL NULL NULL NULL
3 1 M NULL NULL NULL NULL
4 1 L NULL NULL NULL NULL
5 1 L NULL 1 Black NULL
The same query would also be expected to have 1_ and 2_ prefixes as 4_, 5_, 19_ and 32_ or any other indeterminate number of ID's based on what is in the table at the time.
I have attempted a PIVOT table, but i am new to them and haven't the first clue on how to create what it is i am looking to do.
Part of the problem you are probably having with the PIVOT function is due to the fact you have multiple columns that you want to apply the function to. If you want to use the PIVOT function, then I would suggest first unpivoting the columns PriceAttributeComparator, PriceAttributeMin and PriceAttributeMax. When you unpivot the data you will no longer have multiple columns, you will have multiple rows, then you can apply the pivot to all of the appropriate values.
You did not specify what version of SQL Server you are using but you can use CROSS APPLY with a UNION ALL to unpivot the columns:
select priceid,
col = cast(attributeid as varchar(10))+'_'+ col,
value
from
(
select PriceID,
AttributeID,
comp = cast(PriceAttributeComparator as varchar(10)),
[min] = cast(PriceAttributeMin as varchar(10)),
[max] = cast(PriceAttributeMax as varchar(10))
from PriceAttribute
) d
cross apply
(
select 'comp', comp union all
select 'min', [min] union all
select 'max', [max]
) c (col, value)
See Demo. This process will convert your data into the following format:
| PRICEID | COL | VALUE |
-----------------------------
| 2 | 1_comp | 1 |
| 2 | 1_min | S |
| 2 | 1_max | (null) |
| 3 | 1_comp | 1 |
| 3 | 1_min | M |
| 3 | 1_max | (null) |
Once the data is in multiple rows, then you can apply the PIVOT function to the values in col:
select priceid,
[1_comp], [1_min], [1_max], [2_comp], [2_min], [2_max]
from
(
select priceid,
col = cast(attributeid as varchar(10))+'_'+ col,
value
from
(
select PriceID,
AttributeID,
comp = cast(PriceAttributeComparator as varchar(10)),
[min] = cast(PriceAttributeMin as varchar(10)),
[max] = cast(PriceAttributeMax as varchar(10))
from PriceAttribute
) d
cross apply
(
select 'comp', comp union all
select 'min', [min] union all
select 'max', [max]
) c (col, value)
) src
pivot
(
max(value)
for col in ([1_comp], [1_min], [1_max], [2_comp], [2_min], [2_max])
) piv;
See SQL Fiddle with Demo.
The above versions work great if you have a known number of values but if the values are unknown, then you will need to use dynamic SQL to get the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(cast(attributeid as varchar(10))+'_'+ col)
from
(
select distinct attributeid
from priceattribute
) d
cross apply
(
select 'comp', 1 union all
select 'min', 2 union all
select 'max', 3
) c (col, so)
group by attributeid, col, so
order by attributeid, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT priceid, ' + #cols + '
from
(
select priceid,
col = cast(attributeid as varchar(10))+''_''+ col,
value
from
(
select PriceID,
AttributeID,
comp = cast(PriceAttributeComparator as varchar(10)),
[min] = cast(PriceAttributeMin as varchar(10)),
[max] = cast(PriceAttributeMax as varchar(10))
from PriceAttribute
) d
cross apply
(
select ''comp'', comp union all
select ''min'', [min] union all
select ''max'', [max]
) c (col, value)
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute sp_executesql #query;
See SQL Fiddle with Demo. These solutions will give a result:
| PRICEID | 1_COMP | 1_MIN | 1_MAX | 2_COMP | 2_MIN | 2_MAX |
----------------------------------------------------------------
| 2 | 1 | S | (null) | (null) | (null) | (null) |
| 3 | 1 | M | (null) | (null) | (null) | (null) |
| 4 | 1 | L | (null) | (null) | (null) | (null) |
| 5 | 1 | L | (null) | 1 | Black | (null) |
It might be simplest to do this using conditional aggregation rather than pivot:
SELECT PriceID,
max(case when AttributeID = 1 then PriceAttributeComparator end) as comp_1,
max(case when AttributeID = 1 then PriceAttributeMin end) as min_1,
max(case when AttributeID = 1 then PriceAttributeMax end) as max_1,
max(case when AttributeID = 2 then PriceAttributeComparator end) as comp_2,
max(case when AttributeID = 2 then PriceAttributeMin end) as min_2,
max(case when AttributeID = 2 then PriceAttributeMax end) as max_2
FROM PriceAttribute pa
group by PriceId;

how to convert row to column if unknown number of columns SQL server

I have data like this:
MaGiangVienID | SoTiet1 | SoTiet2 | DateID
79000G07.000206 | 60 | 60.00 | t11
79000G07.000206 | 54 | 54.00 | t12
I want to my result like this:
MaGiangVienID | SoTiet1_t11 | SoTiet2_t11 | SoTiet1_t12 | SoTiet2_t12
79000G07.000206 | 60 | 60.00 | 54 | 54.00
I don't know how many columns because MaGiangVienID have a lot of DateID
Please help me!!Thanks a lot.
For this type of data transformation you need to apply both the UNPIVOT and PIVOT functions. The UNPIVOT takes the data from the multiple columns and places it into rows and then the PIVOT takes the rows and converts it back to columns.
To perform the UNPIVOT all of the values that you convert to rows must be the same datatype so conversion might be needed.
Unpivot:
select MaGiangVienID,
value,
col +'_'+DateId col
from
(
select MaGiangVienID,
cast(SoTiet1 as varchar(50)) SoTiet1,
cast(SoTiet2 as varchar(50)) SoTiet2,
DateID
from yourtable
) src
unpivot
(
value
for col in (SoTiet1, SoTiet2)
) unpiv
See SQL Fiddle with Demo. The result of the unpivot is:
| MAGIANGVIENID | VALUE | COL |
-----------------------------------------
| 79000G07.000206 | 60 | SoTiet1_t11 |
| 79000G07.000206 | 60.00 | SoTiet2_t11 |
| 79000G07.000206 | 54 | SoTiet1_t12 |
| 79000G07.000206 | 54.00 | SoTiet2_t12 |
As you see the UNPIVOT generates the new column names with the DateId appended to the end of it. Now you apply the PIVOT function.
Static PIVOT:
select MaGiangVienID, SoTiet1_t11, SoTiet2_t11, SoTiet1_t12, SoTiet2_t12
from
(
select MaGiangVienID,
value,
col +'_'+DateId col
from
(
select MaGiangVienID,
cast(SoTiet1 as varchar(50)) SoTiet1,
cast(SoTiet2 as varchar(50)) SoTiet2,
DateID
from yourtable
) src
unpivot
(
value
for col in (SoTiet1, SoTiet2)
) unpiv
) src
pivot
(
max(value)
for col in (SoTiet1_t11, SoTiet2_t11, SoTiet1_t12, SoTiet2_t12)
) piv
See SQL Fiddle with Demo
Now the above version works great if you have a known number of DateId values but you stated that you don't so you will want to implement this same query using dynamic sql.
Dynamic PIVOT:
DECLARE #colsUnpivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#colsPivot as NVARCHAR(MAX)
select #colsUnpivot = stuff((select ','+quotename(C.name)
from sys.columns as C
where C.object_id = object_id('yourtable') and
C.name not in ('MaGiangVienID', 'DateID')
for xml path('')), 1, 1, '')
select #colsPivot = STUFF((SELECT DISTINCT ','
+ quotename(c.name + '_'+t.DateId)
from yourtable t
cross apply sys.columns as C
where C.object_id = object_id('yourtable') and
C.name not in ('MaGiangVienID', 'DateID')
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query
= 'select MaGiangVienID, '+#colsPivot+'
from
(
select MaGiangVienID, value, col +''_''+DateId col
from
(
select MaGiangVienID,
cast(SoTiet1 as varchar(50)) SoTiet1,
cast(SoTiet2 as varchar(50)) SoTiet2,
DateID
from yourtable
) src
unpivot
(
value
for col in ('+#colsUnpivot+')
) unpiv
) src
pivot
(
max(value)
for col in ('+ #colspivot +')
) p'
exec(#query)
See SQL Fiddle with Demo
Both versions produce the same result:
The result is:
| MAGIANGVIENID | SOTIET1_T11 | SOTIET2_T11 | SOTIET1_T12 | SOTIET2_T12 |
---------------------------------------------------------------------------
| 79000G07.000206 | 60 | 60.00 | 54 | 54.00 |
If you do not have access to the UNPIVOT/PIVOT functions then you can replicate the query. The UNPIVOT function can be replicated using a UNION ALL and the PIVOT can be produced using a CASE statement with an aggregate function:
select MaGiangVienID,
max(case when col = 'SoTiet1_t11' then value end) SoTiet1_t11,
max(case when col = 'SoTiet2_t11' then value end) SoTiet2_t11,
max(case when col = 'SoTiet1_t12' then value end) SoTiet1_t12,
max(case when col = 'SoTiet2_t12' then value end) SoTiet2_t12
from
(
select MaGiangVienID, 'SoTiet1_t11' col, cast(SoTiet1 as varchar(50)) value
from yourtable
where DateID = 't11'
union all
select MaGiangVienID, 'SoTiet2_t11' col, cast(SoTiet2 as varchar(50)) value
from yourtable
where DateID = 't11'
union all
select MaGiangVienID, 'SoTiet1_t12' col, cast(SoTiet1 as varchar(50)) value
from yourtable
where DateID = 't12'
union all
select MaGiangVienID, 'SoTiet2_t12' col, cast(SoTiet2 as varchar(50)) value
from yourtable
where DateID = 't12'
) src
group by MaGiangVienID
See SQL Fiddle with Demo
All versions will produce identical results.

How can I return several text fields with the same ID number in one row in SQL server?

I have table:
ID Note
1 1 aaa
2 1 bbb
3 1 ccc
4 2 ddd
5 2 eee
6 2 fff
I need to return it as:
ID Note1 Note2 Note3
1 1 aaa bbb ccc
2 2 ddd eee fff
Thank you!
You can use the PIVOT function for this type of query. If you have a known number of columns, then you can hard-code the values:
select *
from
(
select id, note,
'Note' +
cast(row_number() over(partition by id order by id) as varchar(10)) col
from yourtable
) x
pivot
(
max(note)
for col in ([Note1], [Note2], [Note3])
) p
See SQL Fiddle with Demo
If you are going to have an unknown number of notes that you want to turn into columns, then you can use dynamic sql:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ','
+ QUOTENAME('Note' +
cast(row_number() over(partition by id order by id) as varchar(10)))
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT id,' + #cols + ' from
(
select id, note,
''Note'' +
cast(row_number() over(partition by id order by id) as varchar(10)) col
from yourtable
) x
pivot
(
max(note)
for col in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo
Both will produce the same results.
| ID | NOTE1 | NOTE2 | NOTE3 |
------------------------------
| 1 | aaa | bbb | ccc |
| 2 | ddd | eee | fff |
Or if you do not want to use the PIVOT function, then you can use an aggregate function with a CASE statement:
select id,
max(case when rn = 1 then note else '' end) Note1,
max(case when rn = 2 then note else '' end) Note2,
max(case when rn = 3 then note else '' end) Note3
from
(
select id, note,
row_number() over(partition by id order by id) rn
from yourtable
) src
group by id
See SQL Fiddle with Demo