SQL Server PIVOT Column Data - sql-server

I have a table with data as given below:
DATE Price
---------- ------
31/12/2009 10
31/12/2009 11
31/12/2009 12
30/12/2009 20
30/12/2009 21
30/12/2009 22
29/12/2009 30
29/12/2009 32
29/12/2009 31
I want to convert this data as given below:
31/12/2009 30/12/2009 29/12/2009
---------- ---------- ----------
10 10 10
11 11 11
12 12 12
But the values in the date column is dynamic. So, I dont know how to use this using SQL Server Pivot.
Could you please let me know how to get this data.
Given below is the script to replicate this scenario:
CREATE TABLE TEMP(EffectiveDate DATETIME,Price INT)
INSERT INTO TEMP(EffectiveDate,Price)
SELECT GETDATE(),10
UNION ALL
SELECT GETDATE(),11
UNION ALL
SELECT GETDATE(),12
UNION ALL
SELECT GETDATE()-1,20
UNION ALL
SELECT GETDATE()-1,21
UNION ALL
SELECT GETDATE()-1,22
UNION ALL
SELECT GETDATE()-2,30
UNION ALL
SELECT GETDATE()-2,32
UNION ALL
SELECT GETDATE()-2,31
SELECT CONVERT(VARCHAR,EffectiveDATE,103) AS 'DATE',Price FROM Temp
Thanks in advance,
Mahesh

OK, as I mentioned, your data does not make sense, but maybe this can help.
The only way to create a dynamic pivot, is by creating dynamic sql.
Also, PIVOT requires that you use an Aggregate function (SUM, AVG, COUNT).
Ok, let see if this can help you.
CREATE TABLE #TEMP (EffectiveDate DATETIME,Price INT)
INSERT INTO #TEMP(EffectiveDate,Price)
SELECT GETDATE(),10
UNION ALL
SELECT GETDATE(),11
UNION ALL
SELECT GETDATE(),12
UNION ALL
SELECT GETDATE()-1,20
UNION ALL
SELECT GETDATE()-1,21
UNION ALL
SELECT GETDATE()-1,22
UNION ALL
SELECT GETDATE()-2,30
UNION ALL
SELECT GETDATE()-2,32
UNION ALL
SELECT GETDATE()-2,31
DECLARE #Cols VARCHAR(MAX)
SELECT #cols = COALESCE(#cols + ',[' + colName + ']',
'[' + colName + ']')
FROM (
SELECT DISTINCT
CONVERT(VARCHAR,EffectiveDATE,103) colName
FROM #TEMP
) s
ORDER BY colName DESC
DECLARE #query VARCHAR(MAX)
SET #query = N'SELECT *
FROM
(SELECT CONVERT(VARCHAR,EffectiveDATE,103) AS ''DATE'',Price
FROM #TEMP) p
PIVOT
(
SUM(Price) FOR DATE IN
( '+
#cols +' )
) AS pvt'
EXECUTE(#query)
DROP TABLE #TEMP

Related

Query column headings data in SQL

I need to display column headings that occur in a different table as a list.
Example:
Column headings - Adam, Cory, Jack, Jane, John, Josef, Mary, Timothy, Charlotte, Jessica, Kristal, Clive
Required column headings (contained within another table) - Jack, Jane, John, Mary, Maria, Josef
How would I check if the column headings are equal to any in the "required" list and then display only those?
I recommend you make use of Pivot and Dynamic SQL. Join from your complete names table to the required names table to end up with just the names you need as columns. Format those values to be later used in pivot with dynamic SQL. With pivot you are forced to aggregate something. Look at the Pivot rows to columns without aggregate post for more information. I hard coded 1 as the aggregate value we need to be able to pivot. You can ignore that value and join on name assuming that is your key to other tables to get additional data for each name.
https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-ver15
https://learn.microsoft.com/en-us/sql/odbc/reference/dynamic-sql?view=sql-server-ver15
Pivot rows to columns without aggregate
declare #PivotColumns nvarchar(max) = ''
create table #required ( name nvarchar(500) )
insert into #required ([name])
select 'Jack' union select 'Jane' union select 'John' union select 'Mary' union select 'Maria' union select 'Josef'
create table #allnames ( name nvarchar(500) )
insert into #allnames ([name])
select 'Adam' union select 'Cory' union select 'Jack' union select 'Jane' union select 'John' union select 'Josef' union select 'Mary' union select 'Timothy' union select 'Charlotte' union select 'Jessica' union select 'Kristal' union select 'Clive' union select 'Maria'
select #PivotColumns = #PivotColumns + QUOTENAME([name]) + ',' from #required
select #PivotColumns = substring(#PivotColumns,1,len(#PivotColumns)-1)
declare #SQL nvarchar(max) = ''
select #SQL = N'
select
*
from (
select
req.*, 1 [Val]
from #allnames as [All]
join #required as Req
on [All].[name] = Req.[name]
) src
pivot
(
max([Val])
FOR [name] in ('+#PivotColumns+')
) piv';
exec sp_executesql #SQL
drop table #required
drop table #allnames

Exporting dynamic column pivot result (Dynamic SQL resultset with varying number of columns) into excel file using SSIS

I have a dynamic pivot sql script (the pivoted columns are dynamic). I wanted to export the result set into excel file and email it with send mail task in ssis. Does anyone know how to do that? Below is my Dynamic column pivot sql script
Declare #SQL varchar(max)
Select #SQL = Stuff((Select Distinct ',' + QuoteName([Response Code]) From YourTable Order by 1 For XML Path('')),1,1,'')
Select #SQL = 'Select [Employee],' + #SQL + '
From (
Select [Employee],[Response Code],Cnt=1,Lvl=0 from YourTable
Union All
Select [Employee],[Response Code],Cnt=0,Lvl=0 from (Select Distinct [Employee] from YourTable) A Join (Select Distinct [Response Code] from YourTable) B on 1=1
Union All
Select ''Total'',[Response Code],count(*),1 From YourTable Group By [Response Code]
) A
Pivot (sum(Cnt) For [Response Code] in (' + #SQL + ') ) p'
Exec(#SQL);
The above script will return the table like this
Employee ptb ulm vml wrn
Emp A 0 0 2 1
Emp B 0 2 0 1
Emp C 1 0 1 0
Total 1 2 3 2
I need to export the above result table in to excel file. I know how to do if the column is static using SSIS ;but I am struggling with the dynamic column pivot. Could anyone please help me. Thank you very much for your time and help

Dynamic Pivot in Sql Syntax Puzzle

I have a tables as follows. Table #temp
Product Date 1st Pass Count 2nd Pass Count 3rd Pass Count
A 06-07-2015 2 4 5
A 06-07-2015 3 2 1
B 06-07-2015 1 1 1
Now I want a view as follows;
Product 06-07-2015 07-07-2015 08-07-2015
A 17 0 0
B 3 0 0
The date column is a sum of the 1st, 2nd and 3rd pass.
I have tried the query below . 2 problems I need help with.
Problem 1 - More than one row for Product A.
Problem 2 - Cant seem to add all 1st, 2nd and 3rd pass in sql query with pivot. Tried sum ( [1st pass]+[2nd pass]+[3rd pass] ) and it gave a syntax error.
Current code that works before I try things to correct the 2 problems above.
DECLARE #cols as NVARCHAR(MAX)
DECLARE #query as NVARCHAR(MAX)
Select #cols=STUFF ( SELECT ',' +QUOTENAME(PRODUCT) FROM #TEMP group by DATE ORDER BY DATE FOR XML PATH (''), TYPE).value.('.',NVARCHAR(MAX)'),1,1,'') set #query='SELECT [PRODUCT],' + #cols + 'from 'Select [PRODUCT],[DATE],[1st Pass],[2nd Pass],[3rd Pass] from #TEMP)x Pivot (sum [1st pass] FOR DTE in ('+#cols+') )p' execute (#query)
Is there something obvious I am missing here in terms of solving these last 2 problems ?
we can get the above result set by using Pivot and Cross Apply
Normal Pivot
DECLARE #t TABLE (Product Varchar(5),dated varchar(10),firstcount int,secondcount int,thirdcpount int)
INSERT INTO #t (Product,dated,firstcount,secondcount,thirdcpount)values
('A','06-07-2015',2,4,5),
('A','06-07-2015',3,2,1),
('B','06-07-2015',1,1,1)
select Product,SUM(ISNULL([06-07-2015],0)) As [06-07-2015],SUM(ISNULL([07-07-2015],0))As [07-07-2015],SUM(ISNULL([08-07-2015],0))As [08-07-2015] from (
select Product,dated,COL,val from #t
CROSS APPLY (VALUES('firstcount',firstcount),('secondcount',secondcount),('thirdcpount',thirdcpount))CS(COL,val))TT
PIVOT (SUM(VAL) FOR Dated IN ([06-07-2015],[07-07-2015],[08-07-2015]))T
GROUP BY Product
And
by using Dynamic Query Pivot
IF OBJECT_ID('tempdb..#t') IS NOT NULL
DROP TABLE #t
GO
CREATE TABLE #t (Product Varchar(5),dated varchar(10),firstcount int,secondcount int,thirdcpount int)
INSERT INTO #t (Product,dated,firstcount,secondcount,thirdcpount)values
('A','06-07-2015',2,4,5),
('A','06-07-2015',3,2,1),
('B','06-07-2015',1,1,1)
,('A','07-07-2015',2,11,5),
('A','07-07-2015',3,2,1),
('B','07-07-2015',1,1,1)
,('A','08-07-2015',3,11,6),
('A','08-07-2015',1,6,1),
('B','08-07-2015',11,1,6)
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max)
SELECT #columns = ISNULL(#columns + ', ', '') + N'[' + tbl.dated + ']'
FROM (
SELECT DISTINCT dated
FROM #t
) AS tbl
SELECT #statement = ' select Product,SUM(ISNULL([06-07-2015],0)) As [06-07-2015],SUM(ISNULL([07-07-2015],0))As [07-07-2015],SUM(ISNULL([08-07-2015],0))As [08-07-2015] from (
select Product,dated,COL,val from #t
CROSS APPLY (VALUES(''firstcount'',firstcount),(''secondcount'',secondcount),(''thirdcpount'',thirdcpount))CS(COL,val))TT
PIVOT (SUM(VAL) FOR Dated IN (' + #columns + ')) as pvt GROUP BY Product'
EXEC sp_executesql #statement = #statement

Entering 40000 rows in sql server through loop

I have to make a database system that is purely on SQL Server. It's about a diagnostic lab. It should contain at least 40,000 distinct patient records. I have a table named "Patient" which contains an auto-generated ID, Name, DOB, Age and Phone number. Our teacher provided us with a dummy stored procedure which contained 2 temporary tables that has 200 names each and in the end he makes a Cartesian product which is supposed to give 40,000 distinct rows. I have used the same dummy stored procedure and modified it according to our table. But the rows inserted are only 1260 every time. Each time we run the query it does not give us more than 1260 records. I have added a part of temporary name tables and the stored procedure.
Declare #tFirstNames Table( FirstName Varchar(50) Not Null )
Declare #tLastNames Table ( LastName Varchar(50) Not Null )
Declare #tNames Table ( Id Int Identity Not Null, Name Varchar(50) Not Null)
Insert Into #tFirstNames (FirstName)
Select 'Julianne' Union All Select 'Sharyl' Union All Select 'Yoshie'
Union All Select 'Germaine' Union All Select 'Ja' Union All
Select 'Kandis' Select 'Hannelore' Union All Select 'Laquanda' Union All
Select 'Clayton' Union All Select 'Ollie' Union All
Select 'Rosa' Union All Select 'Deloras' Union All
Select 'April' Union All Select 'Garrett' Union All
Select 'Mariette' Union All Select 'Carline' Union All
Insert Into #tLastNames (LastName)
Select 'Brown' Union All Select 'Chrichton' Union All Select 'Bush'
Union All Select 'Clinton' Union All Select 'Blair'
Union All Select 'Wayne' Union All Select 'Hanks'
Union All Select 'Cruise' Union All Select 'Campbell'
Union All Select 'Turow' Union All Select 'Tracey'
Union All Select 'Arnold' Union All Select 'Derick'
Union All Select 'Nathanael' Union All Select 'Buddy'
Insert Into #tNames
Select FirstName + ' ' + LastName
From #tFirstNames, #tLastNames
Declare #iIndex Integer
Declare #iPatientTotalRecords Integer
Declare #vcName Varchar(50)
Declare #iAge Integer
--Set #iIndex = 1
Select #iPatientTotalRecords = Max(Id), #iIndex = Min(Id) From #tNames
While #iIndex <= #iPatientTotalRecords
Begin
Select #vcName = Name From #tNames Where Id = #iIndex
Set #iAge = Cast( Rand() * 70 As Integer ) + 10
Insert into Patient values
(#vcName, #iAge,
Case Cast( Rand() * 3 As Integer)
When 0 Then 'Male'
When 1 Then 'Female'
Else 'Female'
End,
Cast( Rand() * 8888889 As Integer ) + 1111111, DateAdd ( year, -#iAge, GetDate()))
Set #iIndex = #iIndex + 1
End
Possible you miss type UNION ALL -
Select 'Julianne' Union All
Select 'Sharyl' Union All
Select 'Yoshie' Union All
Select 'Germaine' Union All
Select 'Ja' Union All
Select 'Kandis' --<-- missing union all
Select 'Hannelore' Union All
Select 'Laquanda' Union All
Select 'Clayton' Union All
Select 'Ollie' Union All
Select 'Rosa' Union All
Select 'Deloras' Union All
Select 'April' Union All
Select 'Garrett' Union All
Select 'Mariette' Union All
Select 'Carline'
Try this one (without WHILE and additional variables):
DECLARE #tFirstNames TABLE (FirstName VARCHAR(50) NOT NULL)
INSERT INTO #tFirstNames (FirstName)
VALUES
('Julianne'), ('Sharyl'), ('Yoshie'), ('Germaine'),
('Ja'), ('Kandis'), ('Hannelore'), ('Laquanda'), ('Clayton'),
('Ollie'), ('Rosa'), ('Deloras'), ('April'), ('Garrett'),
('Mariette'), ('Carline')
DECLARE #tLastNames TABLE (LastName VARCHAR(50) NOT NULL)
INSERT INTO #tLastNames (LastName)
VALUES
('Brown'), ('Chrichton'), ('Bush'), ('Clinton'),
('Blair'), ('Wayne'), ('Hanks'), ('Cruise'), ('Campbell'),
('Turow'), ('Tracey'), ('Arnold'), ('Derick'),
('Nathanael'), ('Buddy')
INSERT INTO dbo.Patient (...)
SELECT
-- Possible problem: String or binary data would be truncated
d.FLName -- <-- FirstName + LastName i.e. 50 + 1 + 50 = 101 chars
, d.Age
, Gender = CASE ABS(CAST((BINARY_CHECKSUM(NEWID(), NEWID())) AS INT)) % 3
WHEN 0 THEN 'Male'
ELSE 'Female'
END
, (ABS(CAST((BINARY_CHECKSUM(NEWID(), NEWID())) AS INT)) % 8888889) + 1111111
, BirthDay = CONVERT(VARCHAR(10), DATEADD( year, -d.Age, GETDATE()), 112)
FROM (
SELECT
FLName = f.FirstName + ' ' + l.LastName
, Age = (ABS(CAST((BINARY_CHECKSUM(f.FirstName, NEWID())) AS INT)) % 70) + 10
FROM #tFirstNames f
CROSS JOIN #tLastNames l
) d

Pivot table with one row and four columns

-- Pivot table with one row and four columns
SELECT 'Values' tValues,
ID,Name,ValueID,Value FROM (
Select ID,Name,ValueID,Value FROM Table WHERE OptionID = 1000000
) AS SourceTable
PIVOT (
COUNT(tValues)
FOR tValues IN ( ID,Attribute,ValueID,Value )
) AS PivotTable;
I'm going off the example at Microsoft.com: http://msdn.microsoft.com/en-us/library/ms177410.aspx
But there are a few things about Pivot i don't really understand, so don't be surprised when you see it in the code above, such as COUNT(tValues), I have no idea what this is for, by judging from the example on microsoft, it seems to be always some sort of numeric value, so i figured i'd try it to see if it would return something, but all it returns is an error. Anyhow, if someone out there can share why this query doesn't work, and possibly explain what the numeric value above the FOR is used for?
The Table containts an x amount of rows, with four columns, so it looks like this:
ID | Name | ValueID | Value
100 | Color | 10000 | Black
101 | Size | 10005 | Large
The output should be like this:
Name_100 | Color | Name_101 | Size |
10000 | Black | 10005 | Large |
Something like this maybe.
This will only work if the name column is unique. If not then you might want to append an id on it.
So first some test data:
CREATE TABLE tblValues
(
ID INT,
Name VARCHAR(100),
ValueID INT,
Value VARCHAR(100)
)
INSERT INTO tblValues
VALUES
(100,'Color',10000,'Black'),
(101,'Size',10005,'Large')
Then you need to get the columns to pivot on:
DECLARE #cols VARCHAR(MAX)
;WITH CTE AS
(
SELECT
'Name_'+CAST(tbl.ID AS VARCHAR(100)) AS Name,
'Name_'+CAST(tbl.ID AS VARCHAR(100)) AS Sort,
tbl.ID
FROM
tblValues AS tbl
UNION ALL
SELECT
tbl.Name,
'Value_'+CAST(tbl.ID AS VARCHAR(100)) AS Sort,
tbl.ID
FROM
tblValues AS tbl
)
SELECT
#cols = COALESCE(#cols + ','+QUOTENAME(Name),
QUOTENAME(Name))
FROM
CTE
ORDER BY
CTE.ID,
CTE.Sort
Then declaring and executing the dynamic sql like this:
DECLARE #query NVARCHAR(4000)=
N'SELECT
*
FROM
(
SELECT
''Name_''+CAST(tbl.ID AS VARCHAR(100)) AS pivotName,
CAST(tbl.ValueID AS VARCHAR(100)) AS name
FROM
tblValues AS tbl
UNION ALL
SELECT
tbl.Name AS pivotName,
tbl.Value AS name
FROM
tblValues AS tbl
) AS p
PIVOT
(
MAX(name)
FOR pivotName IN ('+#cols+')
) AS pvt'
EXECUTE(#query)
Then in my case I will drop the table I have created
DROP TABLE tblValues
Edit
Or in you case it should be something like this:
First the columns:
DECLARE #cols VARCHAR(MAX)
;WITH CTE AS
(
SELECT
'Name_'+CAST(tbl.ID AS VARCHAR(100)) AS Name,
'Name_'+CAST(tbl.ID AS VARCHAR(100)) AS Sort,
tbl.ID
FROM
[Table] AS tbl
WHERE
tbl.OptionID = 1000000
UNION ALL
SELECT
tbl.Name,
'Value_'+CAST(tbl.ID AS VARCHAR(100)) AS Sort,
tbl.ID
FROM
[Table] AS tbl
WHERE
tbl.OptionID = 1000000
)
SELECT
#cols = COALESCE(#cols + ','+QUOTENAME(Name),
QUOTENAME(Name))
FROM
CTE
ORDER BY
CTE.ID,
CTE.Sort
Then the dynamic sql.
DECLARE #query NVARCHAR(4000)=
N'SELECT
*
FROM
(
SELECT
''Name_''+CAST(tbl.ID AS VARCHAR(100)) AS pivotName,
CAST(tbl.ValueID AS VARCHAR(100)) AS name
FROM
[Table] AS tbl
WHERE
tbl.OptionID = 1000000
UNION ALL
SELECT
tbl.Name AS pivotName,
tbl.Value AS name
FROM
[Table] AS tbl
WHERE
tbl.OptionID = 1000000
) AS p
PIVOT
(
MAX(name)
FOR pivotName IN ('+#cols+')
) AS pvt'
EXECUTE(#query)
You do not need to create the table or drop the table. That was just because I did not have your table in my database and that if someone else want's to run the example.
If you want to use Pivot tables with a variable number of columns, then I'd suggest using something along the lines of;
DECLARE #cols VARCHAR(4000)
DECLARE #query VARCHAR(8000)
SELECT #cols = STUFF(( SELECT DISTINCT
'],[' + Name
FROM Table
ORDER BY '],[' + Name
FOR XML PATH('')
), 1, 2, '') + ']'
SET #query =
'SELECT * FROM
(
SELECT col1, col2, col3, whateverColYourInterestedIn, Name, Value
FROM Table
)t
PIVOT (MAX(Value) FOR Name
IN ('+#cols+')) AS pvt'
EXECUTE (#query)
That is probably not quite right, but it should hopefully be a starting point for you.
For more info, check out links such as this or this.

Resources