sql query, each column in result is a different WHERE clause [duplicate] - sql

This question already has answers here:
SQL Server dynamic PIVOT query?
(9 answers)
Closed 6 years ago.
I'm trying to find the easiest way to return some results based on dates.
So for example the table is like this
product date qty
corn 4/18/16 5
corn 4/18/16 1
corn 4/15/16 10
I would want the results to be
product 4/15/16 4/18/16
corn 10 6
So I am grouping by the product, sum the qty, but each column in result will be a different WHERE filedate = .
Can someone please point me in the right direction?

Try like this
SELECT * FROM
(
SELECT product,date,qty
FROM Table1
)X
PIVOT
(
SUM(X.qty)
FOR date IN([4/18/16],[4/15/16])
)Y
For multiple source, you need to write dynamic query like below
DECLARE #cols AS NVARCHAR(MAX),#query AS NVARCHAR(MAX)
;WITH CTE (DATELIST, MAXDATE) AS
(
SELECT '01/04/2016' DATELIST, '30/04/2016' MAXDATE
UNION ALL
SELECT DATEADD(dd, 1, DATELIST), MAXDATE
FROM CTE
WHERE DATELIST < MAXDATE
)
SELECT C.DATELIST
INTO #TempDates
FROM CTE C
SELECT #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(convert(CHAR(10), DATELIST, 120))
FROM #TempDates
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = 'SELECT product,' + #cols + ' FROM
(
SELECT B.product, B.date, B.qty, D.DATELIST, CONVERT(CHAR(10), DATELIST, 120) PivotDate
FROM #TempDates D
LEFT JOIN YourTable B ON D.DATELIST BETWEEN ''01/04/2016'' AND ''30/04/2016''
) X
PIVOT
(
SUM(qty)
FOR PivotDate IN (' + #cols + ')
) P '
EXECUTE(#query)

Related

How to properly create a Dynamic Pivot Function in SQL? [duplicate]

This question already has answers here:
Group by column and multiple Rows into One Row multiple columns
(2 answers)
Closed 8 months ago.
I come back with my problem. I've been trying to create a dynamic pivot procedure but I have some trouble while creating the columns.
Example:
TranID
Bank Name
NetAmount
Account
01
StormWindBank
23.0$
A
02
StormWindBank
14.0$
B
03
StormWindBank
00.0$
A
04
StormWindBank
12.0$
B
Result intended :
Account
Bank Name
NetAmount
NetAmount2
A
StormWindBank
23.0$
00.0$
B
StormWindBank
14.0$
12.0$
SELECT DISTINCT [Account]
,[Currency]
,TranID
,[Bank Code]
,[Bank Name]
,[Client No_]
,[NetAmount]
INTO #TEMP
FROM [My Table]
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.NetAmount)
FROM #TEMP c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT [Account], [Bank Name], ' + #cols + ' from
(
select [Account],TranID, NetAmount, [Bank Name]
from #TEMP
) x
pivot
(
max(TranID)
for NetAmount in (' + #cols + ')
) p '
So far, I have the result below:
Account
Bank Name
23.0$
00.0$
A
StormWindBank
1
2
B
StormWindBank
3
4
The 1, 2, 3, 4 are the TranID.
I'm close but I have been struggling to fix that, anyone have an idea ?
Thank you!
You need to PIVOT off a derived column using row_number()
Example
Declare #SQL varchar(max) = stuff( ( Select Distinct concat(',[NetAmount',row_number() over (partition by [Bank Name],[Account] order by [TranID]),']' )
From #TEMP For XML Path('') ),1,1,'')
Set #SQL = '
Select *
From (
Select [Account]
,[Bank Name]
,Item = concat(''NetAmount'',row_number() over (partition by [Bank Name],[Account] order by [TranID]) )
,Value = [NetAmount]
from #TEMP
) src
Pivot ( max( [Value] ) for Item in ('+ #SQL +') ) pvt
'
Exec(#SQL)
Results
Account Bank Name NetAmount1 NetAmount2
A StormWindBank 23.0$ 00.0$
B StormWindBank 14.0$ 12.0$

Pivot SQL table with dynamic year columns

I'm having trouble figuring this out. I've checked similar posts but they only have one column as pivoted as a row. While I need to pivot
I have the following query:
SELECT
Year([Date]) as Year
,SUM([Drop]) as [Drop]
,SUM([TicketsDistributed]) as [TicketsDistributed]
,SUM([TicketsSold]) as [TicketsSold]
,SUM([GrossTickets]) as [GrossTickets]
,SUM([GrossTickets])/SUM(TicketsSold) as 'Per Cap'
FROM [dbo].[Tickets]
group by [Date]
Which give me this result:
Year Drop TicketsDistributed TicketsSold GrossTickets Per Cap
2016 222 100 5000 4000.00 0.800000
2015 222 110 5000 4000.00 0.900000
2014 222 120 5000 4000.00 1.00000
And I would like the following:
2016 2015 2014
Drop 222 222 222
TicketsDistributed 100 110 120
TicketsSold 5000 5000 5000
GrossTickets 4000 4000 4000
Per Cap 0.8 0.9 1
Based on the suggested answer this is what I have so far but it's not working
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(Year(Date))
from [dbo].[SpringTrainings] t
cross apply
(
select SUM([Drop]) as [Drop]
,SUM([TicketsDistributed]) as [TicketsDistributed]
,SUM([TicketsSold]) as [TicketsSold]
,SUM([GrossTickets]) as [GrossTickets]
,SUM([GrossTickets])/SUM(TicketsSold) as PerCap
FROM [dbo].[SpringTrainings]
) c ([Drop],[TicketsDistributed],[TicketsSold],[GrossTickets],PerCap)
group by Year(Date)
order by Year(Date)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT [Drop],[TicketsDistributed],[TicketsSold],[GrossTickets],PerCap,' + #cols + '
from
(
select SUM([Drop]) as [Drop]
,SUM([TicketsDistributed]) as [TicketsDistributed]
,SUM([TicketsSold]) as [TicketsSold]
,SUM([GrossTickets]) as [GrossTickets]
,SUM([GrossTickets])/SUM(TicketsSold) as PerCap
FROM [dbo].[SpringTrainings]
) x
pivot
(
max(Year([Date]))
for Year([Date]) in (' + #cols + ')
) p '
execute sp_executesql #query;
If you wish to keep using the pivot operator within T-SQL, then first you need to "unpivot" your existing query so you have Year, Label, and Value. While there is an unpivot operator in T-SQL personally I find using CROSS APPLY and VALUES to be much simpler and equally as fast (for more on his approach read this article by Brad Schultz), I particularly like it because I can visualize the result easily by the way I layout the value pairs.
SELECT
d.Year
, a.label
, a.value
FROM (
SELECT
YEAR([Date]) AS [Year]
, SUM([Drop]) AS [Drop]
, SUM([TicketsDistributed]) AS [TicketsDistributed]
, SUM([TicketsSold]) AS [TicketsSold]
, SUM([GrossTickets]) AS [GrossTickets]
, SUM([GrossTickets]) / SUM(TicketsSold) AS [PerCap]
FROM [dbo].[Tickets]
GROUP BY
[Year]
) AS t
CROSS APPLY ( /* now transform into 5 rows per year but just 1 value column */
VALUES
('Drop',t.Drop)
, ('TicketsDistributed',t.TicketsDistributed)
, ('TicketsSold',t.TicketsSold)
, ('GrossTickets',t.GrossTickets)
, ('PerCap',t.PerCap)
) AS a (label, value)
That query (above) replaces the derived table x in your dynamic SQL. Once the data has been massaged into that form the pivot looks way simpler:
) x
pivot
(
max([x.Value])
for [x.Year] in ([2014],[2015],[2016])
) p
For your #cols I would suggest something simple like this:
SELECT DISTINCT
QUOTENAME(Year([date]))
FROM [dbo].[Tickets]
TIP: if you need a way to order the rows, include that in the cross apply too, like this:
CROSS APPLY ( /* now transform into 5 rows per year but just 1 value column */
VALUES
(1, 'Drop',t.Drop)
, (2, 'TicketsDistributed',t.TicketsDistributed)
, (3, 'TicketsSold',t.TicketsSold)
, (4, 'GrossTickets',t.GrossTickets)
, (5, 'PerCap',t.PerCap)
) AS a (row_order, label, value)
and then that [row_order] can be used after the pivot is performed.
So the overall could look like this:
DECLARE #cols AS nvarchar(max)
, #query AS nvarchar(max)
SELECT #cols = STUFF((
SELECT DISTINCT
',' + QUOTENAME(YEAR([date]))
FROM [dbo].[Tickets]
FOR xml PATH (''), TYPE
)
.value('.', 'NVARCHAR(MAX)')
, 1, 1, '')
SET #query = 'SELECT [Year], [Label], '
+ #cols
+ ' FROM (
SELECT
d.Year
, a.label
, a.value
FROM (
SELECT
YEAR([Date]) AS [Year]
, SUM([Drop]) AS [Drop]
, SUM([TicketsDistributed]) AS [TicketsDistributed]
, SUM([TicketsSold]) AS [TicketsSold]
, SUM([GrossTickets]) AS [GrossTickets]
, SUM([GrossTickets]) / SUM(TicketsSold) AS [PerCap]
FROM [dbo].[Tickets]
GROUP BY
[Year]
) AS d
CROSS APPLY (
VALUES
(1,''Drop'',t.Drop)
, (2,''TicketsDistributed'',t.TicketsDistributed)
, (3,''TicketsSold'',t.TicketsSold)
, (4,''GrossTickets'',t.GrossTickets)
, (5,''PerCap'',t.PerCap)
) AS a (row_order,label,value)
) x
pivot
(
max([x.Value])
for [x.Year] in (' + #cols + ')
) p
ORDER BY [row_order]'
EXECUTE sp_executesql #query;

Dynamic pivot query in sql server

I have a functioning pivot query for static column values which i want to convert for dynamic column values.
The query is :
with a as (
select request_id, dateadd(month,datediff(month,0,logged_datetime),0) as 'Month'
,dateadd(month,datediff(month,0,logged_datetime),0) as 'Year'
from requests
)
select * from (
select datepart(m,a.Month) as 'months',datepart(YEAR,a.Year) as 'years',a.request_id
from a ) ps
pivot (
count(request_id) for [years] in ([2008],[2009],[2010],[2011],[2012],[2013],[2014],[2015])
) as pvt
order by months
For the dynamic query written below I am getting errors like
Msg 207, Level 16, State 1, Line 5 Invalid column name '2010'. :
select distinct datepart(year,dateadd(month,datediff(month,0,logged_datetime),0)) as 'Yearz'
into #t
FROM requests
DECLARE #Dynamic AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
SELECT #ColumnName= ISNULL(#ColumnName + ',','')
+ QUOTENAME(Yearz)
FROM (SELECT * from #t) AS Yea
SET #Dynamic =
N'
select * from (
select datepart(m,dateadd(month,datediff(month,0,logged_datetime),0)) as months,' + #ColumnName + ',request_id
from requests ) ps
pivot (
count(request_id) for [Years] in (' + #ColumnName + ')
) as pvt
order by months
'
EXEC sp_executesql #Dynamic
SAMPLE TABLE
SELECT * INTO #REQUESTS
FROM
(
SELECT 1 request_id, '2012-06-01' logged_datetime
UNION ALL
SELECT 2 request_id, '2012-05-01'
UNION ALL
SELECT 11 request_id, '2012-06-01'
UNION ALL
SELECT 12 request_id, '2012-05-01'
UNION ALL
SELECT 3 request_id, '2012-07-01'
UNION ALL
SELECT 4 request_id, '2013-09-01'
UNION ALL
SELECT 5 request_id, '2013-10-01'
UNION ALL
SELECT 6 request_id, '2014-01-01'
UNION ALL
SELECT 7 request_id, '2014-02-01'
UNION ALL
SELECT 8 request_id, '2014-03-01'
UNION ALL
SELECT 9 request_id, '2014-05-01'
UNION ALL
SELECT 10 request_id, '2015-11-01'
)TAB
QUERY
Get the column for years and order it in numeric order
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + CAST([YEAR] AS VARCHAR(4)) + ']', '[' + CAST([YEAR] AS VARCHAR(4)) + ']')
FROM (SELECT DISTINCT YEAR(dateadd(month,datediff(month,0,logged_datetime),0)) [YEAR] FROM #REQUESTS) PV
ORDER BY CAST([YEAR] AS INT)
Now pivot the query
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT * FROM
(
-- We will get the count for a year and number of request_id in that month here as CNT column
select DISTINCT datepart(m,a.Month) as ''months'',datepart(YEAR,a.Year) as ''years'',
COUNT(*) OVER(PARTITION BY datepart(YEAR,a.Year),datepart(m,a.Month)) CNT
from
(
select request_id, dateadd(month,datediff(month,0,logged_datetime),0) as ''Month''
,dateadd(month,datediff(month,0,logged_datetime),0) as ''Year''
from #requests
)a
) x
PIVOT
(
MIN(CNT)
FOR years IN (' + #cols + ')
) p
ORDER BY MONTHS;'
EXEC SP_EXECUTESQL #query
Click here to view the result
I think you need to wrap your dynamic column names using the QUOTENAME function:
See example here:

Adding a WHERE statement refering another table in Dynamic SQL

I currently have the following script which is pivoting results from rows into columns. It works a Great, apart from two issues;
I have a flag in another table which I want to filter by (basically: WHERE Table.Stats=YES). I'd normally do this in a basic query with an inner join followed by that WHERE statement. In the query below, I already have a WHERE FileSeq=25, which works, but this criteria I need to get working is calling on a different table.
The query is returning a lot of uncessary NULL fields.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(col+CAST(rn AS varchar(6)))
FROM
(
SELECT row_number() over(partition by UID ORDER BY ClassCode) rn
FROM dbo.StudentClasses
) d
CROSS APPLY
(
SELECT 'ClassCode', 1
) c (col, so)
GROUP BY col, rn, so
ORDER BY rn, so
FOR XML PATH(''), TYPE
).VALUE('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT UID,' + #cols + '
FROM
(
SELECT UID, col+CAST(rn AS varchar(10)) col, VALUE
FROM
(
SELECT UID, classcode,
row_number() over(partition by UID ORDER BY classcode) rn
FROM StudentClasses WHERE FileSeq=25
) t
CROSS APPLY
(
SELECT ''classcode'', CAST(classcode AS varchar(6))
) c (col, VALUE)
) x
PIVOT
(
MAX(VALUE)
for col in (' + #cols + ')
) p '
EXECUTE(#query)
Any assistance appreciated

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