Pivot table error - sql

WHY, why, why? Do I get an error:
"Msg 325, Level 15, State 1, Line 17
Incorrect syntax near 'PIVOT'. You may need to set the compatibility level of the current database to a higher value to enable this feature. See help for the stored procedure sp_dbcmptlevel."
For this query?
WITH Offnet7 AS (
SELECT disposition.dispositiondesc, interaction.dispositionid, DATEPART(wk,interaction.ibegintime) as iWeek
FROM interaction INNER JOIN
disposition ON interaction.reasonid = disposition.dispositionid
WHERE interaction.dispositionid = 10 and (reasonid = 20365 or reasonid = 20366 or reasonid = 11168) and
interaction.ibegintime >= '2013-1-1' and
interaction.ibegintime < '2014-1-1'
)
SELECT iWeek, dispositiondesc, count(iWeek) as 'OffnetCounts'
FROM Offnet7
Group by dispositiondesc, iWeek
PIVOT
(
OffnetCounts
for iWeek in ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15])
) AS counts
EDIT:
Tried to make a SQL Fiddle, and it choked when I went to "Build Schema." (SQL Noob)
I pulled the types from SQL management studio's object explorer and copied some example data. But this is what I attempted:
CREATE TABLE interaction
([reasonid] int, [dispositionid] int, [ibegintime] datetime)
;
INSERT INTO interaction
([reasonid], [dispositionid], [ibegintime])
VALUES
(20366, 10, '2012-01-31 23:59:48.000'),
(20366, 10, '2012-02-07 14:03:01.000'),
(20366, 10, '2012-02-07 14:06:48.000'),
(20366, 10, '2012-02-13 21:44:10.000'),
(20366, 10, '2012-02-27 21:36:33.000')
;
CREATE TABLE disposition
([dispositionid] int, [predefined] int, [dispositiondesc] varchar(64), [displayvalue] varchar(254))
;
INSERT INTO disposition
([dispositionid], [predefined], [dispositiondesc], [displayvalue])
VALUES
(10, 1, 'TRANSFERRED OFFNET', 'TRANSFERRED OFFNET'),
(11168, 0, 'TAKEDA PASSWORD', 'TAKEDA PASSWORD'),
(15433, 0, 'Voice Mail - TAKEDAEMEA', 'Voice Mail - TAKEDAEMEA'),
(20365, 0, 'TAKEDA iPAD, iPhone or BlackBerry', 'TAKEDA iPAD, iPhone or BlackBerry'),
(20366, 0, 'TAKEDA Concur', 'TAKEDA Concur')
;
Conclusion:
Thanks for all the help Bluefeet!
For anyone interested in this, his first answer WOULD HAVE worked if the SQL compatibility level was set correctly by my DBA. After trying his first answer I got a:
"Msg 102, Level 15, State 1, Line 19 Incorrect syntax near '('."
Because the DBA doesn't have the SQL Server configured with a compatibility level that supports the PIVOT statement.

Your syntax is off. The PIVOT is doing the GROUP BY and an aggregation. It seems to me that you want to be using:
WITH Offnet7 AS
(
SELECT disposition.dispositiondesc,
interaction.dispositionid,
DATEPART(wk,interaction.ibegintime) as iWeek
FROM interaction
INNER JOIN disposition
ON interaction.reasonid = disposition.dispositionid
WHERE interaction.dispositionid = 10
and (reasonid = 20365 or reasonid = 20366 or reasonid = 11168)
and interaction.ibegintime >= '2013-1-1'
and interaction.ibegintime < '2014-1-1'
)
SELECT dispositiondesc,
[1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15]
FROM Offnet7
PIVOT
(
count(dispositionid)
for iWeek in ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15])
) AS counts;
See Demo
This will create a table of data with the counts of the dispositionid's for each week, grouped by the dispositiondesc.
Edit, this can also be done using an aggregate function with a CASE expression:
SELECT disposition.dispositiondesc,
sum(case when DATEPART(wk,interaction.ibegintime) = 1 then 1 else 0 end) [1],
sum(case when DATEPART(wk,interaction.ibegintime) = 2 then 1 else 0 end) [2],
sum(case when DATEPART(wk,interaction.ibegintime) = 3 then 1 else 0 end) [3],
sum(case when DATEPART(wk,interaction.ibegintime) = 4 then 1 else 0 end) [4],
sum(case when DATEPART(wk,interaction.ibegintime) = 5 then 1 else 0 end) [5],
sum(case when DATEPART(wk,interaction.ibegintime) = 6 then 1 else 0 end) [6],
sum(case when DATEPART(wk,interaction.ibegintime) = 7 then 1 else 0 end) [7],
sum(case when DATEPART(wk,interaction.ibegintime) = 8 then 1 else 0 end) [8],
sum(case when DATEPART(wk,interaction.ibegintime) = 9 then 1 else 0 end) [9],
sum(case when DATEPART(wk,interaction.ibegintime) = 10 then 1 else 0 end) [10],
sum(case when DATEPART(wk,interaction.ibegintime) = 11 then 1 else 0 end) [11],
sum(case when DATEPART(wk,interaction.ibegintime) = 12 then 1 else 0 end) [12],
sum(case when DATEPART(wk,interaction.ibegintime) = 13 then 1 else 0 end) [13],
sum(case when DATEPART(wk,interaction.ibegintime) = 14 then 1 else 0 end) [14],
sum(case when DATEPART(wk,interaction.ibegintime) = 15 then 1 else 0 end) [15]
FROM interaction
INNER JOIN disposition
ON interaction.reasonid = disposition.dispositionid
WHERE interaction.dispositionid = 10
and (reasonid = 20365 or reasonid = 20366 or reasonid = 11168)
and interaction.ibegintime >= '2013-1-1'
and interaction.ibegintime < '2014-1-1'
group by disposition.dispositiondesc;
See SQL Fiddle with Demo

Related

Arrange a single column data in multiple columns in SQL Server

I have the following table(raw data). I would like to see the data in following format(Formatted Data).
I tried the following query. It produces a rather weird result. Could someone guide me here how to achieve this.
declare #monthnames varchar(100)
select distinct [Month], MonthNumber
into #Months
from Table
order by MonthNumber
SELECT #monthnames = Stuff((SELECT ', ' + [Month]
FROM #Months
order by MonthNumber
FOR XML PATH('')
), 1, 2, '')
declare #query varchar(500)
set #query = 'select CUR,' + #monthnames +
' from ' +
' Pivot ( min(DATE) for [Month] in (' + #monthnames + ') ) as Pivottable ORDER BY CUR'
EXEC (#query)
You don't really need to use Dynamic SQL as you have a fixed number of pivoting columns.
What you are missing is the rn, so that each date appear under different row
SELECT CUR,
[1] as Jan,
[2] as Feb,
[3] as Mar,
[4] as Apr,
[5] as May
FROM (
SELECT CUR, MonthNumber, DATE,
rn = ROW_NUMBER() OVER (PARTITION BY CUR, MonthNumber ORDER BY DATE)
FROM #Table
) AS d
PIVOT
(
MIN(DATE)
FOR MonthNumber IN ([1], [2], [3], [4], [5])
) AS p
declare #t table
(
CUR varchar(10),
[Month] varchar(20),
MonthNumber tinyint,
[Date] date
);
insert into #t(Cur, [Month], MonthNumber, [Date])
values
('AED', 'January', 1, '20200110'),
('AED', 'February', 2, '20200212'),('AED', 'February', 2, '20200215'),
('AED', 'March', 3, '20200305'),('AED', 'March', 3, '20200305'),('AED', 'March', 3, '20200305'),
('AED', 'April', 4, '20200402'),('AED', 'April', 4, '20200412'),('AED', 'April', 4, '20200415'),
('AED', 'June', 6, '20200619'),
('AED', 'August', 8, '20200801'),('AED', 'August', 8, '20200805'),('AED', 'August', 8, '20200810'), ('AED', 'August', 8, '20200824'),
----
('ARS', 'January', 1, '20200118'),
('ARS', 'April', 4, '20200416'),
('ARS', 'May', 5, '20200512'), ('ARS', 'May', 5, '20200513'), ('ARS', 'May', 5, '20200514'),
('ARS', 'September', 9, '20200902'),('ARS', 'September', 9, '20200922');
select CUR, [January],[February],[March],[April],[May],[June],[July],[August],[September],[October],[November],[December]
from
(
select CUR, [Date], dense_rank() over(partition by CUR, [Month] /*or MonthNumber*/ order by [Date]) as ranking,
[Month]
from #t
) as t
pivot
(
min([Date]) for [Month] in ([January],[February],[March],[April],[May],[June],[July],[August],[September],[October],[November],[December])
) as pvt
order by CUR;

How to show NULL instead of 0 when using sum aggregate / pivoting

Consider this 24-hour summary. The problem is that I'm getting 0s returned for hours where values haven't been inserted yet. I believe this is due to the SUM() function call.
SELECT
section,
[21], [22], [23], [0], [1], [2], [3], [4], [5], [6], [7], [8],
[21] + [22] + [23] + [0] + [1] + [2] + [3] + [4] + [5] + [6] + [7] + [8] as s1_total
-- shift 2 fields are ommitted for brievity
FROM (
SELECT
section,
-- hours from 21:00 (1st shift) to 20:00 (2nd shift)
SUM(CASE WHEN prTime = '21:00:00' THEN Amount ELSE 0 END) AS [21],
SUM(CASE WHEN prTime = '22:00:00' THEN Amount ELSE 0 END) AS [22],
SUM(CASE WHEN prTime = '23:00:00' THEN Amount ELSE 0 END) AS [23],
SUM(CASE WHEN prTime = '00:00:00' THEN Amount ELSE 0 END) AS [0],
SUM(CASE WHEN prTime = '01:00:00' THEN Amount ELSE 0 END) AS [1],
SUM(CASE WHEN prTime = '02:00:00' THEN Amount ELSE 0 END) AS [2],
-- ... similar cases are omitted for brieviety
SUM(CASE WHEN prTime = '20:00:00' THEN Amount ELSE 0 END) AS [20]
FROM (
SELECT prTime, prDate, section01 AS Amount, 'section 1' as [Section] FROM SectionsHourlyValues
UNION
SELECT prTime, prDate, section02 AS Amount, 'section 2' as [Section] FROM SectionsHourlyValues
UNION
SELECT prTime, prDate, section03 AS Amount, 'section 3' as [Section] FROM SectionsHourlyValues
) AS U
WHERE
(prDate = CONVERT(DATE, DATEADD(HOUR, -4, CONVERT(DATETIME2(7), #dt, 104))) and prTime > '20:00:00') or
(prDate = CONVERT(DATE, #dt, 104) and prTime <= '20:00:00')
GROUP BY section
) t;
For example, running the query
DECLARE #dt varchar(10) = 'certain_date';
SELECT * from [dbo].[SectionsHourlyValues] WHERE
(prDate = CONVERT(DATE, DATEADD(HOUR, -4, CONVERT(DATETIME2(7), #dt, 104))) and prTime > '20:00:00') or
(prDate = CONVERT(DATE, #dt, 104) and prTime <= '20:00:00');
wouldn't return us the data for say 09:00:00 / section1 whereas the summary would show us 0.
Then I want to show NULL (for not yet inserted records) instead of 0. How do I do that?
How about replacing the 0 with NULL in your conditional aggregation ?
SUM(CASE WHEN etc... ELSE NULL END)
Use NULLIF
ex
NULLIF(SUM(CASE WHEN prTime = '21:00:00' THEN Amount ELSE 0 END),0)
or simply do not use ELSE
SUM(CASE WHEN prTime = '21:00:00' THEN Amount END)
You're getting 0 values not due to the SUM function for values not yet inserted (that would be NULL and would ignored by the SUM function), but because the ELSE of your CASE statement returns 0:
SUM(CASE WHEN prTime = '21:00:00' THEN Amount ELSE 0 END) AS [21]
To solve your problem, you can use NULLIF that is rather similar to CASE:
NULLIF(MyExpressionThatCouldReturn0, 0)
That in your case would be:
NULLIF(SUM(CASE WHEN prTime = '01:00:00' THEN Amount ELSE 0 END),0)
Otherwise, as said before, do not use ELSE in the CASE statement, used as parameter of your SUM:
SUM(CASE WHEN prTime = '21:00:00' THEN Amount END)

Need help converting sql query with pivot to LINQ

Can someone help me convert the following to LINQ? as I am new to C# and link
SELECT
DayWise, [1] AS Lead1, [2] AS Lead2, [3] AS Lead3,
[4] AS Lead4, [5] AS Lead5, [19] AS Greater
FROM (
SELECT CONVERT(VARCHAR(10), dt_createdon, 101) AS DayWise,
COUNT(int_queryid) AS leadcount ,
int_queryid
FROM tx_searchedresponse
GROUP BY CONVERT(VARCHAR(10), dt_createdon, 101) ,int_queryid) A
PIVOT(
COUNT(leadcount)
FOR leadcount IN ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10],
[11], [12], [13], [14], [15], [16], [17], [18], [19])
) p order by DayWise

How can I assign a normal table from a dynamic pivot table?

I need to make a report in Stimulsoft from the last 12 months from our current date, I used dynamic pivot table to make this, the original table is at figure 1
Then the pivot table is like the figure 2 (bigger image link here: http://i.stack.imgur.com/LPCuP.jpg)
The DACP_Value at figure 1 is the row at the date it corresponds at figure 2. Note that the culture is set to pt-BR (brazil)
Here is a sample code of the generation of the pivot table made in SQLFiddle
http://www.sqlfiddle.com/#!3/3205a/23
I need to put this dynamic data with the headers inside a normal table (it can be a temporary table) so I can use it in my report query and be recognized by the Stimulsoft software.
Add INTO YourTable after the SELECT on your code:
DECLARE #Col NVARCHAR(MAX) =
( SELECT ', ' + QUOTENAME(CONVERT(VARCHAR, DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP) - (12 - Number), 0), 103)) + ' = [' + CAST(number AS VARCHAR) + ']'
FROM Master..spt_values
WHERE Type = 'P'
AND number BETWEEN 0 AND 12
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
DECLARE #SQL NVARCHAR(MAX) =
N'WITH Data AS
( SELECT DACP_ID,
DACP_Value,
[MonthNum] = 12 - DATEDIFF(MONTH, DACP_Date, CURRENT_TIMESTAMP)
FROM yourtable
WHERE DATEDIFF(MONTH, DACP_Date, CURRENT_TIMESTAMP) BETWEEN 0 AND 12
)
SELECT DACP_ID' + #Col + '
INTO YourTable --Add this line here
FROM Data
PIVOT
( SUM(DACP_Value)
FOR MonthNum IN ([0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12])
) pvt;'
EXECUTE SP_EXECUTESQL #SQL
As a way, you can use the master-detail report in Stimulsoft tool.
As master table you can use the table with date only:
SELECT CONVERT(DATE, DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP) - (12 - Number), 0), 103) AS DT,
CONVERT(VARCHAR(2),MONTH(DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP) - (12 - Number), 0))) + CONVERT(VARCHAR(4),YEAR(DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP) - (12 - Number), 0))) As MonthYear
FROM Master..spt_values
WHERE Type = 'P'
AND number BETWEEN 0 AND 12
The detail table it's "yourTable" with additional column:
select *, convert(varchar(2),Month(DACP_date)) + convert(varchar(4),Year(DACP_date)) as MonthYear from yourtable
realtion on MonthYear columns.
In report you can use the Cross-Data component for master data, and DataBand component for detail data.
Please see the image from the following link:
http://imgur.com/Ve03BXU
Also this is a solution for the case when the amount of data for each date is the same, ie ID for each date are the same. If not, one may have to add more conditions for showing headers on the left side.

SQL Comma Separated List from Multiple Columns

I have data that looks like this:
CUSTOMER_ID OPERDAYSJUL OPERDAYSAUG OPERDAYSSEP ... OPERDAYSJUN
1 30 15 2
2 5 1 0
3 6 0 12
4 12 5 23
For each customer_id, I want a comma-delimited list indicating which months the customer operates:
CUSTOMER_ID OPERATING_MONTHS
1 Jul, Aug, Sep
2 Jul, Aug
3 Jul, Sep
4 Jul, Aug, Sep
and so forth. How might I use SQL Server 2005 SQL (not T-SQL) to easily produce this comma-delimited list?
Most solutions I see here on Stack Overflow and elsewhere seem to create comma-separated lists based on joining multiple rows values, not column values:
T-SQL
FOR XML PATH('')
Correlated subquery combined with REPLACE/STUFF/SUBSTRING
Am I missing something obvious? Thanks in advance for assistance or pointer to appropriate existing solution here.
This strips off the extra comma
SELECT
CUSTOMER_ID,
SUBSTRING(
CASE WHEN OPERDAYSJUL > 0 THEN ', Jul' ELSE '' END +
CASE WHEN OPERDAYSAUG > 0 THEN ', Aug' ELSE '' END +
...
CASE WHEN OPERDAYSJUN > 0 THEN ', Jun' ELSE '' END,
3, 255)
FROM TheTable
declare #t table (CUSTOMER_ID int
, OPERDAYSJUL int
, OPERDAYSAUG int
, OPERDAYSSEP int
-- ... rest of 9 months here
);
insert into #t (CUSTOMER_ID, OPERDAYSJUL, OPERDAYSAUG, OPERDAYSSEP)
select 1, 30, 15, 22 union all
select 2, 0, 10, 10 union all
select 3, 0, 0, 10 union all
select 4, 0, 0, 0 union all
select 5, 10, 0, 10 union all
select 6, 10, 10, 0 union all
select 7, 0, 10, 0 union all
select 8, 10, 0, 0;
with cte_months as (
select CUSTOMER_ID
, case when OPERDAYSJUL=0 then '' else ', Jul' end
+ case when OPERDAYSAUG=0 then '' else ', Aug' end
+ case when OPERDAYSSEP=0 then '' else ', Sep' end
-- ... rest of 9 months here
as month_list
from #t)
select CUSTOMER_ID, substring(month_list, 3, 70)
from cte_months;
You can do something like this.
CONCAT(CASE OPERDAYSJUL > 0 THEN "Jul," ELSE "" END,CASE OPERDAYSAUG > 0 THEN "Aug" ELSE "" END ... )
Assuming your table has 13 columns (1 for each month of the year + CUSTOMER_ID), you can write something like:
SELECT
CUSTOMER_ID,
CASE OPERDAYSJUL > 0 THEN 'Jul,' ELSE '' END +
CASE OPERDAYSAUG > 0 THEN 'Aug,' ELSE '' END +
...
FROM MyTable
and build up a string that represents your comma-separated list using CASE statements, one for each month.
select
customer_id,
case when len(operating_month) > 0 then
left(operating_month, len(operating_month) - 1)
else
operating_month
end as operating_month
from
(
SELECT CUSTOMER_ID,
CASE OPERDAYSJUL > 0 THEN 'Jul,' ELSE '' END
+ CASE OPERDAYSAUG > 0 THEN 'Aug,' ELSE '' END
+ ...
as operating_month
FROM MyTable
) as x