How can I create a month name as a column name for a given date range in sql? - sql

I have a data as below:
Table
country date value
------------------------------------------------------
test1 5/1/2008 500
test1 5/7/2008 200
test1 5/8/2008 300
test1 7/1/2008 100
test1 7/2/2008 100
test2 6/1/2008 100
And I want a result as below:
Result
-----------
countryName May-08 Jun-08 July-08
test1 1000 - 200
test2 - 100

This is adapted from T-SQL Pivot? Possibility of creating table columns from row values
You can see it working here: http://sqlfiddle.com/#!3/7b8c0/28
I think you might need to fiddle around with the column ordering
-- Static PIVOT
SELECT *
FROM (SELECT country,
CONVERT(char(3), date, 0) + '-' +
RIGHT(CONVERT(varchar, YEAR(date)), 2) AS date,
value
FROM country) AS D
PIVOT(SUM(value) FOR date IN([May-08],[Jun-08],[Jul-08])) AS P;
GO
-- Dynamic PIVOT
DECLARE #T AS TABLE(y INT NOT NULL PRIMARY KEY);
DECLARE
#cols AS NVARCHAR(MAX),
#y AS INT,
#sql AS NVARCHAR(MAX)
SELECT #cols = STUFF(
(SELECT N',' + QUOTENAME(y) AS [text()]
FROM (SELECT DISTINCT CONVERT(char(3), date, 0) + '-' +
RIGHT(CONVERT(varchar, YEAR(date)), 2) AS y
FROM Country
) AS Y
ORDER BY y desc
FOR XML PATH('')),
1, 1, N'')
-- Construct the full T-SQL statement
-- and execute dynamically
SET #sql = N'SELECT *
FROM (SELECT country, CONVERT(char(3), date, 0) + ''-'' +
RIGHT(CONVERT(varchar, YEAR(date)), 2) AS date, value
FROM Country) AS D
PIVOT(SUM(value) FOR date IN(' + #cols + N')) AS P;'
EXEC sp_executesql #sql

You have to use a rather complex query for that, using a LOOP it think.
For creating dynamic column names look at this post: https://stackoverflow.com/a/10926106/1321564
With sql server you have some advantages: https://stackoverflow.com/a/5638042/1321564

Related

SQL Server pivot query - questions

I have a table with 3 columns: order_id, product_id, product_count
The first column is an order passed by a client, the second is the product unique id and the third is the quantity of a product bought in an order.
I want to create a matrix of order_id / product_id with number of items bought.
As a result I would like to have something that looks like this:
If I make this request:
SELECT *
FROM
(SELECT
[order_id], [prod_id], [product_count]
FROM mydb.dbo.mytable) QueryResults
PIVOT
(SUM([product_count])
FOR [prod_id] IN ([21], [22], [23])
) AS PivotTable
My issue is that I have more than 200 different products to retrieve. Is there a way to make it without entering all values?
I'd written this and was testing when BICube posted his comment - and yes, this is another dynamic Pivot. You had the basic code - all you need to do is to
Build a variable with the column name list e.g., ColList = '[21],[22],[23]'
Use this variable in the PIVOT to provide the column list - but note you then need to make the whole statement into Dynamic SQL.
Here is the answer I wrote (Note I just made up order data rather than transcribing from your image).
CREATE TABLE #MyTable (Order_ID int, Prod_ID int, Product_Count int);
INSERT INTO #MyTable (Order_ID, Prod_ID, Product_Count)
VALUES
(100, 1, 15),
(100, 2, 12),
(100, 5, 17),
(101, 3, 10),
(101, 4, 11),
(102, 6, 12),
(102, 1, 16);
SELECT * FROM #MyTable;
DECLARE #ColList nvarchar(max) = N''
SELECT #ColList += N',' + QUOTENAME(LTRIM(STR(Prod_ID)))
FROM (SELECT DISTINCT Prod_ID FROM #MyTable) A;
SET #ColList = STUFF(#ColList,1,1,''); -- Remove leading comma
DECLARE #PivotSQL nvarchar(max);
SET #PivotSQL =
N'SELECT * FROM (
SELECT
[Order_ID],
[prod_id],
[product_count]
FROM #MyTable
) QueryResults
PIVOT (
SUM([product_count])
FOR [prod_id]
IN (' + #ColList + N')
) AS PivotTable;'
EXEC (#PivotSQL);
And here are the results
Order_ID 1 2 3 4 5 6
100 15 12 NULL NULL 17 NULL
101 NULL NULL 10 11 NULL NULL
102 16 NULL NULL NULL NULL 12
Based on #seanb answer that saved me, I tried to replace the NULL values with 0. I understood the principle (the base). Here is how I updated the SQL request to replace the NULL values.
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX),
#PivotColumnNames AS NVARCHAR(MAX),
#PivotSelectColumnNames AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #PivotColumnNames= ISNULL(#PivotColumnNames + ',','') + QUOTENAME(prod_id)
FROM (SELECT DISTINCT prod_id FROM #MyTable) AS prod_id
--Get distinct values of the PIVOT Column with isnull
SELECT #PivotSelectColumnNames
= ISNULL(#PivotSelectColumnNames + ',','')
+ 'ISNULL(' + QUOTENAME(prod_id) + ', 0) AS '
+ QUOTENAME(prod_id)
FROM (SELECT DISTINCT prod_id FROM #MyTable) AS prod_id
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery =
N'SELECT order_id, ' + #PivotSelectColumnNames + '
FROM #MyTable
PIVOT(SUM(product_count)
FOR prod_id IN (' + #PivotColumnNames + ')) AS PivotTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql #DynamicPivotQuery

How can I run my custom function and query in a loop for different time frames?

I am writing a function to calculate the total number of seconds a user was online at my website. Afterwards, I convert the number of seconds to hh:mm:ss:
select * into #temp from [MyFunction](timestamp1, timestamp2);
select u.Name,
convert(varchar(8), t.Seconds / 3600) + ':'
+ right('0', convert(varchar(2) t.Seconds % 3600/60), 2) + ':'
+ right('0', convert(varchar(2) t.Seconds % 60), 2)
as [Total Time]
from #temp t left join Users u
on t.UserID = u.UserID;
Where an example timestamp is 2016-04-01 00:00:00.000. What I want now, is to see total time spent on my website, not on 1 range, but a sequence of ranges, for instance:
2016-01-01 to 2016-01-15
2016-01-16 to 2016-01-31
2016-02-01 to 2016-02-15
Is it possible to put my code in a dynamic query to calculate all of these ranges by running the same code every time?
The output of my code above is:
Name [Total Time]
--------------------
Anton 6:34:55
Bert 5:22:14
What I would like is an output such as
Name [Period_1] [Period_2] [Period_3] [Period_4]
---------------------------------------------------
Anton 6:34:55 5:00:22 null 10:44:32
Bert 5:22:14 null null 9:22:53
So each range, or loop over the code, should be a column.
I believe pivot() will help me here, but any help kickstarting me with the dynamic SQL (or any better solution) would be greatly appreciated.
Wrap your current code into a procedure with parameters, something like:
CREATE PROCEUDRE dbo.CalcTime
#Period varchar(100) -- Name of the period
,#PeriodStart datetime -- Period starts
,#PeriodEnd datetime -- Period ends
and using appropriate datatypes.
Next, create a second procedure. Within this one, define another temporary table, like
CREATE TABLE #Results
(
Name varchar(100) not null -- Or however long it might get
,Period varchar(100) not null -- Ditto
,TotalTime int null -- *
)
Loop over every period you wish to define data for. For each period, call the "CalcTime" stored procedure, and dump the results into the temp table. Two ways to do this, use
INSERT #Results
execute dbo.CalcTime 'Period', 'Jan 1, 2016', 'Jan 15, 2016'
or, having defined the temp table in the calling procedure, you can reference it in the called procedure in a standard INSERT... SELECT... statement.
Also within the loop, build a comma-delimited string that lists all your period labels, e.g.
SET #AllPeriodLabels = isnull(#AllPeriodLabels + ',', '') + #ThisPeriodLabel
or,
SET #AllPeriodLabels = isnull(#AllPeriodLabels + ',', '') + '[' + #ThisPeriodLabel + ']' -- **
Use this to build the dynamic SQL pivot statement against the temp table, and you’re done. As mentioned in the comments, there are any number of SO posts on how to do that, and here are links to two: The first discusses building a dynamic pivot statement, and the second uses similar tactics for an unpivot statement.
* Avoid embedded spaces in object names, they will only give you pain.
** Ok, Sometimes you have to do it.
Two pseudo tables:
persons:
personId int
lastname nvarchar(50)
visits:
personid int
created datetime
duration int -- (store things like duration in seconds)
First make a list of the columns, here I used a created column and converted it to a month period. So the result is something like: [201501],[201502],[201503],....
declare #cols nvarchar(max)
set #cols = STUFF((select ',' + quotename(convert(VARCHAR(6), created, 112))
from visits
group by convert(VARCHAR(6), created, 112)
order by convert(VARCHAR(6), created, 112)
for xml path(''), type).value('.', 'nvarchar(max)'), 1, 1, '')
I need dynamic SQL to fill in the variable number of COLs, I suggest you start with NON dynamic SQL, make it dynamic should be the last step.
declare #sql nvarchar(max)
set #sql = N'
select *
-- lazy create a temp so you don't have to bother about the column definitions
-- into #temp
from (
select p.lastname, convert(VARCHAR(6), created, 112) as period
-- this is optional to get a Grand Row total
-- ,(select sum(duration) from visits v where v.personId = p.personId) as total
from visits v
inner join persons p on v.personId = p.personId
) src
pivot (
sum(duration) for period in (' + #cols + ')
) pvt;
'
Well you can print this for verification or run it ...
exec sp_executesql #sql
You can make a twist by dumping the result in a temp table (created on the fly). That creates the opportunity to add extra columns for output, like an organization etc. etc..
alter table #temp add organization nvarchar(100)
Good luck !
Here is a working test code. Adapt it as you see fit.
Setup:
-- create test tables
CREATE TABLE Users
(
UserId INT,
UserName NVARCHAR(max)
)
CREATE TABLE Access
(
UserId INT,
StartTime DATETIME2,
EndTime DATETIME2
)
CREATE TABLE Periods
(
NAME NVARCHAR(max),
StartTime DATETIME2,
EndTime DATETIME2
)
go
-- function to format the time
CREATE FUNCTION ToTime(#SECONDS BIGINT)
returns NVARCHAR(max)
AS
BEGIN
RETURN CONVERT(VARCHAR(8), #SECONDS / 3600) + ':'
+ RIGHT('00'+CONVERT(VARCHAR(2), #SECONDS % 3600/60), 2)
+ ':'
+ RIGHT('00'+CONVERT(VARCHAR(2), #SECONDS % 60), 2)
END
go
-- populate values
INSERT INTO Users
VALUES (1, 'Anton'),
(2,'Bert')
DECLARE #I INT=100
DECLARE #D1 DATETIME2
DECLARE #D2 DATETIME2
WHILE ( #I > 0 )
BEGIN
SET #D1=Dateadd(second, Rand() * 8640000, Getdate())
SET #D2=Dateadd(second, Rand() * 1000, #D1)
INSERT INTO Access
VALUES (Floor(Rand() * 2 + 1), #D1, #D2);
SET #I=#I - 1
END
SET #I=1
SET #D1=Getdate()
WHILE ( #I < 6 )
BEGIN
SET #D2=Dateadd(day, 15, #D1)
INSERT INTO Periods
VALUES (Concat('Period_', #I),
#D1,
#D2);
SET #D1=#D2
SET #I=#I + 1
END
go
Working code:
-- Getting the values
DECLARE #COLS NVARCHAR(max)
SET #COLS = Stuff((SELECT ',' + Quotename(NAME)
FROM Periods
GROUP BY NAME
ORDER BY NAME
FOR xml path(''), type).value('.', 'nvarchar(max)'), 1, 1, ''
)
DECLARE #SQL NVARCHAR(max)
SET #SQL = N'SELECT * FROM
(
SELECT u.UserName,
p.Name AS Period,
dbo.Totime(Sum(Datediff(SECOND,a.StartTime,a.EndTime))) AS [Time]
FROM Access a
INNER JOIN Users u
ON a.UserId=u.UserId
INNER JOIN Periods p
ON p.StartTime<=a.StartTime
AND a.StartTime<p.EndTime
GROUP BY u.UserName,
p.Name ) x PIVOT ( Max([Time]) FOR Period IN (' + #COLS +')
) p;'
--PRINT #SQL
EXECUTE(#SQL)

transpose rows to columns in sql

I have problem in getting the desired output with the SQL query.
My sql data is as follows:
TOTAL Charge PAYMNET A B C D E MonthYear
------- ----------- ----------- --------- -------- ---------- ------- ------- ----------
661 157832.24 82967.80 700.00 10.70 58329.33 0.00 0.00 Oct-2013
612 95030.52 17824.28 850.00 66.10 53971.41 0.00 0.00 Nov-2013
584 90256.35 16732.91 700.00 66.10 52219.87 0.00 0.00 Dec-2013
511 72217.32 12336.12 285.00 53.17 42951.12 0.00 0.00 Jan-2014
I need the output as follows,
Data Jan-2013 Feb-2013 Mar-2013
TOTALCOUNT 761 647 671
Charge 126888 119995 151737.5
Payment 25705.4 26235.47 28704.41
A 1089.08 1020 745
B 2100.4 1947.25 1868.22
C 94246.55 84202.15 115673.7
D 0 0 0
E 0 0 0
I have seen the examples of pivot and unpivot, in pivot I don't get the column headers as row data, and in unpivot I didn't found an example where I can transpose multiple columns. I have another option to get this result in the code. But I want to know is it possible to get this kind of result in sql?
Edit
The result will give only for 3 or 4 months, not more than that.
Update : The first sample data is the actual data which I will get as a result of multiple joins and grouping on multiple tables, which I will store into a temp table. I tried to get the required result by modifying the query which is not possible because of the table structure. I managed to get the result as in the first sample data, but this is not what the client want to see!!! So I need to process the temp table data which will be only 3 to 4 rows into required output. The query to get the first result is select * from temp. The processing needs to be done on temp table result.
Update-2
I have tried the following query
declare #cols varchar(max)
select #cols = STUFF((select ', ' + MonthYear
from #tmp for xml path('')),1,1,'')
declare #query varchar(max)
set #query =
'select ''TOTAL'' as Data,' +#cols+' from
(select MonthYear,TOTALCLAIMS from #tmp)st
pivot
(
MAX(TOTAL) for MonthYear in (' + #cols + ')
)pt;'
Which gave me the first row correctly!!! But I tried to use union as
set #query =
'select ''TOTAL'' as Data,' +#cols+' from
(select MonthYear,TOTALCLAIMS from #tmp)st
pivot
(
MAX(TOTAL) for MonthYear in (' + #cols + ')
)pt;
union
select ''CHARGES'' as Data,' +#cols+' from
(select MonthYear,TOTALCLAIMS from #tmp)st
pivot
(
MAX(CHARGES) for MonthYear in (' + #cols + ')
)pt;'
Which gives an error as incorrect syntax near union. Any one know how to union pivot results? Or is there any better way to do this?
Thank You.
I have tried this code. Please check and let me know if it works
I know that it doesnt look so good. Also not sure how it will be performance wise.
--Can have more columns like A,B,...
DECLARE #tbl TABLE
(
TOTAL INT,
CHARGE FLOAT,
PAYMENT FLOAT,
MONTHYEAR VARCHAR(50)
)
--Test data
INSERT INTO #tbl SELECT 661, 157832.24, 82967.80, 'Oct2013'
INSERT INTO #tbl SELECT 612, 95030.52, 17824.28, 'Nov2013'
INSERT INTO #tbl SELECT 584 ,90256.35, 16732.91, 'Dec2013'
--Can be a physical table
CREATE TABLE #FinalTbl
(
DATA VARCHAR(100)
)
--inserted hardcode records in data column. To add it dynamically you would need to loop through information_schema.columns
--SELECT *
--FROM information_schema.columns
--WHERE table_name = 'tbl_name'
INSERT INTO #FinalTbl
VALUES ('TOTAL')
INSERT INTO #FinalTbl
VALUES ('CHARGE')
INSERT INTO #FinalTbl
VALUES ('PAYMENT')
DECLARE #StartCount INT, #TotalCount INT, #Query VARCHAR(5000), #TOTAL INT,#CHARGE FLOAT,#PAYMENT FLOAT,#MONTHYEAR VARCHAR(50)
SELECT #TotalCount = COUNT(*) FROM #tbl;
SET #StartCount = 1;
WHILE(#StartCount <= #TotalCount)
BEGIN
SELECT #TOTAL = TOTAL,
#CHARGE = CHARGE,
#PAYMENT = PAYMENT,
#MONTHYEAR = MONTHYEAR
FROM
(SELECT ROW_NUMBER() over(ORDER BY MONTHYEAR) AS ROWNUM, * FROM #tbl) as tbl
WHERE ROWNUM = #StartCount
SELECT #Query = 'ALTER TABLE #FinalTbl ADD ' + #MONTHYEAR + ' VARCHAR(1000)'
EXEC (#Query)
SELECT #Query = 'UPDATE #FinalTbl SET ' + #MONTHYEAR + ' = ''' + CONVERT(VARCHAR(50), #TOTAL) + ''' WHERE DATA = ''TOTAL'''
EXEC (#Query)
SELECT #Query = 'UPDATE #FinalTbl SET ' + #MONTHYEAR + ' = ''' + CONVERT(VARCHAR(50), #CHARGE) + ''' WHERE DATA = ''CHARGE'''
EXEC (#Query)
SELECT #Query = 'UPDATE #FinalTbl SET ' + #MONTHYEAR + ' = ''' + CONVERT(VARCHAR(50), #PAYMENT) + ''' WHERE DATA = ''PAYMENT'''
EXEC (#Query)
SELECT #StartCount = #StartCount + 1
END
SELECT * FROM #FinalTbl
DROP TABLE #FinalTbl
Hope this helps
I would imagine the reason you are only getting 3 or 4 months is because you don't have data for the missing months? If you want to display columns for missing months you will need to either:
Create a Table datatype with all the months you want to display
and left join the remainder of the tables to it in your query. You
could then use the PIVOT function as normal.
If you know how many columns up front i.e. one for each month in a particular year and it won't change, you can simply use CASE
Statements (one for each month) to transpose the data without the
PIVOT operator.
I can provide examples if needed.
Select Month(Mdate)md,'A' AS Col,sum(A) as a from Product group by Month(MDate)
union all
Select Month(Mdate)md,'B',sum(b) as a from Product group by Month(MDate)
union all
Select Month(Mdate)md,'C',sum(c) as a from Product group by Month(MDate)
union all
Select Month(Mdate)md,'D',Count(A) as a from Product group by Month(MDate)
Try Pivot with the above query you may to get required result....

change the column name while selecting from dyanamic table

Hi I have attendence query which will generate the attendence report with using PIVOT function
Here's the procedure :
declare #in_date DATETIME
/*Select all the stagign entries related to promotion id and investment type id */
/* also only those staging daat related interface status tracking*/
-- Getting all distinct dates into a temporary table #Dates
SELECT a.date as full_date_of_attendence INTO #Dates
FROM dbo.getFullmonth(#in_date) a
ORDER BY a.date
-- The number of days will be dynamic. So building
-- a comma seperated value string from the dates in #Dates
SELECT #cols = COALESCE(#cols + ',[' + CONVERT(varchar, full_date_of_attendence, 106)
+ ']','[' + CONVERT(varchar, full_date_of_attendence, 106) + ']')
FROM #Dates
ORDER BY full_date_of_attendence
--select #cols
---- Building the query with dynamic dates
SET #qry =
'SELECT * FROM
(SELECT admission_id, attendence_status , date_of_attendence
FROM dbo.tblattendence)emp
PIVOT (MAX(attendence_status) FOR date_of_attendence IN (' + #cols + ')) AS stat'
-- Executing the query
EXEC(#qry)
-- Dropping temporary tables
DROP TABLE #Dates
here is the output of the above query::
admission_id 01 May 2013 02 May 2013 03 May 2013
2 NULL 1 0
3 NULL 1 1
4 NULL 0 0
5 NULL 0 1
Here I want to change the names of the columns as 01,02,03......
and I want the values 1 as 'P' and 0 as 'A'
can anyone would help me to achieve this ??
I would suggest the following changes to your code. If you want a list of the days (1, 2, 3, etc), then you can use the DAY function.
Typically when I get a list of columns dynamically, my preference is using STUFF and FOR XML PATH, I would alter that code to the following:
select #colsPiv = STUFF((SELECT ',' + QUOTENAME(cast(day(full_date_of_attendence) as varchar(2)))
from #Dates
GROUP BY full_date_of_attendence
ORDER BY full_date_of_attendence
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
Then if you want to replace the 0 with an A and a 1 with a P, you will want to create a query to get a list of columns to replace the values:
select #colsSel = STUFF((SELECT ', case when ' + QUOTENAME(cast(day(full_date_of_attendence) as varchar(2)))+'= 1 then ''P'' else ''A'' end as '+QUOTENAME(cast(day(full_date_of_attendence) as varchar(2)))
from #Dates
GROUP BY full_date_of_attendence
ORDER BY full_date_of_attendence
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
Basically, this is creating a select list similar to this:
select case when [1] = 1 then 'P' else 'A' end as [1], ...
Then your final query will be:
SET #qry =
'SELECT admission_id, '+#colsSel +'
FROM
(
SELECT admission_id,
attendence_status ,
day(date_of_attendence) date_of_attendence
FROM dbo.tblattendence
)emp
PIVOT
(
MAX(attendence_status)
FOR date_of_attendence IN (' + #colsPiv + ')
) AS stat'
See SQL Fiddle with Demo
Let's change just the two things you wanted to, i.e.
CONVERT(CHAR(2), full_date_of_attendence, 106) -- use CHAR(2) instead of varchar
CASE attendence_status when 1 then 'P' else 'A' END in the SELECT...
The code with minimal changes. Hope this helps you see how you can make similar changes in future to other code.
declare #in_date DATETIME
/*Select all the stagign entries related to promotion id and investment type id */
/* also only those staging daat related interface status tracking*/
-- Getting all distinct dates into a temporary table #Dates
SELECT a.date as full_date_of_attendence INTO #Dates
FROM dbo.getFullmonth(#in_date) a
ORDER BY a.date
-- The number of days will be dynamic. So building
-- a comma seperated value string from the dates in #Dates
SELECT #cols = COALESCE(#cols + ',', '') + [' +
CONVERT(CHAR(2), full_date_of_attendence, 106) + ']'
FROM #Dates
ORDER BY full_date_of_attendence
--select #cols
---- Building the query with dynamic dates
SET #qry =
'SELECT * FROM
(SELECT admission_id, CASE attendence_status when 1 then 'P' else 'A' END, date_of_attendence
FROM dbo.tblattendence)emp
PIVOT (MAX(attendence_status) FOR date_of_attendence IN (' + #cols + ')) AS stat'
-- Executing the query
EXEC(#qry)
-- Dropping temporary tables
DROP TABLE #Dates

Dynamic pivot table with two id columns

This is probably simple but I"m just not seeing it. Your help is appreciated. I have a table in MS SQLServer that looks like this
CustomerID Time ItemID
1 2008-10-07 06:32:53:00.000 87432
1 2008-10-07 06:32:53:00.000 26413
2 2010-06-23 03:45:10:00.000 6312
2 2011-09-14 07:36:03:00.000 87432
2 2011-09-14 07:36:03:00.000 87432
I want to end up with a table that has each customer, the timestamp and the count of the items purchased during that timestamp, that looks like this
CustomerID Time 87432 26413 6312
1 2008-10-07 06:32:53:00.000 1 1 0
2 2010-06-23 03:45:10:00.000 0 0 1
2 2011-09-14 07:36:03:00.000 2 0 0
In the source table, the time and itemID are variable (and plentiful), so I'm thinking a dynamic pivot will do the trick. Is this possible to do with pivot? If so, how?
You can do this with a dynamic PIVOT. This will count the number of ItemIds that you have for any number of Times.
See a SQL Fiddle with a Demo. This demo leaves the time as a varchar as you stated they were. But this will work if the data is a datetime as well.
Since you want time in the final result, then when you select the columns, you will need to add the time column twice. I called it time1 and time. This allows you to aggregate on time1 in the PIVOT and still have a time column for your final product.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(itemid)
from temp
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT customerid, [time], ' + #cols + ' from
(
select customerid, [time] as time1, [time] as [time], itemid
from temp
) x
pivot
(
count([time1])
for itemid in (' + #cols + ')
) p '
execute(#query)
Approach #1 - Click here to see Demo
Declare #ItemIDs varchar(1000) = ''
Declare #Query varchar(8000) = ''
Select #ItemIDs = ISNULL(QuoteName(Convert(varchar, ItemID)) + ',', '')
+ #ItemIDs
From
(
Select distinct ItemID From #MyTable
)K
SET #ItemIDs = SUBSTRING(#ItemIDs,0,len(#ItemIDs))
SET #Query = 'Select CustomerID, [Time],' +
#ItemIDs + ' From
(
Select CustomerID, [Time], ItemID from #MyTable
)K Pivot
(
count(ItemID) FOR ItemID IN (' + #ItemIDs + ')
) AS pvt'
EXEC(#Query)
Approach #2 - Click here to see Demo
Select CustomerID, [Time], [87432] as [87432],
[26413] as [26413], [6312] as [6312] From
(
Select CustomerID, [Time], ItemID from #MyTable
)K Pivot
(
count(ItemID) FOR ItemID IN ([87432] , [26413],[6312])
) AS pvt