SQL Query rows need to be converted to columns dynamically - sql

Please help me to solve my below query -
I have the following data in my table-
Agent Variable Chandigarh NewDelhi
ABC Leads 102.00 10
ABC TotalTime 10.52 1
ABC RPH 22.79 22
ABC TotalRev 239.70 23
XYZ Leads 14.00 14
XYZ TotalTime 1.52 1
XYZ RPH 21.64 21
XYZ TotalRev 32.90 32
I want the solution like this
Agent Chandigarh_Leads Chandigarh_TotalTime Chandigarh_RPH Chandigarh_RPH_TotalRev NewDelhi_Leads .......
ABC 102.00 10.52 22.79 239.70 10 .......
XYZ 14 1.52 21.64 32.90 14 ............
FYI, I can have more states in columns, it has no limits it may be 10 or 20 or 5 etc. So i need result dynamic query. Please help me, is it possible without static query?

Dynamic SQL + pivoting:
DECLARE #sql nvarchar(max),
#columns nvarchar(max),
#col_to_cast nvarchar(max),
#col_unpvt nvarchar(max)
--This will give:
--,[Chandigarh_Leads],[Chandigarh_RPH]....[NewDelhi_TotalRev],[NewDelhi_TotalTime]
SELECT #columns = COALESCE(#columns,'')+',['+name+'_'+Variable +']'
FROM (
SELECT DISTINCT Variable
FROM #yourtable) v
CROSS JOIN (
SELECT name
FROM sys.columns
WHERE object_id = OBJECT_ID(N'#yourtable')
AND name not in ('Agent', 'Variable')
) c
ORDER BY c.name, v.Variable
--As columns while unpivoting must be same type we need to cast them in same datattype:
--This will give
--,CAST([Chandigarh] as float) as [Chandigarh],CAST([NewDelhi] as float) as [NewDelhi]
SELECT #col_to_cast = COALESCE(#col_to_cast,'')+',CAST(' + QUOTENAME(name)+ ' as float) as '+ QUOTENAME(name)
#col_unpvt = COALESCE(#col_unpvt,'') + ','+ QUOTENAME(name)
FROM sys.columns
WHERE object_id = OBJECT_ID(N'#yourtable')
AND name not in ('Agent', 'Variable')
SELECT #sql = N'
SELECT *
FROM (
SELECT Agent,
[Columns]+''_''+Variable as ColName,
[Values] as ColVal
FROM (
SELECT Agent,
Variable'+#col_to_cast+'
FROM #yourtable
) p
UNPIVOT (
[Values] FOR [Columns] IN ('+STUFF(#col_unpvt,1,1,'')+')
) unpvt
) t
PIVOT (
MAX(ColVal) FOR ColName IN ('+STUFF(#columns,1,1,'')+')
) pvt'
EXEC sp_executesql #sql
Output:
Agent Chandigarh_Leads Chandigarh_RPH Chandigarh_TotalRev Chandigarh_TotalTime NewDelhi_Leads NewDelhi_RPH NewDelhi_TotalRev NewDelhi_TotalTime
ABC 102 22,79 239,7 10,52 10 22 23 1
XYZ 14 21,64 32,9 1,52 14 21 32 1

Related

How to use pivot function in sql server?

I have a table like this:
Factory indexcode grade
200 1 95
200 2 100
5000 1 85
5000 3 90
How can I get this result?
Factory. 1 2 3
200 95 100 -
5000 85 - 90
The indexcode varies between 1 to 6.
You can try below -
select factorycode,pv.*
from tablename
pivot
(max(grade) for indexcode in ([1],[2],[3])) as pv
If your indexcodes are fixed (1-6) in that case you can use following PIVOT query.
SELECT *
FROM TABLE_NAME
PIVOT ( Max(grade)
FOR indexcode IN ( [1], [2], [3],[4],[5],[6]) ) pvt
If your index code values are not fixed and can take any value, in that case you can go for dynamic pivot like following.
DECLARE #cols AS NVARCHAR(max) = Stuff((SELECT DISTINCT ', ' + Quotename(indexcode)
FROM TABLE_NAME
FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1, '');
DECLARE #query AS NVARCHAR(max) = ' SELECT *
FROM TABLE_NAME
PIVOT ( max(grade)
FOR indexcode IN ('+#cols+') ) pvt';
EXECUTE(#query)
DEMO

Group Columns based on Row ID

I have a table pulling data, like:
ID FID Value
001 20 200
001 20 400
001 50 600
002 50 100
How do write a query to get a column for each row ID that would sum the Value's?
For example, I want to return the following:
ID 20 50
001 600 600
002 NULL 100
A pattern like this:
SELECT
ID,
SUM(CASE WHEN FID = 20 THEN Value END) as sum20,
SUM(CASE WHEN FID = 50 THEN Value END) as sum50 --extend by adding more CASE WHEN rows
FROM
table
GROUP BY ID
..has the advantage of working in databases that don't support PIVOT syntax.
If you'd like PIVOT syntax:
SELECT ID, [20], [50] --extend by providing more values in square brackets
FROM
table
PIVOT
(
SUM(Value)
FOR FID IN ([20], [50]) --extend by providing more values in square brackets
) pvt
If you have dynamic list of FID's you can use dynamic query as below:
Declare #cols1 varchar(max)
Declare #query nvarchar(max)
Select #cols1 = stuff((select Distinct ','+QuoteName(Fid) from #data for xml path('')),1,1,'')
Set #query = ' Select * from (
Select Id, [Fid], [Value] from #data ) a
pivot (sum([Value]) for [Fid] in (' + #cols1 + ') ) p '
Exec sp_executesql #query

Write a query to count different kind of records in single line result

I have a table with 2 columns TimeStamp and ID in MS SQLSERVER
TimeStamp ID
2015-05-20 1
2015-05-20 2
2015-05-20 1
2015-05-21 1
2015-05-21 2
2015-05-21 2
2015-05-21 1
My requirement is to calculate number of records for every Id according to date.
Requirement:
Date No of records for Id=1 No. records for ID=2 Total
2015-05-20 2 1 3
2015-05-21 2 2 4
Please let me know how can i do this for other columns as well.
Thanks
Using Pivot - can look like this:
SELECT [TimeStamp], [1] AS [No of records for Id=1], [2] AS [No of records for Id=2], [1]+[2] AS Total
FROM dbo.YourTable
PIVOT
(
COUNT(ID) FOR ID IN ([1],[2])
) pvt
ORDER BY [TimeStamp]
For completion the Dynamic Way:
DECLARE #id_values NVARCHAR(MAX)
DECLARE #stmt NVARCHAR(MAX)
SET #id_values = ''
SET #stmt = ''
--Get List of ID's
SELECT #id_values = #id_values + ',[' + CAST(ID AS VARCHAR) + ']'
FROM dbo.YourTable
GROUP BY ID
SET #id_values = RIGHT(#id_values, LEN(#id_values)-1) --Remove Leading Comma
--Build PIVOT Statement
SET #stmt = 'SELECT [TimeStamp],' + #id_values + ','+ REPLACE(#id_values,',','+') + ' AS Total
FROM dbo.YourTable
PIVOT
(
COUNT(ID) FOR ID IN (' + #id_values + ')
) pvt
ORDER BY [TimeStamp]'
--Execute
EXEC sp_executesql #stmt
I've got your answer using subqueries:
SQLFIDDLE: http://sqlfiddle.com/#!3/8c28c/5
SELECT DISTINCT t1.myts,
(SELECT COUNT(*)
FROM mytable t2
WHERE t2.myts = t1.myts
AND t2.id = 1) AS id_1_count,
(SELECT COUNT(*)
FROM mytable t2
WHERE t2.myts = t1.myts
AND t2.id = 2) AS id_2_count,
(SELECT COUNT(*)
FROM mytable t2
WHERE t2.myts = t1.myts) AS total
FROM mytable t1
If you add an id here though you would need another subquery

Converting column values (rows) to columns and aggregate count on two rows of two different tables

I have two tables
Program
Student
Student:
Name Status1 Syear SCode
--------------------
kk A 2000 1
ra A 2001 2
Paras L 2000 2
Prit L 2001 2
Poot A 2002 4
Program:
PName PCode
--------------------
Msc 1
DC 2
PO 4
Join on ID
Required output :
SELECT *
FROM
(SELECT
Program.PName AS v, Status1
FROM
Student, Program
WHERE
Student.PCode = SCode
GROUP BY
Program.PName, Student.Syear, Status1) AS src
pivot
(
count(v)
FOR Status1 IN ([A],)
) as piv
It does not display PNAME in output
A L
-----------
1 0
1 2
1 0
Desired output
PNAME A L
-----------
Msc 1 0
DC 1 2
PO 1 0
1. STATIC PIVOT
You can do this if the column names is known in advance
SELECT PName,ISNULL([A],0) [A],ISNULL([L],0)[L] FROM
(
-- Source data for pivoting
SELECT P.PName,Status1,
COUNT(Status1)OVER(PARTITION BY PNAME,Status1)CNT
FROM #PROGRAM P
JOIN #Student S ON P.PCODE=S.SCODE
) x
PIVOT
(
--Defines the values in each dynamic columns
MIN(CNT)
-- Get the names of columns to pivot
FOR Status1 IN ([A],[L])
) p
ORDER BY PName
Click here to view result
2. DYNAMIC PIVOT
Dynamic pivoting can be done if the number of columns is not known in advance.
First of all get columns dynamically to pivot
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + Status1 + ']', '[' + Status1 + ']')
FROM (SELECT DISTINCT Status1 FROM #Student) PV
ORDER BY Status1
Now the below variable is used to replace NULL with zero.
DECLARE #NulltoZeroCols NVARCHAR (MAX)
SELECT #NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+Status1+'],0) AS ['+Status1+']'
FROM (SELECT DISTINCT Status1 FROM #Student)TAB
ORDER BY Status1 FOR XML PATH('')),2,8000)
Now pivot it. I have written the logic inside
DECLARE #query NVARCHAR(MAX)
SET #query = '-- This outer query forms your pivoted result
SELECT PName,'+#NullToZeroCols+' FROM
(
-- Source data for pivoting
SELECT P.PName,Status1,
COUNT(Status1)OVER(PARTITION BY PNAME,Status1)CNT
FROM #PROGRAM P
JOIN #Student S ON P.PCODE=S.SCODE
) x
PIVOT
(
--Defines the values in each dynamic columns
MIN(CNT)
-- Get the names from the #cols variable to show as column
FOR Status1 IN (' + #cols + ')
) p
ORDER BY PName;'
EXEC SP_EXECUTESQL #query
Click here to view result

Pivot a resultset (rows to columns)

Consider the following #table:
guid field value
--------------------
123 A foo
123 B foobar
123 C 123
234 A bar;baz
234 B 3464
345 A foobaz
I need to transpose / pivot this into the following #table2:
guid A B C
---------------------------
123 foo foobar 123
234 bar;baz 3464 -
345 foobaz - -
In other words: the guid needs to stay the table key but all the fields need to be transposed into columns.
Is this possible in SQL Server?
Usually, I would use a server-side (php, python, asp) script to pull #table from the database and transpose the resultset by iterating to the resultset as an array but this is not an option in this case. I need a sql-only solution.
Any help would be greatly appreciated.
This should pivot your data and will keep your GUID.
select tbl.guid, tbl.[A], tbl.[B], tbl.[C] from (
select * from (
select guid, field, value
from #table
) t
pivot (
max(value) for field in ([A],[B],[C])
) p
) tbl
Creating your columns in preparation for the dynamic SQL:
declare #columns nvarchar(max) = (select stuff((
select distinct ',[' + t.field + ']'
from #table t
for xml path('')
),1,1,''))
Mixing the columns into the dynamic SQL:
declare #sql = N'
select tbl.guid, ' + #columns + ' from (
select * from (
select guid, field, value
from #table
) t
pivot (
max(value) for field in (' + #columns + ')
) p
) tbl'
And execute:
execute (#sql)