I have a table ProductTransDetailPassenger the structure is
PID FirstName Email Phone NoOfAdult NoOfChild
1 ABC x#.com 111 2 0
1 XYZ y#.com 222 2 0
2 QWE z#.com 333 2 1
2 RTY c#.com 444 2 1
2 YUI v#.com 555 2 1
Based on the traveler Count(i.e No.OfAdult + No.OfChild) I need to display the result as
PID FirstName-1 Email-1 Phone-1 FirstName-2 Email-2 Phone-2 FirstName-3 Email-3 Phone-3
1 ABC x#.com 111 XYZ y#.com 222 N/A N/A N/A
2 QWE z#.com 333 RTY c#.com 444 YUI v#.com 555
The table may change dynamically according to the max number of travelers. For an PID with less number of travelers than the Max, the remaining columns need to be displayed as N/A
Can u please help me out with this!!
I have tried this implementation using the PIVOT, but the result is not as expected
Thanks in Advance,
The SQL Snippet
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT distinct + char(10) + QUOTENAME(PTDP.FirstName) --+ QUOTENAME(AP.Type) + QUOTENAME(PTDP.EmailAddress) + QUOTENAME(PTDP.PhoneNumber) + QUOTENAME(DAY(GETDATE() - PTDP.Birthdate))
FROM ProductTransactionDetailPassenger PTDP
INNER JOIN AppParameters AP ON AP.EnumValue = PTDP.GenderTypeValue AND Ap.Context = 'Gender'
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = N'SELECT ' + #cols + ' from
(
select
PTDP.ProductTransactionDetailID PID,
PTDE.ProductTransactionDetailID ID
from ProductTransactionDetailPassenger PTDP
inner join ProductTransactionDetail PTD
on PTD.ProductTransactionDetailID=PTDP.ProductTransactionDetailID
and PTD.ParentProductTransactionDetailID=00000000-0000-0000-0000-000000000000
INNER JOIN dbo.ProductTransactionDetailExtended PTDE ON PTDE.ProductTransactionDetailID = PTD.ProductTransactionDetailID
) x
pivot
(
max(x.PID) //this must be traveler count
for ' + #cols + ' in (' + #cols + ')
) p '
print #query
execute(#query)
Ref:
Pivot Dynamic Columns, no Aggregation
The query below should get you the desired results:
DECLARE #Temp TABLE
(
PID int,
PIDROW int,
FirstName varchar(25),
Email varchar(25),
Phone varchar(25)
)
INSERT INTO #Temp
SELECT
PID,
DENSE_RANK() OVER (PARTITION BY PID ORDER BY PID,FirstName) PIDROW,
FirstName,
Email,
Phone
from [dbo].[ProductTransDetailPassenger];
WITH FirstName AS
(
SELECT PID,
[1], [2], [3], [4]
FROM
(SELECT PIDROW, FirstName, PID
FROM #Temp) AS SourceTable
PIVOT
(
MAX(FirstName)
FOR PIDROW IN ([1], [2], [3], [4])
) AS PivotTable
),
Email As
(
SELECT PID,
[1], [2], [3] , [4]
FROM
(SELECT PIDROW, Email, PID
FROM #Temp) AS SourceTable
PIVOT
(
MAX(Email)
FOR PIDROW IN ([1], [2], [3], [4])
) AS PivotTable
),
Phone As
(
SELECT PID,
[1], [2], [3] , [4]
FROM
(SELECT PIDROW, Phone, PID
FROM #Temp) AS SourceTable
PIVOT
(
MAX(Phone)
FOR PIDROW IN ([1], [2], [3], [4])
) AS PivotTable
)
SELECT
f.[1] AS 'FirstName-1',
e.[1] AS 'Email-1',
p.[1] AS 'Phone-1',
f.[2] AS 'FirstName-2',
e.[2] AS 'Email-2',
p.[2] AS 'Phone-2',
f.[3] AS 'FirstName-3',
e.[3] AS 'Email-3',
p.[3] AS 'Phone-3'
FROM FirstName f
JOIN Email e on f.PID = e.PID
JOIN Phone p on f.PID = p.PID
Please don't do this. You are destroying the table as a relational table, it will be very hard to do SQL queries against the table and you will have many, many null values. You have to create another table with the id, email and phone.
Related
I am using SQL Server. I created a query:
SELECT
p.[accountNumber],
pf.fundid
FROM
[dbo].[Property] p
LEFT JOIN
dbo.propertyfundassessment pf ON p.id = pf.propertyid
LEFT JOIN
dbo.fund f ON pf.fundid = f.id
WHERE
p.accountnumber = '238492348' AND p.taxyear = 2018
This shows the data as:
accountNumber fundid
--------------------------
1 238492348 1004
2 238492348 1005
3 238492348 1006
4 238492348 1007
5 238492348 1008
6 238492348 1009
7 238492348 1022
8 238492348 1339
I am trying to some how pivot the table in order to make the table look like this instead:
accountNumber adv1 adv2 adv3 adv4 adv5 adv6 adv7 adv8
-----------------------------------------------------------------
1 238492348 1004 1005 1006 1007 1008 1009 1022 1339
Can someone assist me in how I can do this with SQL Server?
I have found this:
SELECT *
FROM
(SELECT ColNbr = ROW_NUMBER() OVER(PARTITION BY accountNUmber ORDER BY fundid,accountNumber)
,accountNumber
,fundid
FROM
#tmpS a
) src PIVOT(MAX(src.fundid) FOR src.ColNbr IN( [1]
,[2]
,[3]
,[4]
,[5]
,[6]
,[7]
,[8]
,[9]
,[10]
,[11]
,[12]
,[13]
,[14]
,[15]
,[16]
,[17]
,[18]
,[19]
,[20]
,[21]
,[22]
,[23]
,[24]
,[25]
)) pvt
And I am trying to combine the two queries to have it do it on the fly. Instead of trying to create a #tmpS table.
Any help would be greatly appreciated!
You can combine both queries like the following:
;WITH StartingData AS
(
SELECT
[accountNumber] = p.[accountNumber],
fundid = pf.fundid,
FundRanking = ROW_NUMBER() OVER (PARTITION BY p.[accountNumber] ORDER BY pf.fundid ASC) -- The order by is crucial for the pivot ordering later
FROM
[dbo].[Property] p
left join dbo.propertyfundassessment pf on p.id = pf.propertyid
left join dbo.fund f on pf.fundid = f.id
where
p.taxyear = 2018
)
SELECT
P.accountNumber,
P.[1],
P.[2],
P.[3],
P.[4],
P.[5],
P.[6],
P.[7],
P.[8],
P.[9],
P.[10],
P.[11],
P.[12],
P.[13],
P.[14],
P.[15],
P.[16],
P.[17],
P.[18],
P.[19],
P.[20],
P.[21],
P.[22],
P.[23],
P.[24],
P.[25]
FROM
StartingData AS S
PIVOT (
MAX(S.fundid) FOR S.FundRanking IN (
[1], [2], [3], [4], [5], [6], [7], [8], [9], [10],
[11], [12], [13], [14], [15], [16], [17], [18],
[19], [20], [21], [22], [23], [24], [25])
) AS P
Keep in mind what Tim said, either you hard-code the number of fundid you will be pivoting (this example hard-codes from 1 to 25), or you will have to use dynamic SQL to generate a pivot statement that dynamically pivots up to the max amount of fundid you might have to a particular accountNumber. This will generate a column for each inicial record, by accountNumber.
To make it dynamic use the following:
IF OBJECT_ID('tempdb..#AccountFunds') IS NOT NULL
DROP TABLE #AccountFunds
SELECT
[accountNumber] = p.[accountNumber],
fundid = pf.fundid,
FundRanking = ROW_NUMBER() OVER (PARTITION BY p.[accountNumber] ORDER BY pf.fundid ASC) -- The order by is crucial for the pivot ordering later
INTO
#AccountFunds
FROM
[dbo].[Property] p
left join dbo.propertyfundassessment pf on p.id = pf.propertyid
left join dbo.fund f on pf.fundid = f.id
where
p.taxyear = 2018
AND p.[accountNumber] = '238492348'
DECLARE #PivotValues VARCHAR(MAX) = STUFF (
(
SELECT DISTINCT
',' + QUOTENAME(CONVERT(VARCHAR(10), A.FundRanking))
FROM
#AccountFunds AS A
ORDER BY
',' + QUOTENAME(CONVERT(VARCHAR(10), A.FundRanking)) ASC
FOR XML
PATH ('')
),
1, 1, '')
DECLARE #SelectColumnAlias VARCHAR(MAX) = STUFF (
(
SELECT
',P.' + QUOTENAME(CONVERT(VARCHAR(10), A.FundRanking)) + ' AS adv' + CONVERT(VARCHAR(10), A.FundRanking)
FROM
#AccountFunds AS A
GROUP BY
A.FundRanking
ORDER BY
A.FundRanking ASC
FOR XML
PATH ('')
),
1, 1, '')
DECLARE #DynamicSQL VARCHAR(MAX) = '
SELECT
P.AccountNumber,
' + #SelectColumnAlias + '
FROM
#AccountFunds AS A
PIVOT (
MAX(A.fundid) FOR A.FundRanking IN (
' + #PivotValues + ')
) AS P '
--PRINT (#DynamicSQL) -- Use Print to check the query
EXEC (#DynamicSQL)
If you check the value of #PivotValues it's something like the following:
[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23],[24],[25]
The value of #SelectColumnAlias is:
P.[1] AS adv1,P.[2] AS adv2,P.[3] AS adv3,P.[4] AS adv4,P.[5] AS adv5,P.[6] AS adv6,P.[7] AS adv7,P.[8] AS adv8,P.[9] AS adv9,P.[10] AS adv10,P.[11] AS adv11,P.[12] AS adv12,P.[13] AS adv13,P.[14] AS adv14,P.[15] AS adv15,P.[16] AS adv16,P.[17] AS adv17,P.[18] AS adv18,P.[19] AS adv19,P.[20] AS adv20,P.[21] AS adv21,P.[22] AS adv22,P.[23] AS adv23,P.[24] AS adv24,P.[25] AS adv25
And finally the full expression:
SELECT
P.AccountNumber,
P.[1] AS adv1,P.[2] AS adv2,P.[3] AS adv3,P.[4] AS adv4,P.[5] AS adv5,P.[6] AS adv6,P.[7] AS adv7,P.[8] AS adv8,P.[9] AS adv9,P.[10] AS adv10,P.[11] AS adv11,P.[12] AS adv12,P.[13] AS adv13,P.[14] AS adv14,P.[15] AS adv15,P.[16] AS adv16,P.[17] AS adv17,P.[18] AS adv18,P.[19] AS adv19,P.[20] AS adv20,P.[21] AS adv21,P.[22] AS adv22,P.[23] AS adv23,P.[24] AS adv24,P.[25] AS adv25
FROM
#AccountFunds AS A
PIVOT (
MAX(A.fundid) FOR A.FundRanking IN (
[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23],[24],[25])
) AS P
Try this dynamic sql
IF OBJECT_ID('Tempdb..#temp')IS NOT NULL
DROP TABLE #temp
;WITH CTE(Id,accountNumber,fundid)
AS
(
SELECT 1,238492348,1004 UNION ALL
SELECT 2,238492348,1005 UNION ALL
SELECT 3,238492348,1006 UNION ALL
SELECT 4,238492348,1007 UNION ALL
SELECT 5,238492348,1008 UNION ALL
SELECT 6,238492348,1009 UNION ALL
SELECT 7,238492348,1022 UNION ALL
SELECT 8,238492348,1339
)
SELECT * ,'adv'+CAST(ROW_NUMBER()OVER(ORDER BY (SELECT 1)) AS VARCHAR(10)) AS tcol INTO #temp FROM CTE
DECLARE #Columns nvarchar(max),#IsnullColumns nvarchar(max)
,#Sql nvarchar(max)
SELECT #Columns= STUFF((SELECT ', '+tcol FROM #temp FOR XML PATH ('')),1,1,'')
SELECT #IsnullColumns=STUFF((SELECT ', '+'MAX('+QUOTENAME(tcol)+') AS ' +QUOTENAME(tcol) FROM #temp FOR XML PATH ('')),1,1,'')
SET #Sql='
SELECT accountNumber ,'+#IsnullColumns+'
FROM
(SELECT * FROM #temp
) AS SRC
PIVOT
(MAX(fundid) FOR tcol IN ('+#Columns+')
) AS PVT
GROUP BY accountNumber'
PRINT #Sql
EXEC (#Sql)
Result
accountNumber adv1 adv2 adv3 adv4 adv5 adv6 adv7 adv8
-----------------------------------------------------------------
238492348 1004 1005 1006 1007 1008 1009 1022 1339
Hi I have data like Below for example.
Table1:
id name
1 ab cd ef
2 john isner novak
3 roger federer murray
4 rafeal nadal grigor dmitrov
I need output as below
id pairs
1 ab cd
2 cd ef
3 john isner
4 isner novak
5 roger federer
6 federer murray
7 rafeal nadal
8 nadal grigor
9 grigor dmitrov
I have tried my best to do this and below is my code. I am new to functions and stored procedures in sql server so not familiar with it. Please help me with the code and also give me a brief about it.
CREATE TABLE YOURTABLE AS SELECT * FROM
(
SELECT PARTDESC,
CASE WHEN WORD2 IS NOT NULL THEN WORD1||' '||WORD2 END AS WORD1WORD2,
CASE WHEN WORD3 IS NOT NULL THEN WORD2||' '||WORD3 END AS WORD2WORD3,
CASE WHEN WORD3 IS NOT NULL THEN WORD3||' '||WORD4 END AS WORD3WORD4
FROM
(
SELECT PARTDESC,
REVERSE(PARSENAME(REPLACE(REVERSE(NAME), ' ', '.'), 1)) AS WORD1,
REVERSE(PARSENAME(REPLACE(REVERSE(NAME), ' ', '.'), 2)) AS WORD2,
REVERSE(PARSENAME(REPLACE(REVERSE(NAME), ' ', '.'), 3)) AS WORD3,
REVERSE(PARSENAME(REPLACE(REVERSE(NAME), ' ', '.'), 4)) AS WORD4
FROM
Table1
) A
) B
--------------------
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 <> 'PARTDESC'
for xml path('')), 1, 1, '')
select #colsPivot = STUFF((SELECT ','
+ quotename(PARTDESC)
from yourtable t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query
= 'select name, '+#colsPivot+'
from
(
select PARTDESC, name, value
from yourtable
unpivot
(
value for name in ('+#colsUnpivot+')
) unpiv
) src
pivot
(
max(value)
for PARTDESC in ('+#colsPivot+')
) piv'
exec(#query)
---------------
After running the above query i need to pick evry column---one column at a time and then append using union all..This is pretty much difficult task
Please help me through this...
It is possible to make this more simple and avoid dynamic sql:
DECLARE #t table(id int identity(1,1), name varchar(100))
INSERT #t VALUES
('ab cd ef'),
('john isner novak'),
('roger federer murray'),
('rafeal nadal grigor dmitrov')
;WITH CTE AS
(
SELECT row_number() over(order by id) rn,id,t.c.value('.', 'VARCHAR(2000)') splitname
FROM (
SELECT id, x = CAST('<t>' +
REPLACE(name, ' ', '</t><t>') + '</t>' AS XML)
FROM #t
) a
CROSS APPLY x.nodes('/t') t(c)
)
SELECT
row_number() over(order by cte1.id) id,
cte1.splitname + ' '+ cte2.splitname name
FROM CTE cte1
JOIN CTE cte2 ON cte1.id = cte2.id and cte1.rn + 1 = cte2.rn
Result:
id name
1 ab cd
2 cd ef
3 john isner
4 isner novak
5 roger federer
6 federer murray
7 rafeal nadal
8 nadal grigor
9 grigor dmitrov
I apologize for my ignorance. I just am not familiar with pivot queries AT ALL and all the examples I find seem about as clear as mud. I have table that returns GroupName and ID Numbers.
For Example:
SELECT GroupName, IDnumber FROM do.Table_1
Returns
GroupName IDnumber
1 8395
1 A660
1 8396
1 A661
2 8398
2 A662
2 8399
What I want is something more like this:
GroupName ID1 ID2 ID3 ID4
1 8395 A660 8396 A661
2 8398 A662 8399 NULL
How can I do this? Pivot query? Some other method?
I am open to suggestion and appreciate any help you could provide.
Yes, you can do it using PIVOT but not in this shape, you have firstly to generate a row number to use it to format the data in the way you want. Something like this:
WITH Ranked
AS
(
SELECT GroupName, IDnumber,
ROW_NUMBER() OVER(PARTITION BY GroupName ORDER BY GroupName) AS RN
FROM Table1
)
SELECT GroupName,
[1] AS ID1, [2] AS ID2, [3] AS ID3, [4] AS ID4
FROM Ranked AS r
PIVOT
(
MAX(IDnumber)
FOR RN IN([1], [2], [3], [4])
) AS p;
SQL Fiddle Demo
This will give you:
| GROUPNAME | ID1 | ID2 | ID3 | ID4 |
|-----------|------|------|------|--------|
| 1 | 8395 | A660 | 8396 | A661 |
| 2 | 8398 | A662 | 8399 | (null) |
If you want to do it dynamically and not to write the row number by hand in the pivot table operator, you have to do it using dynamic SQL, something like:
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #colnames AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
SELECT #cols = STUFF((SELECT distinct ',' +
QUOTENAME(RN)
FROM
(
SELECT ROW_NUMBER() OVER(PARTITION BY GroupName ORDER BY GroupName) AS RN
FROM Table1
) AS t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT #colnames = STUFF((SELECT distinct ',' +
QUOTENAME(RN) + 'AS' +
QUOTENAME('ID' + CAST(RN AS NVARCHAR(5)))
FROM
(
SELECT ROW_NUMBER() OVER(PARTITION BY GroupName ORDER BY GroupName) AS RN
FROM Table1
) AS t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT #query = 'WITH Ranked
AS
(
SELECT GroupName, IDnumber,
ROW_NUMBER() OVER(PARTITION BY GroupName ORDER BY GroupName) AS RN
FROM Table1
)
SELECT GroupName, ' + #colnames +
' FROM Ranked AS r
PIVOT
(
MAX(IDnumber)
FOR RN IN(' + #cols + ')' +
') p';
execute(#query);
SQL Fiddle Demo
This should give you the same result:
| GROUPNAME | ID1 | ID2 | ID3 | ID4 |
|-----------|------|------|------|--------|
| 1 | 8395 | A660 | 8396 | A661 |
| 2 | 8398 | A662 | 8399 | (null) |
You may need to use dynamic pivoting since the Id will be dynamic. Here is your sample table
SELECT * INTO #TEMP
FROM
(
SELECT 1 GroupName, '8395' IDnumber
UNION ALL
SELECT 1, 'A660'
UNION ALL
SELECT 1, '8396'
UNION ALL
SELECT 1, 'A661'
UNION ALL
SELECT 2, '8398'
UNION ALL
SELECT 2, 'A662'
UNION ALL
SELECT 2, '8399'
)TAB
Select row number over each Groupname and insert into a temporary table so that it can be used for both selecting the columns for pivoting and inside the pivot
SELECT *,
'ID' + CAST(ROW_NUMBER() OVER(PARTITION BY GroupName ORDER BY GROUPNAME) AS VARCHAR(10)) IDS
INTO #NEWTABLE
FROM #TEMP
Select columns for pivot
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + IDS + ']',
'[' + IDS + ']')
FROM (SELECT DISTINCT IDS FROM #NEWTABLE) PV
ORDER BY IDS
Now pivot dynamically
DECLARE #query NVARCHAR(MAX)
SET #query = '
SELECT * FROM
(
SELECT * FROM #NEWTABLE
) x
PIVOT
(
MAX(IDnumber)
FOR IDS IN (' + #cols + ')
) p
'
EXEC SP_EXECUTESQL #query
Click here to view the result (incase an error is occured on loading page press RUNSQL, it works)
RESULT
How could I put those multiple rows into one line, and the contents are in different columns:
From:
ID | Subject1/Catalog/Session
10868952 | NUR/3110/D507
10868952 | NUR/3110/D512
10868952 | NUR/4010/D523
10868952 | NUR/4010/HD20
To
ID |Subject1/Catalog/Session |Subject2/Catalog/Session | Subject3/Catalog/Session |Subject4/Catalog/Session | Subject5/Catalog/Session
10868952 |NUR/3110/D507 | NUR/3110/D512 | NUR/4010/D523 | NUR/4010/HD20 |
Would be best if in the future you can provide ddl and sample data. I did this for you this time.
Here is how you could do this if you know the number of elements per row. I put links in the comments of the original post to both the static and dynamic versions of this type of approach.
if OBJECT_ID('tempdb..#Something') is not null
drop table #Something
create table #Something
(
ID int,
Subject1 varchar(50)
)
insert #Something
select 10868952, 'NUR/3110/D507' union all
select 10868952, 'NUR/3110/D512' union all
select 10868952, 'NUR/4010/D523' union all
select 10868952, 'NUR/4010/HD20';
with OrderedResults as
(
select *, ROW_NUMBER() over(partition by ID order by Subject1) as RowNum
from #Something
)
select ID
, MAX(Case when RowNum = 1 then Subject1 end) as Subject1
, MAX(Case when RowNum = 2 then Subject1 end) as Subject2
, MAX(Case when RowNum = 3 then Subject1 end) as Subject3
, MAX(Case when RowNum = 4 then Subject1 end) as Subject4
from OrderedResults
group by ID
Here is how you can do this as a dynamic pivot. There are a number of concepts going on here. One is a tally table. In this code it is implemented as a cte. In my actual system I have this as a view. It generates 10,000 rows with zero reads. The tally table and most of the other concepts here were learned by the immortal Jeff Moden. If you do not know what a tally table is or how they work, check out Jeff's article here. http://www.sqlservercentral.com/articles/T-SQL/62867/
I will post some code for how to do this for this example but anybody who is unfamiliar with this technique should read his article. http://www.sqlservercentral.com/articles/Crosstab/65048/
Here is a full working example of doing this as a dynamic cross tab. When you are satisfied that the sql this generates is safe feel free to uncomment the last two lines.
LAST but certainly not least. Make sure that you fully understand what this code and how it works. It is not going to be my phone that rings at 3am when something goes wrong. You are the one who will have to be there to support this code.
if OBJECT_ID('Something') is not null
drop table Something
create table Something
(
ID int,
Subject1 varchar(50)
)
insert Something
select 10868952, 'NUR/3110/D507' union all
select 10868952, 'NUR/3110/D512' union all
select 10868952, 'NUR/4010/D523' union all
select 10868952, 'NUR/4010/HD20' union all
select 12345, 'asdfasdf'
declare #MaxCols int
declare #StaticPortion nvarchar(2000) =
'with OrderedResults as
(
select *, ROW_NUMBER() over(partition by ID order by Subject1) as RowNum
from Something
)
select ID';
declare #DynamicPortion nvarchar(max) = '';
declare #FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by ID order by ID';
with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select #DynamicPortion = #DynamicPortion +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then Subject1 end) as Subject' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <=
(
select top 1 Count(*)
from Something
group by ID
order by COUNT(*) desc
)
select #StaticPortion + #DynamicPortion + #FinalStaticPortion
--declare #SqlToExecute nvarchar(max) = #StaticPortion + #DynamicPortion + #FinalStaticPortion;
--exec sp_executesql #SqlToExecute
I have a following table:
State LAB GROUP DATE CODE ID
UP A I 1-Jan 1 345
UP R S 1-Feb 1 456
UP A S 1-Jan 2 567
DL R S 1-Feb 3 678
DL T S 1-Jan 1 789
DL A S 1-Jan 2 900
MN T S 1-Jan 3 1011
MN R I 1-Feb 1 1122
MN S I 1-Feb 2 1233
I need a pivot table of following type:
STATE A R T TOTAL
UP 2 1 0 3
DL 1 1 1 3
MN 0 1 1 2
DISTINCT COUNT OF ID FOR EACH LAB FOR EACH STATE.
I then need the pivot tables filtered for following columns:
GROUP
DATE
CODE
So 1st table will have the pivot table above counting only those records which have GROUP=S
2nd table will have the pivot table above counting only those records which have CODE=1
and so on, I wish to put multiple conditions. and generate several tables one by one and export them.
If this is possible in SQL please let me know! I ruled out excel vba due to the size of table (source table will have 800,000 records approx).
Try this :-
Select [State],[A],[R],[T],Total = [A] + [R]+ [T]
from
(
Select [State],
[A] = Sum(Case when LAB='A' then 1 else 0 END) ,
[R] = Sum(Case when LAB='R' then 1 else 0 END) ,
[T] = Sum(Case when LAB='T' then 1 else 0 END)
from YourTable
group by [State]
)a
SQL FIDDLE
CREATE TABLE #t(States VARCHAR(10),LAB VARCHAR(5),GROUPs VARCHAR(5),DATEs VARCHAR(10),CODE INT,ID INT)
INSERT INTO #t values('UP','A','I','1-Jan',1,345)
INSERT INTO #t values('UP','R','S','1-Feb',1,456)
INSERT INTO #t values('UP','A','S','1-Jan',2,567)
INSERT INTO #t values('DL','R','S','1-Feb',3,678)
INSERT INTO #t values('DL','T','S','1-Jan',1,789)
INSERT INTO #t values('DL','A','S','1-Jan',2,900)
INSERT INTO #t values('MN','T','S','1-Jan',3,1011)
INSERT INTO #t values('MN','R','I','1-Feb',1,1122)
INSERT INTO #t values('MN','S','I','1-Feb',2,1233)
SELECT States,ISNULL(A,0) A,ISNULL(R,0) R,ISNULL(T,0) T,ISNULL(A,0)+ISNULL(R,0)+ISNULL(T,0) total
FROM
(
SELECT States,LAB,Count(ID) AS cnt FROM #t GROUP BY States,LAB /*apply GROUP DATE CODE condition here*/
) AS PVT
PIVOT(MAX(cnt) FOR LAB IN (A,R,T)) pvt
Another solution using PIVOT :
WITH PivotInUse AS (
SELECT state,lab,COUNT(*) AS cnt
FROM YourTable
GROUP BY state,lab
)
SELECT STATE
,COALESCE([A], 0) AS A
,COALESCE([R], 0) AS R
,COALESCE([T], 0) AS T
,COALESCE([A], 0) + COALESCE([R], 0) + COALESCE([T], 0) AS TOTAL
FROM PivotInUse
PIVOT(SUM(cnt) FOR lab IN ([A],[R],[T])) AS p;
Your sample table
SELECT * INTO #TEMP FROM
(
SELECT 'UP' [State],'A' LAB,'I' [GROUP],'1-Jan' [DATE],1 CODE,345 ID
UNION ALL
SELECT 'UP','R','S','1-Feb',1,456
UNION ALL
SELECT 'UP','A','S','1-Jan',2,567
UNION ALL
SELECT 'DL','R','S','1-Feb',3,678
UNION ALL
SELECT 'DL','T','S','1-Jan',1,789
UNION ALL
SELECT 'DL','A','S','1-Jan',2,900
UNION ALL
SELECT 'MN','T','S','1-Jan',3,1011
UNION ALL
SELECT 'MN','R','I','1-Feb',1,1122
UNION ALL
SELECT 'MN','S','I','1-Feb',2,1233
)TAB
Now you need to get the distinct count of each state and get the sum as the result to show Total
in pivoted result.
SELECT DISTINCT [State],LAB,SUM(CNT) CNT
INTO #NEWTABLE
FROM
(
SELECT DISTINCT
[State],LAB,
CASE WHEN [State] IS NULL THEN NULL ELSE COUNT([State]) OVER(PARTITION BY [State],LAB) END CNT
FROM #TEMP
)TAB
GROUP BY [State],LAB
WITH ROLLUP
Now we need to get the distinct columns for pivot(#cols) and columns to identify and replace null with zero in pivot(#NullToZeroCols)
DECLARE #cols NVARCHAR (MAX)
DECLARE #NullToZeroCols NVARCHAR (MAX)
SET #cols = SUBSTRING((SELECT DISTINCT ',['+LAB+']' FROM #NEWTABLE GROUP BY LAB FOR XML PATH('')),2,8000)
SET #NullToZeroCols = SUBSTRING((SELECT DISTINCT ',ISNULL(['+LAB+'],0) AS ['+LAB+']'
FROM #NEWTABLE GROUP BY LAB FOR XML PATH('')),2,8000)
Join the pivotted query with the #NEWTABLE to get the Total for each State
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT P.State,' + #NullToZeroCols + ',T2.CNT TOTAL FROM
(
SELECT DISTINCT [State],LAB,CNT FROM #NEWTABLE
) x
PIVOT
(
SUM(CNT)
FOR [LAB] IN (' + #cols + ')
) p
JOIN #NEWTABLE T2 ON P.[STATE]=T2.[STATE]
WHERE P.State IS NOT NULL AND T2.LAB IS NULL AND T2.[STATE] IS NOT NULL;'
EXEC SP_EXECUTESQL #query
Here is your result
Here is the SQLFiddle http://sqlfiddle.com/#!3/c2588/1 (If it shows any error while loading the page, just click RUNSQL, it will work)
Now if you want to get the result as you said DISTINCT COUNT OF ID FOR EACH LAB FOR EACH STATE, just change
OVER(PARTITION BY [State],LAB)
to
OVER(PARTITION BY [State],LAB,Id)
which will show the following result after executing the pivot query