I was working from the fiddle example to create a cross tab view. Essentially, I received a table with Customers, Vendors and Product Type. I want to generate a view where the vendors are the rows and the columns are the total sales by product type.
The structure is
CustomerID Vendor ProductType
--------------------------------
1 A Type1
2 A Type2
3 B Type1
4 A Type2
The end result I want is:
Vendor Type1 Type2
---------------------
A 1 2
B 1 0
/* Count the number of sales by Product Type for each Vendor. */
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(ProductType)
from MyTable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Vendor,' + #cols + '
from MyTable
pivot
(
count (ProductType)
for ProductType in (' + #cols + ')
) p
ORDER BY Vendor ASC'
execute(#query)
The end result is multiple rows for each vendor instead of a single row with the aggregated counts.
E.g.
Vendor Type1 Type2
---------------------
A 1 0
A 0 1
B 1 0
A 0 1
Does anyone have any insight into what I may have missed with this query?
Thanks.
I would suggest that you use a subquery to select the columns that you need from your table. The problem is that your data is being grouped by the vendor and the customerId. The customerId is distinct for each row, changing your query to the following will give you the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(ProductType)
from MyTable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query
= 'SELECT Vendor,' + #cols + '
from
(
select vendor, producttype
from MyTable
) d
pivot
(
count (ProductType)
for ProductType in (' + #cols + ')
) p
ORDER BY Vendor ASC'
execute(#query);
See SQL Fiddle with Demo. This gives a result:
| VENDOR | TYPE1 | TYPE2 |
| A | 1 | 2 |
| B | 1 | 0 |
Related
Morning all, Longtime lurker, first time poster.
I'm writing a stored procedure to take the results from one SELECT statement and use that output to build another SELECT statement. Trouble is I can not find a mechanism or code to accomplish this. Assigning the results to a variable doesn't seem to be an option because SQL doesn't support Arrays (that I know of).
+----+-------------+-------------+
| ID | ___$seqval | Column_Name |
+----+-------------+-------------+
| 1 | 0x000000E10 | EnvType |
| 2 | 0x000000E10 | DataType |
| 3 | 0x000000E10 | DateMod |
+----+-------------+-------------+
Trying to get to;
SELECT Column_name(1), Column_name(2)..
From tblServer_Data
There could be up to a total of 20 columns returned.
SQL DEMO
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME([Column_Name])
FROM Table1 c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SELECT #cols as Columns; -- just for debug
set #query = 'SELECT [ID], ' + #cols + ' from
(
select 1 as ID
, [seqval]
, [Column_Name]
from Table1
) x
pivot
(
max([seqval])
for [Column_Name] in (' + #cols + ')
) p '
SELECT #query as Query; -- just for debug
execute(#query);
OUTPUT
Then you can do SELECT over that output
This will give a SELECT statement of the columns in a selected table.
SELECT 'SELECT ' + STUFF(
(SELECT ',' + c.column_name from
(SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS c
where c.TABLE_NAME = your_table) c
for xml path ('')),1,1,'') + ' FROM ' + your_table
Query:
select employee_sk,
[201701],
[201702]
from
(select Employee_SK, Period_NK, CalcClinical_FTE from cmgr.FACT_Payroll) as sourcetable
pivot
(
sum(CalcClinical_FTE)
for period_nk
in ([201701],[201702])
) as a
I have multiple periods in the period_nk column ranging from 201401 to 201801.
So, how can i assign the pivot values without having to write each column individually like 201701,201702, 201703...?
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.period_nk)
FROM temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT category, ' + #cols + ' from
(
select category,
period_nk,
amount
from temp
) x
pivot
(
max(amount)
for period_nk in (' + #cols + ')
) p '
execute(#query)
drop table temp
Output :
category 201701 201702 201703 201704 201705
1 ABC 1000,0000 NULL NULL NULL 1100,0000
2 DEF NULL 500,0000 NULL 700,0000 NULL
3 GHI NULL NULL 800,0000 NULL NULL
online demo
This question already has answers here:
Efficiently convert rows to columns in sql server
(5 answers)
Closed 6 years ago.
I'm struggling with an error while making a dynamic pivot table
The source data is
JobID | SalesForMonth | YearMonth
7734 | 400 | 2016-12
7734 | 350 | 2017-01
8540 | 444 | 2016-12
8540 | 300 | 2017-01
and aiming for
JobID | 2016-12 | 2017-01
7734 | 400 | 350
8540 | 444 | 300
and I've tried to use a query I found on here to create the column headers. But must admit I don't really understand the 'For XML' line and getting a syntax error there on line 6
DECLARE
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(YearMonth)
FROM v_JobSalesByMonth
FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')
SELECT #query =
'SELECT * FROM
(SELECT JobID, YearMonth, SalesForMonth
FROM v_JobSalesByMonth) X
PIVOT
(
(JobID, SalesForMonth)
for [YearMonth] in (' + #cols + ')
) P'
I'd also like to stick in a 'total sales' for the jobID column
Any help would be much appreciated
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(YearMonth) From v_JobSalesByMonth Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select [JobID],[TotalSales],' + #SQL + '
From (
Select JobID
,TotalSales = sum(SalesForMonth) over (Partition By JobID)
,YearMonth
,SalesForMonth
From v_JobSalesByMonth A
) A
Pivot (sum(SalesForMonth) For [YearMonth] in (' + #SQL + ') ) p'
Exec(#SQL);
Returns
EDIT - Dynamically Create View
Since you can't have dynamic SQL in a view, you could have job scheduled (daily or monthly) to drop and re-create the view.
if object_id('vw_SalesByMonth','v') is not null
drop view vw_SalesByMonth;
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(YearMonth) From Yourtable Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Create View vw_SalesByMonth
AS
Select [JobID],[TotalSales],' + #SQL + '
From (
Select JobID
,TotalSales = sum(SalesForMonth) over (Partition By JobID)
,YearMonth
,SalesForMonth
From YourTable A
) A
Pivot (sum(SalesForMonth) For [YearMonth] in (' + #SQL + ') ) p'
Exec(#SQL);
Select * from vw_SalesByMonth
I have data as follows:
Name CategoryName
Test1 cat1
Test1 cat2
Test2 cat1
Test3 cat2
I want to display it so that I get a list of users with 1/0 (true/false) under the category name:
Name cat1 cat2
Test1 1 1
Test2 1 0
Test3 0 1
Using the following sql I can generate the 1 but I cannot work out how to get the 0.
note: The sql to get the users in the categories is very much simplified from what I actually am using so may not be totally correct
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.CategoryName)
FROM Category c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Name, ' + #cols + ' from
(
SELECT Name
CategoryName,
1 as assigned
FROM User INNER JOIN
UserCategory ON User.ID = UserCategory.UserID
) x
pivot
(
max(assigned)
for CategoryName in (' + #cols + ')
) p '
execute(#query)
Can I update this to generate a 1/0, rather than a 1/null?
EDIT - Solution
Thanks to #Tab Allerman
I updated this so I had 2 cols variables
SET #colsForSelect = STUFF((SELECT distinct ', ISNULL(' + QUOTENAME(c.CategoryName) + ',0) AS ' + QUOTENAME(c.CategoryName)
FROM Category c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
and kept the original #cols.
I used the #colsForSelect in the beginning of the query and then the original #cols in the 'pivot for'.
I hope this makes sense to anyone who needs help
SET #cols = STUFF((SELECT distinct ', ISNULL(' + QUOTENAME(c.CategoryName) + ',0) AS ' + QUOTENAME(c.CategoryName)
I have the following SQL code that creates a very useful pivot table:
Use [A1_20132014]
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + Link_ID + ']', '[' + Link_ID + ']')
FROM (SELECT DISTINCT Link_ID FROM A1) PV
ORDER BY Link_ID
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT * FROM
(
-- We will select the data that has to be shown for pivoting
SELECT date_1, StartHour,Cost, Link_ID
FROM A1
WHERE Section = (''1AB'')
) x
PIVOT
(
-- Values in each dynamic column
SUM(Cost)
-- Select columns from #cols
FOR Link_ID IN (' + #cols + ')
) p;'
EXEC SP_EXECUTESQL #query
from these headings
link_id Section date_1 StartHour Cost data_source
4000000027866016A 8NB 2013-09-02 6 5871 1
4000000027866017B 5EB 2013-10-09 9 8965 2
4000000027856512B 4TB 2013-05-06 15 6754 1
4000000027866015A 6HB 2013-06-08 8 5354 1
4000000027866011A 1AB 2013-06-09 11 2 1
with these source types;
link_Id nvarchar(50)
Section nvarchar(50)
Date_1 smalldatetime
StartHour int
Cost float
data_source int
However despite WHERE clause that specifies a certain section unfortunately ALL sections still appear in the pivot table but populated with NULL values all the way down.
Is there a way of completely excluding the columns that do not meet the WHERE clause?
Thanks for any help.
Henry.
Put the where clause in the subquery. That way you'll only get columns that apply to 1AB
SELECT #cols = COALESCE (#cols + ',[' + Link_ID + ']', '[' + Link_ID + ']')
FROM (SELECT DISTINCT Link_ID FROM A1 WHERE Section = '1AB') PV
ORDER BY Link_ID