Can't figure out how to transpose data from one table to another. Do I use a cursor?
Sample Data:
Build Part SN DateShipped
A 1 123 2017-01-01
A 2 234 2017-02-02
A 3 345 2017-03-03
B 1 987 2017-01-01
B 2 876 2017-02-02
B 3 765 2017-03-03
Desired Result:
Build Part1SN Part1Ship Part2SN Part2Ship Part3SN Part3Ship
A 123 2017-01-01 234 2017-02-02 345 2017-03-03
B 987 2017-01-01 876 2017-02-02 765 2017-03-03
Since you are mixing data types (date & int) in the Pivot, I'll give a working example of a dynamic Pivot. Date note of what we are doing within the Cross Apply.
I'm also assuming Part is sequential within build, otherwise we would need to apply/nest a Row_Number()
Example
Declare #SQL varchar(max) = '
Select *
From (
Select A.Build
,B.*
From YourTable A
Cross Apply ( values (concat(''Part'',A.Part,''SN''), concat('''',A.SN))
,(concat(''Ship'',A.Part,''Ship''),concat('''',A.DateShipped))
) B (Item,Value)
) A
Pivot (max([Value]) For [Item] in (' + Stuff((Select ','+QuoteName(concat('Part',Part,'SN'))
+','+QuoteName(concat('Ship',Part,'Ship'))
From (Select Distinct Part From YourTable ) A
Order By 1
For XML Path('')),1,1,'') + ') ) p'
Exec(#SQL)
--Print #SQL
Returns
The Generated SQL Looks Like This
Select *
From (
Select A.Build
,B.*
From YourTable A
Cross Apply ( values (concat('Part',A.Part,'SN'), concat('',A.SN))
,(concat('Ship',A.Part,'Ship'),concat('',A.DateShipped))
) B (Item,Value)
) A
Pivot (max([Value]) For [Item] in ([Part1SN],[Ship1Ship],[Part2SN],[Ship2Ship],[Part3SN],[Ship3Ship]) ) p
select Build,
max(case Part when 1 then SN end) 'Part1SN', max(case Part when 1 then DateShipped end) 'Part1Ship',
max(case Part when 2 then SN end) 'Part2SN', max(case Part when 2 then DateShipped end) 'Part2Ship',
max(case Part when 3 then SN end) 'Part3SN', max(case Part when 3 then DateShipped end) 'Part3Ship'
from TempTable
group by Build
You should try using pivot Table.
For reference follow the below link
https://www.sqlshack.com/multiple-options-to-transposing-rows-into-columns/
Related
I want to transpose the below rows dynamically into columns.
**Process Id Attribute Values**
1 Equipment Normal
1 Complaints No
1 Availability 30 min
2 Phone1 123456789
2 Phone2 987654321
I have tried to pivot it but I am unable to get the desired results. I need the below output
Process ID Attribute1 Value1 Arrtibute2 Value2 Attribute3 Value3
1 Equipment Normal Complaints No Availability 30 min
2 Phone1 123456789 Phone2 987654321 NULL NULL
One process can have one or more attributes. So if a process have 10 attributes, it should create 10 columns in the desired output. Any suggestions?
All the newest ANSI compliant databases should support this. Witn no DBMS, I stick to the newest ANSI standard.
WITH
-- your input
input(Process_Id,Attribute,Values) AS (
SELECT 1,'Equipment','Normal'
UNION ALL SELECT 1,'Complaints','No'
UNION ALL SELECT 1,'Availability','30 min'
UNION ALL SELECT 2,'Phone1','123456789'
UNION ALL SELECT 2,'Phone2','987654321'
)
,
-- need a sequence counter ...
with_seq AS (
SELECT
ROW_NUMBER() OVER(PARTITION BY process_id) AS seq
, *
FROM input
)
SELECT
process_id
, MAX(CASE seq WHEN 1 THEN attribute END) AS attrib1
, MAX(CASE seq WHEN 1 THEN values END) AS val1
, MAX(CASE seq WHEN 2 THEN attribute END) AS attrib2
, MAX(CASE seq WHEN 2 THEN values END) AS val2
, MAX(CASE seq WHEN 3 THEN attribute END) AS attrib3
, MAX(CASE seq WHEN 3 THEN values END) AS val3
FROM with_seq
GROUP BY process_id;
-- out process_id | attrib1 | val1 | attrib2 | val2 | attrib3 | val3
-- out ------------+-----------+-----------+------------+-----------+--------------+-------
-- out 1 | Equipment | Normal | Complaints | No | Availability | 30 min
-- out 2 | Phone1 | 123456789 | Phone2 | 987654321 | |
Try this below code. It will provide desired output.
My sample Algorithm
1. Create manual named columns by using ROW_NUMBER()
2. Create Dynamic columns for Attribute,Value named as #columnsAttribute, #columnsValue
3. Create Dynamic group by columns for both Attribute & Value named as #Allcolumns
4. Dynamic query creation with pivot for both Attribute & Value
declare #tblAttribute as
table(processid int,
attribute NVARCHAR(100),
value NVARCHAR(200))
insert into #tblAttribute(processid,attribute,value)
values(1,'Equipment','Normal'),
(1,'Complaints','No'),
(1,'Availability','30 min'),
(1,'test','testvalue'),
(2,'Phone1','123456789'),
(2,'Phone2','987654321')
;with ctetbl as
(
select ROW_NUMBER() over (partition by processid order by processid) rno,* from #tblAttribute
)
,ctetbl1 as
(
select processid,
'Attribute'+ cast(rno as NVARCHAR(2)) as DynamicAttribute,
'Value'+cast(rno as NVARCHAR(2)) as DyanamicValue
,attribute,value from ctetbl
)
select * into #tblDynamicAttribute from ctetbl1
declare #Allcolumns as NVARCHAR(max),
#columnsAttribute as NVARCHAR(max),
#columnsValue as NVARCHAR(max),
#sql as NVARCHAR(MAX) = ''
select #Allcolumns=coalesce(#Allcolumns+',','')+'max('+QUOTENAME(B.DynamicAttribute)+') as '+ QUOTENAME(B.DynamicAttribute) +',max('+QUOTENAME(B.DyanamicValue)+') as '+ QUOTENAME(B.DyanamicValue)
from (select distinct DynamicAttribute,DyanamicValue from #tblDynamicAttribute) as B
order by b.DynamicAttribute
select #columnsAttribute=coalesce(#columnsAttribute+',','')+QUOTENAME(B.DynamicAttribute)
from (select distinct DynamicAttribute,DyanamicValue from #tblDynamicAttribute) as B
order by b.DynamicAttribute
select #columnsValue=coalesce(#columnsValue+',','')+QUOTENAME(B.DyanamicValue)
from (select distinct DynamicAttribute,DyanamicValue from #tblDynamicAttribute) as B
order by b.DynamicAttribute
-- construct dynamic SQL
SET #sql ='
select x.processid,' + #Allcolumns +' from (
SELECT processid,' + #columnsAttribute+','+ #columnsValue +' FROM
(
SELECT
processid,attribute,value,dynamicattribute,DyanamicValue
FROM
#tblDynamicAttribute p
) t
PIVOT(
max(attribute)
FOR dynamicattribute IN ('+ #columnsAttribute +')
) AS pivot_table
PIVOT(
max(value)
FOR DyanamicValue IN ('+ #columnsValue +')
) AS pivot_table1
) x group by processid;';
-- execute the dynamic SQL
EXECUTE sp_executesql #sql;
drop table #tblDynamicAttribute
Sample Output
This is table A
Wallet Type State
------------------------
106 1
106 2
106 1
106 1
106 2
112 1
112 2
112 2
Now i need a table where it counts wallet type according to the state
Table B would be like this
State Distributor(106) Agent(112)
----------------------------------------
1 3 1
2 2 2
Try this:
You can get this using Aggregate functions.
SUM:
SELECT State
,SUM(CASE WHEN Wallet_Type = 106 THEN 1 ELSE 0 END) Distributor_106
,SUM(CASE WHEN Wallet_Type = 112 THEN 1 ELSE 0 END) Distributor_112
FROM Your_Table
WHERE Wallet_Type IN (106, 112)
GROUP BY State
COUNT:
SELECT State
,COUNT(CASE WHEN Wallet_Type = 106 THEN 1 END) Distributor_106
,COUNT(CASE WHEN Wallet_Type = 112 THEN 1 END) Distributor_112
FROM Your_Table
WHERE Wallet_Type IN (106, 112)
GROUP BY State
These type of problems can also be solved using PIVOT keyword in SQL server.
To know more about PIVOT read here.
see working demo
Your query using PIVOT should be like
select
[state],
[Distributor(106)]=[106],
[Agent(112)]=[112]
from
(
select
[state],
[cstate]=state, -- created duplicate as this will be consumed in count operation and will not be available as output column later
[Wallet Type]
from tableA
) src
pivot
(
count(cstate) for [Wallet Type] in ([106],[112])
)p
You can use pivot table for this case
declare #t1 table (wallet_type int, state int)
insert into #t1
values (106, 1),
(106 , 2 ),
(106 , 1 ),
(106 , 1 ),
(106 , 2 ),
(112 , 1 ),
(112 , 2 ),
(112 , 2 )
--select * from #t1
select *
from
(
select state, wallet_type, count(wallet_type) 'count' from #t1
group by state, wallet_type
) src
pivot
(
sum(count)
for wallet_type in ([106], [112])
) piv;
Online Demo: http://rextester.com/QBTOQ8569
Try this one... (Dynamic PIVOT)
DECLARE #cols AS NVARCHAR(max) = Stuff((SELECT DISTINCT ', ' + Quotename(WalletType)
FROM TableName
FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1, '');
DECLARE #query AS NVARCHAR(max) = ' SELECT *
FROM TableName
PIVOT ( Count(wallettype)
FOR wallettype IN ('+#cols+') ) pvt';
EXECUTE(#query)
Output
+-------+-----+-----+
| State | 106 | 112 |
+-------+-----+-----+
| 1 | 3 | 1 |
| 2 | 2 | 2 |
+-------+-----+-----+
First of All, you need to declare a cols Variable that will give you all the distinct Wallet Types that will be used later in the query:
DECLARE #cols AS NVARCHAR(max) =
Stuff((SELECT DISTINCT ', ' + Convert(nvarchar, WalletType)
FROM [IHC].[dbo].[TABLENAMEHERE]
FOR XML PATH ('')), 1, 2, '')
what it does is, it gets all the distinct comma separated WalletTypes. as XML Path gives you data in XML so we can play with it.
then use PIVOT operator as suggested by some people. here:
select *
from
(
select [state], [WalletType], count([WalletType]) as count FROM [IHC].[dbo].[TABLENAMEHERE]
group by [state], [WalletType]
) SourceTable
pivot
(
sum(count)
for [WalletType] in (#cols)
) piv;
the first part of this query gives you state, WalletType, 'Count of Wallet' Types grouped by state and Wallet Type or say broken w.r.t State and Wallet Type
like this:
state WalletType count
1 106 4
2 106 2
1 112 1
2 112 2
now this 'Count of Wallet' as count is used in PIVOT function to get the SUM of COUNT w.r.t the Wallet Types so it sums the count w.r.t WalletType and gives the final result
make sure you use it in a dynamic query.
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 |
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.
This question already has answers here:
SQL turning values returned in 11 rows into 89 total columns
(2 answers)
Closed 9 years ago.
this is my query
select * from dbo.tblHRIS_ChildDetails where intSID=463
output:
intCHID intsid nvrchildname nvrgender dttchildDOB Occupation
3 463 SK Female 2001-12-11 00:00:00.000 Studying
4 463 SM Male 2007-10-08 00:00:00.000 Student
i need the output like this this is query is dynamic it may return n number of rows based on the intSID
chidname1 gender DOB childoccupation1 chidname2 gender DOB childoccupation2
SK female 2001-12-11 00:00:00.000 studying SM Male 2007-10-08 00:00:00.000 Student
For this type of data, you will need to implement both the UNPIVOT and then the PIVOT functions of SQL Server. The UNPIVOT takes your data from the multiple columns and place it into two columns and then you apply the PIVOT to transform the data back into columns.
If you know all of the values that you want to transform, then you can hard-code it, similar to this:
select *
from
(
select value, col+'_'+cast(rn as varchar(10)) col
from
(
select nvrchildname,
nvrgender,
convert(varchar(10), dttchildDOB, 120) dttchildDOB,
occupation,
row_number() over(partition by intsid order by intCHID) rn
from tblHRIS_ChildDetails
where intsid = 463
) src
unpivot
(
value
for col in (nvrchildname, nvrgender, dttchildDOB, occupation)
) unpiv
) src1
pivot
(
max(value)
for col in ([nvrchildname_1], [nvrgender_1],
[dttchildDOB_1], [occupation_1],
[nvrchildname_2], [nvrgender_2],
[dttchildDOB_2], [occupation_2])
) piv
See SQL Fiddle with Demo
Now, if you have an unknown number of values to transform, then you can use dynamic SQL for this:
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('tblHRIS_ChildDetails') and
C.name not in ('intCHID', 'intsid')
for xml path('')), 1, 1, '')
select #colsPivot = STUFF((SELECT ','
+ quotename(c.name
+'_'+ cast(t.rn as varchar(10)))
from
(
select row_number() over(partition by intsid order by intCHID) rn
from tblHRIS_ChildDetails
) t
cross apply sys.columns as C
where C.object_id = object_id('tblHRIS_ChildDetails') and
C.name not in ('intCHID', 'intsid')
group by c.name, t.rn
order by t.rn
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query
= 'select *
from
(
select col+''_''+cast(rn as varchar(10)) col, value
from
(
select nvrchildname,
nvrgender,
convert(varchar(10), dttchildDOB, 120) dttchildDOB,
occupation,
row_number() over(partition by intsid order by intCHID) rn
from tblHRIS_ChildDetails
where intsid = 463
) x
unpivot
(
value
for col in ('+ #colsunpivot +')
) u
) x1
pivot
(
max(value)
for col in ('+ #colspivot +')
) p'
exec(#query)
See SQL Fiddle with Demo
The result of both queries is:
| NVRCHILDNAME_1 | NVRGENDER_1 | DTTCHILDDOB_1 | OCCUPATION_1 | NVRCHILDNAME_2 | NVRGENDER_2 | DTTCHILDDOB_2 | OCCUPATION_2 |
-----------------------------------------------------------------------------------------------------------------------------
| SK | Female | 2001-12-11 | Studying | SM | Male | 2007-10-08 | Student |
You have to provide distinct column names but besides that, it's simple. But as others stated, this is not commonly done and looks like if you want print some report with two columns.
select
max(case when intCHID=1 then nvrchildname end) as chidname1,
max(case when intCHID=1 then gender end) as gender1,
max(case when intCHID=1 then dttchildDOB end) as DOB1,
max(case when intCHID=1 then Occupation end) as cildOccupation1,
max(case when intCHID=2 then nvrchildname end) as chidname2,
max(case when intCHID=2 then gender end) as gender2,
max(case when intCHID=2 then dttchildDOB end) as DOB2,
max(case when intCHID=2 then Occupation end) as cildOccupation2
from
dbo.tblHRIS_ChildDetails
where
intSID=463