query to combine multiple columns in one columns - sql

I have table which contain the following information.
I want to run a query and show only one line. something like this
I try to use a case statement, However i maybe have other employee who work in different state, and i do not want to list 50 state since most of employee may only work 2-3 state, but in different state. Any help will appreciate. Thanks

Since you want to pivot on multiple columns, my suggestion would be to first look at unpivoting the State, StateWages and StateTax columns then apply the PIVOT function.
You didn't specify what version of SQL Server you are using but you can use either UNPIVOT to CROSS APPLY to convert these multiple columns into rows. The syntax will be similar to:
select PRCo, Employee,
col = c.col + cast(seq as varchar(50)),
c.value
from
(
select PRCo, Employee, State, StateWages, StateTax,
row_number() over(partition by PRCo, Employee
order by state) seq
from yourtable
) d
cross apply
(
select 'State', State union all
select 'StateWages', cast(StateWages as varchar(10)) union all
select 'StateTax', cast(StateTax as varchar(10))
) c (col, value);
See SQL Fiddle with Demo. You'll notice that before I implemented the CROSS APPLY, I used a subquery with row_number() to create a unique value for each row per employee. The reason for doing this is so you can return the multiple state columns, etc. Once you have done this you can use PIVOT:
select PRCo, Employee,
State1, StateWages1, StateTax1,
State2, StateWages2, StateTax2
from
(
select PRCo, Employee,
col = c.col + cast(seq as varchar(50)),
c.value
from
(
select PRCo, Employee, State, StateWages, StateTax,
row_number() over(partition by PRCo, Employee
order by state) seq
from yourtable
) d
cross apply
(
select 'State', State union all
select 'StateWages', cast(StateWages as varchar(10)) union all
select 'StateTax', cast(StateTax as varchar(10))
) c (col, value)
) src
pivot
(
max(value)
for col in (State1, StateWages1, StateTax1,
State2, StateWages2, StateTax2)
) p;
See SQL Fiddle with Demo. The above version works great if you have a limited number of value but it sounds like you need a dynamic solution. Using the code above you can easily convert it to dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(col+cast(seq as varchar(10)))
from
(
select row_number()
over(partition by PRCo, Employee
order by state) seq
from yourtable
) d
cross apply
(
select 'State', 1 union all
select 'StateWages', 2 union all
select 'StateTax', 3
) c (col, so)
group by col, so, seq
order by seq, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT PRCo, Employee, ' + #cols + N'
from
(
select PRCo, Employee,
col = c.col + cast(seq as varchar(50)),
c.value
from
(
select PRCo, Employee, State, StateWages, StateTax,
row_number() over(partition by PRCo, Employee
order by state) seq
from yourtable
) d
cross apply
(
select ''State'', State union all
select ''StateWages'', cast(StateWages as varchar(10)) union all
select ''StateTax'', cast(StateTax as varchar(10))
) c (col, value)
) x
pivot
(
max(value)
for col in (' + #cols + N')
) p '
exec sp_executesql #query;
See SQL Fiddle with Demo. Both versions will give a result:
| PRCO | EMPLOYEE | STATE1 | STATEWAGES1 | STATETAX1 | STATE2 | STATEWAGES2 | STATETAX2 |
|------|----------|--------|-------------|-----------|--------|-------------|-----------|
| 1 | 304 | CA | 20162.03 | 804.42 | IN | 20162.03 | 665.90 |

Related

Syntax Error pivoting a SQL table using string columns

I have a table Occupation like such:
Name | Occupation
-----------------
Sam | Doctor
Joe | Professor
John | Actor
Hailey | Singer
April | Doctor
My goal is to utilize the PIVOT function to display each distinct Occupation as their own column like so:
Doctor | Professor | Singer | Actor
-----------------------------------
Sam | Joe | Hailey | John
April
I went through various stack overflow questions with similar issues, and even utilized the documentation here and followed step by step. My efforts have been futile, so what gives? I am receiving a syntax error every time I run this code. Any suggestions?
Code:
SELECT *
FROM(SELECT Name, Occupation from Occupations) as src
PIVOT
(MAX(Name) FOR Name IN [Doctor], [Professor], [Singer], [Actor]) as piv;
I am solving this problem on Hackerrank, and the compiler was MySQL. I changed it to MSSQL and am no longer receiving a syntax error.
You were missing 2 () One on each side in the PIVOT part, I bolded the brackets I added:
([Doctor], [Professor], [Singer], [Actor]) - These 2
SELECT *
FROM (
SELECT Name, Occupation
FROM Occupations
) as src
PIVOT
(
MAX(Name) FOR Name IN ([Doctor], [Professor], [Singer], [Actor])
) as piv;
This query will generate the answer as per the way you need. The above answer does not provide the answer as the way you required. Try this answer.
DECLARE #sql NVARCHAR(MAX) = N''
DECLARE #cols NVARCHAR(MAX) = N''
--Making the column list dynamically
SELECT #cols = STUFF((SELECT DISTINCT ', '+QUOTENAME( [T2].[Occupation])
FROM Occupation_data [T2]
FOR XML PATH('')), 1, 1, '')
--preparing PIVOT query dynamically.
SET #SQL = ' SELECT
*
into #temp
FROM
(
SELECT row_number() over (order by name) as id, [Name], [Occupation]
FROM Occupation_data
) AS cp
PIVOT
(
min([Name]) FOR [Occupation] IN (' + #cols + ')
) AS up;
Select
row_number() over (order by doctor asc ) as id1
,*
into #temp_1
from #temp where Doctor is not null
Select
row_number() over (Order by Actor asc ) as id2
,*
into #temp_2
from #temp where Actor is not null
Select
row_number() over (Order by Professor asc ) as id3
,*
into #temp_3
from #temp where Professor is not null
Select
row_number() over (Order by Singer asc ) as id4
,*
into #temp_4
from #temp where Singer is not null
select
A.Doctor
,B.Actor
,C.Professor
,D.Singer
from
#temp_1 A inner join
#temp_2 B ON A.id1 = B.id2
INNER JOIN
#temp_3 C ON A.id1 = C.id3
INNER JOIN
#temp_4 D ON A.id1 = d.id4
drop table #temp
drop table #temp_1
drop table #temp_2
drop table #temp_3
drop table #temp_4
';
PRINT( #SQL)
EXEC (#SQL)
Output:
If this answer works for you I will make it more generic and give you so that you can apply this for any work like this.

Split/separate column into multiple columns

I'm completely stuck and I cannot find any answers for this problem even though problem seems to be quite simple. Can I separate that 'description' column without making a new table?
For now I just wrote this simplest code.
select item_id, description
from data
where item_id = '123'
With that code it looks like this:
item_id description
123 A
123 B
123 C
But I'd like to make it look like this:
item_id desc_1 desc_1 desc_2
123 A B C
Use conditional aggregation with the help of case expression
select item_id,
max(case when description= 'A' then description end) [desc_1],
max(case when description= 'B' then description end) [desc_2],
max(case when description= 'C' then description end) [desc_3],
from table
group by item_id
EDIT : So, the dynamic pivot way will look like as for SQL Server
declare #col varchar(max), #q varchar(max)
set #col = stuff(
(select distinct ','+quotename('desc_'+cast(row_number() over(partition by Item_id order by description) as varchar))
from table for xml path('')),
1,1,'')
set #q = 'select * from
(
select *,
''desc_''+cast(row_number() over(partition by Item_id order by description) as varchar) rn
from table
)a
PIVOT
(
max(description) for rn in ('+#col+')
)p'
EXEC (#Q)
Result :
item_id desc_1 desc_2 desc_3
123 A B C
234 B C d
first Declare Distinct column names
Like ABC, DEF,GHI
and values
then write dynamic pivot
DECLARE #COLS AS NVARCHAR(MAX)
DECLARE #query AS NVARCHAR(MAX)
SET #COLS=STUFF((select ',' + QUOTENAME(Course) from cst_coursedetails where programid=1 FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'),1,1,'')
SET #query =' SELECT * FROM(SELECT B.COLLCODE, B.COLLNAME,C.Course AS COURSE,D.ROLLNAME, E.ExamType, COUNT (A.HTNO) AS PRECOUNT FROM TableOne AS A
INNER JOIN TableTwo AS B ON A.COLLCODE=B.COLLCODE AND A.PROGRAMID=B.PROGRAMID
INNER JOIN TableThreee AS C ON C.CourseId=A.CourseId
INNER JOIN TableFour AS D ON D.ROLLID=A.ROLLID
INNER JOIN CST_EXAMTYPE AS E ON E.ExamTypeId=A.ExamTypeId
WHERE A.STATUSID !=17 AND a.ProgramId=1 AND A.ROLLID IN(1,2,3) AND A.EXAMTYPEID IN(1) GROUP BY B.COLLNAME,B.COLLCODE,C.Course,d.ROLLNAME ,E.ExamType
)SRC
PIVOT(
SUM(PRECOUNT) FOR COURSE IN('+#COLS+')
)AS PIV'
afs -- with clause name
giga -- alias name for listagg
with afs as
(
select item_id,LISTAGG(description, ',') WITHIN GROUP (ORDER BY item_id) AS
giga from test_jk group by item_id
)
select item_id,REGEXP_SUBSTR (giga, '[^,]+', 1, 1) AS
desc_1,REGEXP_SUBSTR (giga, '[^,]+', 1, 2) as desc_2 from afs;
output

Adding a WHERE statement refering another table in Dynamic SQL

I currently have the following script which is pivoting results from rows into columns. It works a Great, apart from two issues;
I have a flag in another table which I want to filter by (basically: WHERE Table.Stats=YES). I'd normally do this in a basic query with an inner join followed by that WHERE statement. In the query below, I already have a WHERE FileSeq=25, which works, but this criteria I need to get working is calling on a different table.
The query is returning a lot of uncessary NULL fields.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(col+CAST(rn AS varchar(6)))
FROM
(
SELECT row_number() over(partition by UID ORDER BY ClassCode) rn
FROM dbo.StudentClasses
) d
CROSS APPLY
(
SELECT 'ClassCode', 1
) c (col, so)
GROUP BY col, rn, so
ORDER BY rn, so
FOR XML PATH(''), TYPE
).VALUE('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT UID,' + #cols + '
FROM
(
SELECT UID, col+CAST(rn AS varchar(10)) col, VALUE
FROM
(
SELECT UID, classcode,
row_number() over(partition by UID ORDER BY classcode) rn
FROM StudentClasses WHERE FileSeq=25
) t
CROSS APPLY
(
SELECT ''classcode'', CAST(classcode AS varchar(6))
) c (col, VALUE)
) x
PIVOT
(
MAX(VALUE)
for col in (' + #cols + ')
) p '
EXECUTE(#query)
Any assistance appreciated

showing rows of table as columns based on some ID

I have a table like
ID option
1 optionA
1 optionB
1 optionC
1 optionD
And I want a result like:
ID A B C D
1 optionA optionB optionC optionD
What is the best way to do this?
Query which i have tried is
select * from TableName PIVOT (option for ID = 2674 )) as abc
this will not work since PIVOT expects aggregated function..
I have also tried COALESCE like this
declare #t table(num VARCHAR(100))
insert into #t
select choice FROM QuestionAnswers where QuestionID=2674
select num from #t
declare #s varchar(8000)
select #s = COALESCE(#s + ',', '') + num
from #t
exec('select '+#s)
but this doesn't work as well..
This type of data transformation is known as a pivot. In SQL Server 2005+ there is a function that will perform this data rotation for you. However, there are many ways that you can perform this data transformation.
Here is a PIVOT query that will work with your sample data:
select *
from
(
select id, [option], right([option], 1) col
from yourtable
) src
pivot
(
max([option])
for col in (a, b, c, d)
) piv
See SQL Fiddle with Demo.
This can also be performed using an aggregate function with a CASE expression:
select id,
max(case when col = 'a' then [option] else null end) a,
max(case when col = 'b' then [option] else null end) b,
max(case when col = 'c' then [option] else null end) c,
max(case when col = 'd' then [option] else null end) d
from
(
select id, [option], right([option], 1) col
from yourtable
) src
group by id
See SQL Fiddle with Demo.
You can perform multiple joins on your table:
select a.id,
a.[option] a,
b.[option] b,
c.[option] c,
d.[option] d
from yourtable a
left join yourtable b
on a.id = b.id
and right(b.[option], 1) = 'b'
left join yourtable c
on a.id = c.id
and right(c.[option], 1) = 'c'
left join yourtable d
on a.id = d.id
and right(d.[option], 1) = 'd'
where right(a.[option], 1) = 'a'
See SQL Fiddle with Demo
Lastly, this can be done using dynamic sql if the values to be turned into columns is unknown:
DECLARE #colsName AS NVARCHAR(MAX),
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #colsName = STUFF((SELECT distinct ', ' + QUOTENAME(right([option], 1)) +' as '+ right([option], 1)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #cols = STUFF((SELECT distinct ', ' + QUOTENAME(right([option], 1))
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT id, ' + #colsName + ' from
(
select id, [option], right([option], 1) col
from yourtable
) x
pivot
(
max([option])
for col in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo
The result of all queries is:
| ID | A | B | C | D |
----------------------------------------------
| 1 | optionA | optionB | optionC | optionD |
CREATE TABLE Product(Cust VARCHAR(25), Product VARCHAR(20), QTY INT)
GO
-- Inserting Data into Table
INSERT INTO Product(Cust, Product, QTY)
VALUES('KATE','VEG',2)
INSERT INTO Product(Cust, Product, QTY)
VALUES('KATE','SODA',6)
INSERT INTO Product(Cust, Product, QTY)
VALUES('KATE','MILK',1)
INSERT INTO Product(Cust, Product, QTY)
VALUES('KATE','BEER',12)
INSERT INTO Product(Cust, Product, QTY)
VALUES('FRED','MILK',3)
INSERT INTO Product(Cust, Product, QTY)
VALUES('FRED','BEER',24)
INSERT INTO Product(Cust, Product, QTY)
VALUES('KATE','VEG',3)
GO
-- Selecting and checking entires in table
SELECT *
FROM Product
GO
-- Pivot Table ordered by PRODUCT
SELECT PRODUCT, FRED, KATE
FROM (
SELECT CUST, PRODUCT, QTY
FROM Product) up
PIVOT (SUM(QTY) FOR CUST IN (FRED, KATE)) AS pvt
ORDER BY PRODUCT
GO
-- Pivot Table ordered by CUST
SELECT CUST, VEG, SODA, MILK, BEER, CHIPS
FROM (
SELECT CUST, PRODUCT, QTY
FROM Product) up
PIVOT (SUM(QTY) FOR PRODUCT IN (VEG, SODA, MILK, BEER, CHIPS)) AS pvt
ORDER BY CUST
GO
-- Unpivot Table ordered by CUST
SELECT CUST, PRODUCT, QTY
FROM
(
SELECT CUST, VEG, SODA, MILK, BEER, CHIPS
FROM (
SELECT CUST, PRODUCT, QTY
FROM Product) up
PIVOT
( SUM(QTY) FOR PRODUCT IN (VEG, SODA, MILK, BEER, CHIPS)) AS pvt) p
UNPIVOT
(QTY FOR PRODUCT IN (VEG, SODA, MILK, BEER, CHIPS)
) AS Unpvt
GO
-- Clean up database
DROP TABLE Product
GO
Ref http://blog.sqlauthority.com/2008/06/07/sql-server-pivot-and-unpivot-table-examples/
Edited
DECLARE #Product TABLE (ID int, _option varchar(10) )
-- Inserting Data into Table
INSERT INTO #Product
(
ID,
_option
)
SELECT 1, 'optionA' UNION ALL
SELECT 1, 'optionB' UNION ALL
SELECT 1, 'optionC' UNION ALL
SELECT 1, 'optionD'
SELECT
optionA, optionB, optionC, optionD
FROM (
SELECT ID, _option
FROM #Product) up
PIVOT (SUM(ID) FOR _option IN (optionA, optionB, optionC, optionD)) AS pvt

pivoting rows to columns in tsql

I have the following table with the following sample data
ID Language Question SubQuestion SubSubQuestion TotalCount TotalPercent
3 E 9 0 1 88527 73%
3 E 9 0 2 19684 16%
3 E 9 0 3 12960 11%
3 E 9 0 9 933 1%
I want all in one row like this
ID Language TotalCount901 TotalPercent901 TotalCount902 TotalPercent902 TotalCount903 TotalPercent903
3 E 88527 73% 19684 16% 12960 11%
I've tired using the pivot command, but it dosnt to work for me.
I made a few assumptions based on your column names, but it looks like you want to use something similar to this. This applies both an UNPIVOT and then a PIVOT to get the values in the columns you requested:
select *
from
(
select id,
language,
col + cast(QUESTION as varchar(10))
+cast(subquestion as varchar(10))
+cast(SubSubQuestion as varchar(10)) col,
value
from
(
select id, language,
cast(TotalCount as varchar(10)) TotalCount,
totalPercent,
question, subquestion, SubSubQuestion
from yourtable
) usrc
unpivot
(
value
for col in (totalcount, totalpercent)
) un
) srcpiv
pivot
(
max(value)
for col in ([TotalCount901], [totalPercent901],
[TotalCount902], [totalPercent902],
[TotalCount903], [totalPercent903],
[TotalCount909], [totalPercent909])
) p
See SQL Fiddle with Demo
Note: when performing the UNPIVOT the columns need to be of the same datatype. If they are not, then you will need to convert/cast to get the datatypes the same.
If you have an unknown number of values to transform, you can use dynamic sql:
DECLARE #query AS NVARCHAR(MAX),
#colsPivot as NVARCHAR(MAX)
select #colsPivot
= STUFF((SELECT ','
+ QUOTENAME(c.name +
cast(QUESTION as varchar(10))
+cast(subquestion as varchar(10))
+cast(SubSubQuestion as varchar(10)))
from yourtable t
cross apply sys.columns as C
where C.object_id = object_id('yourtable') and
C.name in ('TotalCount', 'TotalPercent')
group by c.name, t.question, t.subquestion, t.subsubquestion
order by t.SubSubQuestion
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'select *
from
(
select id,
language,
col + cast(QUESTION as varchar(10))
+cast(subquestion as varchar(10))
+cast(SubSubQuestion as varchar(10)) col,
value
from
(
select id, language,
cast(TotalCount as varchar(10)) TotalCount,
totalPercent,
question, subquestion, SubSubQuestion
from yourtable
) usrc
unpivot
(
value
for col in (totalcount, totalpercent)
) un
) srcpiv
pivot
(
max(value)
for col in (' + #colsPivot + ')
) p '
execute(#query)
See SQL Fiddle with Demo