Dynamic Columns Pivot returning multiple rows - SQL Server 2014 - sql

I am trying to write a PIVOT query on dynamic columns. It works but it is returning multiple rows.
My query is
set #query = 'select PanelID, PanelCode, PanelName, EvaluatorID, PersonID, ApplicationID, ' + #cols + ' from (
select
distinct p.PanelID, p.PanelCode, p.PanelName, e.EvaluatorID, e.PersonID, ppl.LastName, pApps.ApplicationID, ev.AnswerNumeric
from
tblpanels p inner join tblEvaluators e on p.PanelID = e.PanelID
inner join tblPeople ppl on ppl.PersonID = e.PersonID
inner join tblPanelApps pApps on pApps.PanelID = p.PanelID
inner join tblEvaluations ev on ev.ApplicationID = pApps.ApplicationID and ev.EvaluatorID = e.EvaluatorID
where
p.PanelID in (1234, 3656)
)tmp
PIVOT
(
max(AnswerNumeric)
For LastName IN (' + #cols + ')
) As P
Order By PanelID, ApplicationID'
execute(#query)
The output is coming as
+=========+===========+===========+=============+==========+===============+======+=======+
| PanelID | PanelCode | PanelName | EvaluatorID | PersonID | ApplicationID | John | Carol |
+=========+===========+===========+=============+==========+===============+======+=======+
| 1234 | 12123412 | Panel A | 3674 | 4834 | 112233 | 6 | NULL |
+---------+-----------+-----------+-------------+----------+---------------+------+-------+
| 1234 | 12123412 | Panel A | 3674 | 4834 | 112233 | NULL | 4 |
+---------+-----------+-----------+-------------+----------+---------------+------+-------+
It should be one row only per ApplicationID. How can I fix this query for below output?
+=========+===========+===========+=============+==========+===============+======+=======+
| PanelID | PanelCode | PanelName | EvaluatorID | PersonID | ApplicationID | John | Carol | Total
+=========+===========+===========+=============+==========+===============+======+=======+
| 1234 | 12123412 | Panel A | 3674 | 4834 | 112233 | 6 | 4 | 10
+---------+-----------+-----------+-------------+----------+---------------+------+-------+
EDIT: I also need a total score at the end for each row.

I fixed it. The evaluatorID and the PersonID were causing the issue. I took them off from the subquery and it is now fixed. I also added the Total column. The updated query is
set #query = 'select PanelID, PanelCode, PanelName, ApplicationID,
' + #cols + ', (ISNULL(' + REPLACE(#cols, ',', ',0.) + ISNULL(') + ',0.)) AS TOTAL from (
select
distinct p.PanelID, p.PanelCode, p.PanelName, pApps.ApplicationID, ppl.LastName, isnull(ev.AnswerNumeric, 0) as AnswerNumeric
from
tblpanels p inner join tblEvaluators e on p.PanelID = e.PanelID
inner join tblPeople ppl on ppl.PersonID = e.PersonID
inner join tblPanelApps pApps on pApps.PanelID = p.PanelID
left join tblEvaluations ev on ev.ApplicationID = pApps.ApplicationID and ev.EvaluatorID = e.EvaluatorID
where
p.PanelID in (1234, 3656)
)tmp
PIVOT
(
max(AnswerNumeric)
For LastName IN (' + #cols + ')
) As P
Order By PanelID, ApplicationID'
--print #query
execute(#query)

Related

SQL: SUM on Aggregate columns

I have this query:
SELECT
spend_codes.spend_code,
SUM(orders.shipping_cost + orders.sales_tax + orders.manual_total + orders.fees) as order_total,
SUM(ordered_items.fees + ordered_items.price * ordered_items.quantity) as item_total
FROM spend_codeables
LEFT JOIN spend_codes
ON spend_codeables.spend_code_id = spend_codes.id
LEFT JOIN orders
ON spend_codeables.spend_codeable_id = orders.id AND spend_codeables.spend_codeable_type = 'App\Order'
LEFT JOIN ordered_items
ON spend_codeables.spend_codeable_id = ordered_items.id AND spend_codeables.spend_codeable_type = 'App\OrderedItem'
GROUP BY
spend_codes.spend_code;
Which has this result:
+--------------+---------------+--------------+
| spend_code | order_total | item_total |
|--------------+---------------+--------------|
| 1230131391 | $362.00 | <null> |
| A12345 | <null> | <null> |
| B29393 | <null> | $374.28 |
+--------------+---------------+--------------+
However, I'd like to add order_total and item_total in order to get just total.
So I'd expect this:
+--------------+---------------+
| spend_code | total |
|--------------+---------------+
| 1230131391 | $362.00 |
| A12345 | <null> |
| B29393 | $374.28 |
+--------------+---------------+
Doing this did not work:
SUM(orders.shipping_cost + orders.sales_tax + orders.manual_total + orders.fees) +
SUM(ordered_items.fees + ordered_items.price * ordered_items.quantity) as total
Another monkeywrench is that the type of the numbers is money not integer.
Anyone would be able to help?
If any of the 2 sums returns NULL then the result of the sum of the sums will also be NULL because NULL + anything returns NULL.
Use SUM() only once:
SUM(
orders.shipping_cost +
orders.sales_tax +
orders.manual_total +
orders.fees +
ordered_items.fees +
ordered_items.price * ordered_items.quantity
) as total
If any of the columns involved may also be NULL use COALESCE() like COALESCE(orders.shipping_cost, 0::money)
you do it in next step using sub query and I used coalesce() for avoid null
with cte as ( SELECT
spend_codes.spend_code,
SUM(orders.shipping_cost + orders.sales_tax + orders.manual_total + orders.fees) as order_total,
SUM(ordered_items.fees + ordered_items.price * ordered_items.quantity) as item_total
FROM spend_codeables
LEFT JOIN spend_codes
ON spend_codeables.spend_code_id = spend_codes.id
LEFT JOIN orders
ON spend_codeables.spend_codeable_id = orders.id AND spend_codeables.spend_codeable_type = 'App\Order'
LEFT JOIN ordered_items
ON spend_codeables.spend_codeable_id = ordered_items.id AND spend_codeables.spend_codeable_type = 'App\OrderedItem'
GROUP BY
spend_codes.spend_code
) select spend_code,coalesce(order_total,0)+coalesce(item_total,0) as total from cte

How to export report and mark a column with data?

This is hard to explain but I'll try. I need to export a report that shows which stores have locations in which states.
Suppose I have the following table:
+----------+-----------+
| STORE_ID | STATE_ABV |
+----------+-----------+
| 1 | AK |
| 1 | AL |
| 1 | AR |
| 2 | MI |
| 2 | OH |
| 2 | IN |
| 3 | CA |
| 3 | NV |
+----------+-----------+
The STORE_ID column is a key to another table where I just need to pull out the STORE_NAME column.
+----------+------------+
| STORE_ID | STORE_NAME |
+----------+------------+
| 1 | Walmart |
| 2 | Target |
| 3 | Kroeger's |
+----------+------------+
What I want is to export a list of each store along with columns for all states. If the store is available in that state, I want to place an "X" for the value.
So the desired output looks like this:
+------------+----+----+----+----+----+----+----+----+
| STORE_NAME | AK | AL | AR | CA | IN | OH | MI | NV |
+------------+----+----+----+----+----+----+----+----+
| Walmart | X | X | X | | | | | |
| Target | | | | | X | X | X | |
| Kroeger's | | | | X | | | | X |
+------------+----+----+----+----+----+----+----+----+
Is this possible in SQL Server? How would I write such a query? There should be a column for every STATE_ABV that exists in the table.
As mentioned, what you are after here is to pivot your data. Personally I dislike the PIVOT functionality of SQL Server, and much more prefer using a Cross-Tab (aka conditional aggregation).
As I suspect that this is going to require a dynamic pivot, I've done that as well:
--Sample tables
CREATE TABLE dbo.StoreLocations (StoreID int,
StateAbv char(2));
CREATE TABLE dbo.Stores (StoreID int IDENTITY,
StoreName varchar(20));
GO
--Sample data
INSERT INTO dbo.Stores (StoreName)
VALUES('Walmart'),('Target'),('Kroeger''s');
INSERT INTO dbo.StoreLocations (StoreID,StateAbv)
VALUES(1,'AK'),
(1,'AL'),
(1,'AR'),
(2,'MI'),
(2,'OH'),
(2,'IN'),
(3,'CA'),
(3,'NV');
GO
--Quick sample to get the format right
SELECT S.StoreName,
IIF(COUNT(CASE WHEN SL.StateAbv = 'AK' THEN 1 END) = 0,NULL, 'X') AS AK
FROM dbo.Stores S
LEFT JOIN dbo.StoreLocations SL ON S.StoreID = SL.StoreID
GROUP BY S.StoreName;
GO
--The real solution
DECLARE #SQL nvarchar(MAX);
SET #SQL = N'SELECT S.StoreName,' + NCHAR(13) + NCHAR(10) +
STUFF((SELECT N',' + NCHAR(13) + NCHAR(10) +
N' IIF(COUNT(CASE WHEN SL.StateAbv = ' + QUOTENAME(SL.StateAbv,'''') + N' THEN 1 END) = 0, NULL,''X'') AS ' + QUOTENAME(SL.StateAbv)
FROM dbo.StoreLocations SL
GROUP BY SL.StateAbv --Could use DISTINCT too
ORDER BY SL.StateAbv
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,3,N'') + NCHAR(13) + NCHAR(10) +
N'FROM dbo.Stores S' + NCHAR(13) + NCHAR(10) +
N' LEFT JOIN dbo.StoreLocations SL ON S.StoreID = SL.StoreID' + NCHAR(13) + NCHAR(10) +
N'GROUP BY S.StoreName;';
PRINT #SQL; --Your best friend
EXEC sp_executesql #SQL;
GO
--Clean up
DROP TABLE dbo.Stores;
DROP TABLE dbo.StoreLocations;
db<>fiddle
I foolishly assumed that the state was unique in StoreLocations. Ideally, you should have a States table as well, then you don't need to get the distinct states from the StoreLocations table.
Example with a States table: db<>fiddle
Just in case you want the dynamic pivot. Personally, I don't mind PIVOT. It is just another screwdriver in the toolbox.
The UNION ALL portion can be removed if you don't mind NULL values
Example dbFiddle
Declare #SQL varchar(max) = '
Select *
From (
Select A.Store_ID
,A.State_Abv
,B.Store_Name
,Value = ''X''
From StoreLocations A
Join Stores B on A.Store_ID=B.Store_ID
Union All
Select B.Store_ID
,A.State_Abv
,B.Store_Name
,Value = ''''
From (Select Distinct State_Abv from StoreLocations) A
Cross Join Stores B
) A
Pivot (max(Value) For [State_Abv] in (' + Stuff((Select Distinct ',' + QuoteName(State_Abv) From StoreLocations Order By 1 For XML Path('')),1,1,'') + ') ) p
Order By Store_ID
'
Exec(#SQL)
Returns
Option with NULL Values
Declare #SQL varchar(max) = '
Select *
From (
Select A.Store_ID
,A.State_Abv
,B.Store_Name
,Value = ''X''
From StoreLocations A
Join Stores B on A.Store_ID=B.Store_ID
) A
Pivot (max(Value) For [State_Abv] in (' + Stuff((Select Distinct ',' + QuoteName(State_Abv) From StoreLocations Order By 1 For XML Path('')),1,1,'') + ') ) p
Order By Store_ID
'
Returns

SQL Pivot trouble

I have data which looks like this:
+--------+-------------------------------+-------------+---------+-------------+----------------+--------------+-------------+--------------+--------------+-----------------+
| Type | Description | Issuer Code | Nominal | book_value | profit_or_loss | market_value | exposure | average_cost | market_price | unrealised_gain |
+--------+-------------------------------+-------------+---------+-------------+----------------+--------------+-------------+--------------+--------------+-----------------+
| Issuer | BHP Billiton Plc | BIL | 1880 | 56073577.75 | NULL | 55588623.09 | 55588623.09 | 265.486067 | 263.19 | -484954.66 |
| Issuer | Investec Limited | INL | 5300 | 14000040642 | NULL | 28468872315 | 28468872315 | 57.536692 | 117 | 14468831673 |
| Issuer | Topi 40 Futures 15 March 2010 | ALSIH1 | 4 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
+--------+-------------------------------+-------------+---------+-------------+----------------+--------------+-------------+--------------+--------------+-----------------+
I'm trying to get it to look like this:
Type = Issuer
Description = BHP Billiton Plc
Issuer Code = BIL
Nominal = 1880
book_value = 56073577.75
profit_or_loss = NULL
market_value = 55588623.09
exposure = 55588623.09
average_cost = 265.486067000000
market_price = 263.190000000000
unrealised_gain = -484954.66
Type = Issuer
Description = Investec Limited
Issuer Code = INL
Nominal = 5300
book_value = 14000040641.84
profit_or_loss = NULL
market_value = 28468872315.00
exposure = 28468872315.00
average_cost = 57.536692000000
market_price = 117.000000000000
unrealised_gain = 14468831673.16
I tried using PIVOT, but i have absolutely no idea how to achieve this. Any links or tutorials would be great.
Here is my attempt at the SQL (Not that it helps because i didnt know what I was doing. hehe)
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SELECT tb.* INTO #TmpFDH FROM
(
SELECT
instrument_id
,date_value
,book_value
,profit_or_loss
,market_value
,exposure
,average_cost
,market_price
,unrealised_gain
,ROW_NUMBER() OVER ( PARTITION BY fdh.instrument_id order by d.date_value DESC) as rn
FROM dw.Fact_Daily_Holding fdh
JOIN dw.dim_date d
ON fdh.holding_date_id = d.date_id
WHERE convert(date,date_value) = convert(date,GETDATE()-1)
) tb
WHERE tb.rn = 1
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.instrument_id)
FROM #TmpFDH c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Type, ' + #cols + ' from
(
SELECT
i.instrument_id
,rp.related_party_type AS [Type]--TYPE?
,rp.related_party_name AS [Description]--DESCRIPTION?
,rp.related_party_code AS [Issuer Code]--ISSUER CODE?
,ISNULL(fo.traded_nominal,0) AS [Nominal]
,fdh.book_value
,fdh.profit_or_loss
,fdh.market_value
,fdh.exposure
,fdh.average_cost
,fdh.market_price
,fdh.unrealised_gain
FROM dw.Dim_Instrument i
JOIN dw.Dim_Related_Party rp
ON i.instrument_code = rp.related_party_code
LEFT JOIN dw.Fact_Order fo
ON i.instrument_id = fo.instrument_id
LEFT JOIN #TmpFDH fdh
ON i.instrument_id = fdh.instrument_id
) x
pivot
(
max(book_value)
for instrument_id in (' + #cols + ')
) p '
execute(#query)
drop table #TmpFDH
I agree with the comment that there may be a better solution in xml so that also may be an option
My condolences that many of your columns are reserved words.
What you may be looking for is an UNPIVOT like below (given the column names in your example):
SELECT *
FROM mytable
UNPIVOT (
value
FOR label IN ([Type], [Description], [Issuer Code], [Nominal], [book_value],
[profit_or_loss], [market_value], [exposure], [average_cost], [market_price], [unrealised_gain])
) AS unpivot

is there a way to query future SSRS subscription schedules?

In my office, many of us use SSRS to schedule recurring reports. I want to view the schedule of upcoming report runs, for the next few days or a week, so that we can see whether 20 reports are all going to try to run at the same time. How can I accomplish that? I've created t-sql reports that show subscription information, but they only show "last run" dates and times. That's not helpful for predicting tomorrow's bottlenecks. The solution should include data-driven subscriptions too.
SSRS stores all of its data in the ReportServer database so you'll need an account with read access to this database. This is all relevant for SSRS running in native mode. I'm also not sure if shared schedules or data-driven subscriptions will be handled by this code, but I'm pretty sure they will be. I just haven't tested them.
PLEASE NOTE: Microsoft does not recommend or support directly querying the ReportServer database. They could change the structure in the next version or update of SSRS and you likely won't get any warning. The Microsoft recommendation is to always use the SSRS web service when you need to interrogate information about reporting services.
These are the tables that are relevant for pulling out the subscription information:
dbo.Catalog - Information about the deployed reports
dbo.ReportSchedule - Information relating reports to schedules and schedules
dbo.Subscriptions - Information about the subscriptions
dbo.Schedule - Information about the schedules
The SQL below pulls out schedule interval information for all reports. It doesn't calculate the next run dates but by figuring out the interval that the schedule is supposed to run on you can write another query to generate the actual dates.
This SQL was originally written for a report that just displays a string describing the interval so the final output is probably not what you're after. It should give you a good starting point though since it does figure out all of the interval details.
--these CTEs are used to match the bitmask fields in the schedule to determine which days & months the schedule is triggered on
WITH wkdays AS (
SELECT 'Sunday' AS label, 1 AS daybit
UNION ALL
SELECT 'Monday', 2
UNION ALL
SELECT 'Tuesday', 4
UNION ALL
SELECT 'Wednesday', 8
UNION ALL
SELECT 'Thursday', 16
UNION ALL
SELECT 'Friday', 32
UNION ALL
SELECT 'Saturday', 64
),
monthdays AS (
SELECT CAST(number AS VARCHAR(2)) AS label,
POWER(CAST(2 AS BIGINT),number-1) AS daybit
FROM master.dbo.spt_values
WHERE type='P' AND number BETWEEN 1 AND 31
),
months AS (
SELECT DATENAME(MM,DATEADD(MM,number-1,0)) AS label,
POWER(CAST(2 AS BIGINT),number-1) AS mnthbit
FROM master.dbo.spt_values
WHERE type='P' AND number BETWEEN 1 AND 12
)
SELECT cat.path,
cat.name,
cat.creationdate,
cat.modifieddate,
subs.Description,
subs.LastStatus,
subs.LastRunTime,
subs.InactiveFlags,
CASE RecurrenceType
WHEN 1 THEN 'Once'
WHEN 2 THEN 'Hourly'
WHEN 3 THEN 'Daily' --by interval
WHEN 4 THEN
CASE
WHEN WeeksInterval>1 THEN 'Weekly'
ELSE 'Daily' --by day of week
END
WHEN 5 THEN 'Monthly' --by calendar day
WHEN 6 THEN 'Monthly' --by day of week
END AS sched_type,
sched.StartDate,
sched.MinutesInterval,
sched.RecurrenceType,
sched.DaysInterval,
sched.WeeksInterval,
sched.MonthlyWeek,
wkdays.label AS wkday,wkdays.daybit AS wkdaybit,
monthdays.label AS mnthday,monthdays.daybit AS mnthdaybit,
months.label AS mnth, months.mnthbit
INTO #t
FROM dbo.Catalog AS cat
LEFT JOIN dbo.ReportSchedule AS repsched ON repsched.ReportID=cat.ItemID
LEFT JOIN dbo.Subscriptions AS subs ON subs.SubscriptionID=repsched.SubscriptionID
LEFT JOIN dbo.Schedule AS sched ON sched.ScheduleID=repsched.ScheduleID
LEFT JOIN wkdays ON wkdays.daybit & sched.DaysOfWeek > 0
LEFT JOIN monthdays ON monthdays.daybit & sched.DaysOfMonth > 0
LEFT JOIN months ON months.mnthbit & sched.[Month] > 0
WHERE cat.ParentID IS NOT NULL --all reports have a ParentID
/* THE PREVIOUS QUERY LEAVES MULTIPLE ROWS FOR SUBSCRIPTIONS THAT HAVE MULTIPLE BITMASK MATCHES *
* THIS QUERY WILL CONCAT ALL OF THOSE FIELDS TOGETHER AND ACCUMULATE THEM IN A TABLE FOR USE LATER. */
CREATE TABLE #c (type VARCHAR(16) COLLATE Latin1_General_CI_AS_KS_WS, name VARCHAR(255) COLLATE Latin1_General_CI_AS_KS_WS, path VARCHAR(255) COLLATE Latin1_General_CI_AS_KS_WS, concatStr VARCHAR(2000) COLLATE Latin1_General_CI_AS_KS_WS);
WITH d AS (
SELECT DISTINCT path,
name,
mnthday AS lbl,
mnthdaybit AS bm
FROM #t
)
INSERT INTO #c (type,path,name,concatStr)
SELECT 'monthday' AS type,
t1.path,t1.name,
STUFF((
SELECT ', ' + CAST(lbl AS VARCHAR(MAX))
FROM d AS t2
WHERE t2.path=t1.path AND t2.name=t1.name
ORDER BY bm
FOR XML PATH(''),TYPE
).value('.','VARCHAR(MAX)'),1,2,'') AS concatStr
FROM d AS t1
GROUP BY t1.path,t1.name;
WITH d AS (
SELECT DISTINCT path,
name,
wkday AS lbl,
wkdaybit AS bm
FROM #t
)
INSERT INTO #c (type,path,name,concatStr)
SELECT 'weekday' AS type,
t1.path,t1.name,
STUFF((
SELECT ', ' + CAST(lbl AS VARCHAR(MAX))
FROM d AS t2
WHERE t2.path=t1.path AND t2.name=t1.name
ORDER BY bm
FOR XML PATH(''),TYPE
).value('.','VARCHAR(MAX)'),1,2,'') AS concatStr
FROM d AS t1
GROUP BY t1.path,t1.name;
WITH d AS (
SELECT DISTINCT path,
name,
mnth AS lbl,
mnthbit AS bm
FROM #t
)
INSERT INTO #c (type,path,name,concatStr)
SELECT 'month' AS type,
t1.path,t1.name,
STUFF((
SELECT ', ' + CAST(lbl AS VARCHAR(MAX))
FROM d AS t2
WHERE t2.path=t1.path AND t2.name=t1.name
ORDER BY bm
FOR XML PATH(''),TYPE
).value('.','VARCHAR(MAX)'),1,2,'') AS concatStr
FROM d AS t1
GROUP BY t1.path,t1.name;
/* PUT EVERYTHING TOGETHER FOR THE REPORT */
SELECT a.path,a.name,a.sched_type,
a.creationdate,a.modifieddate,
a.description AS sched_desc,
a.laststatus AS sched_laststatus,
a.lastruntime AS sched_lastrun,
a.inactiveflags AS sched_inactive,
CASE RecurrenceType
WHEN 1 THEN 'Run once on '
ELSE 'Starting on '
END + CAST(StartDate AS VARCHAR(32)) + ' ' +
CASE RecurrenceType
WHEN 1 THEN ''
WHEN 2 THEN 'repeat every ' + CAST(MinutesInterval AS VARCHAR(255)) + ' minutes.'
WHEN 3 THEN 'repeat every ' + CAST(DaysInterval AS VARCHAR(255)) + ' days.'
WHEN 4 THEN
CASE
WHEN WeeksInterval>1 THEN 'repeat every ' + CAST(WeeksInterval AS VARCHAR(255)) + ' on ' + COALESCE(wkdays.concatStr,'')
ELSE 'repeat every ' + COALESCE(wkdays.concatStr,'')
END
WHEN 5 THEN 'repeat every ' + COALESCE(mnths.concatStr,'') + ' on calendar day(s) ' + COALESCE(mnthdays.concatStr,'')
WHEN 6 THEN 'run on the ' + CASE MonthlyWeek WHEN 1 THEN '1st' WHEN 2 THEN '2nd' WHEN 3 THEN '3rd' WHEN 4 THEN '4th' WHEN 5 THEN 'Last' END + ' week of ' + COALESCE(mnths.concatStr,'') + ' on ' + COALESCE(wkdays.concatStr,'')
END AS sched_pattern
FROM (
SELECT DISTINCT path,name,creationdate,modifieddate,description,laststatus,lastruntime,inactiveflags,sched_type,recurrencetype,startdate,minutesinterval,daysinterval,weeksinterval,monthlyweek
FROM #t
) AS a
LEFT JOIN #c AS mnthdays ON mnthdays.path=a.path AND mnthdays.name=a.name AND mnthdays.type='monthday'
LEFT JOIN #c AS wkdays ON wkdays.path=a.path AND wkdays.name=a.name AND wkdays.type='weekday'
LEFT JOIN #c AS mnths ON mnths.path=a.path AND mnths.name=a.name AND mnths.type='month'
DROP TABLE #t,#c;
Below Query can help you fetch schedule for your reports for the next day, this is built on standard metadata tables from report server database.
dbo.Catalog - Information about the deployed reports
dbo.ReportSchedule - Information relating reports to schedules and
schedules
dbo.Subscriptions - Information about the subscriptions
dbo.Schedule - Information about the schedules
Query:
Change getDate() function to have particular day schedule.
SELECT CAT.Name
,CAT.[Path] AS ReportPath
--,SUB.LastRunTime
,SCH.NextRunTime
,CONVERT(VARCHAR(10), CONVERT(datetime, SCH.NextRunTime, 1), 101) As RunDate
,right(convert(varchar(32),SCH.NextRunTime,100),8) As RunTime
,SUB.[Description]
,SUB.EventType
,SUB.LastStatus
,SUB.ModifiedDate
,SCH.Name AS ScheduleName
FROM reportserver.dbo.Subscriptions AS SUB
INNER JOIN reportserver.dbo.Users AS USR
ON SUB.OwnerID = USR.UserID
INNER JOIN reportserver.dbo.[Catalog] AS CAT
ON SUB.Report_OID = CAT.ItemID
INNER JOIN reportserver.dbo.ReportSchedule AS RS
ON SUB.Report_OID = RS.ReportID
AND SUB.SubscriptionID = RS.SubscriptionID
INNER JOIN reportserver.dbo.Schedule AS SCH
ON RS.ScheduleID = SCH.ScheduleID
Where CONVERT(VARCHAR(10), CONVERT(datetime, SCH.NextRunTime, 1), 101) = CONVERT(VARCHAR(10), CONVERT(datetime, getDate()+1, 1), 101)
ORDER BY USR.UserName
,CAT.[Path];
This procedure will give list of all values related to Report subscription.
here you will find startdate. and on the basis of that you can complete your task.
Create PROCEDURE [dbo].[GetSubscriptionData]
AS
BEGIN
SET NOCOUNT ON;
WITH
[Sub_Parameters] AS
(
SELECT [SubscriptionID], [Parameters] = CONVERT(XML,a.[Parameters])
FROM [Subscriptions] a
),
[MySubscriptions] AS
(
SELECT DISTINCT [SubscriptionID], [ParameterName] = QUOTENAME(p.value('(Name)[1]', 'nvarchar(max)')), [ParameterValue] = p.value('(Value)[1]', 'nvarchar(max)')
FROM [Sub_Parameters] a
CROSS APPLY [Parameters].nodes('/ParameterValues/ParameterValue') t(p)
),
[SubscriptionsAnalysis] AS
(
SELECT a.[SubscriptionID], a.[ParameterName], [ParameterValue] =
(
SELECT STUFF((SELECT [ParameterValue] + ', ' as [text()]
FROM [MySubscriptions]
WHERE [SubscriptionID] = a.[SubscriptionID] AND [ParameterName] = a.[ParameterName]
FOR XML PATH('') ),1, 0, '') +''
)
FROM [MySubscriptions] a
GROUP BY a.[SubscriptionID],a.[ParameterName]
)
SELECT
DISTINCT (a.[SubscriptionID]),
c.[UserName] AS Owner,
b.Name as ReportName,
Convert(XML,a.[ExtensionSettings]).value('(//ParameterValue/Value[../Name="RENDER_FORMAT"])[1]','nvarchar(50)') as ReportExtension,
b.Path,
a.[Locale],
a.[InactiveFlags],
d.[UserName] AS Modified_by,
a.[ModifiedDate],
a.[Description],
a.[LastStatus],
a.[EventType],
a.[LastRunTime],
a.[DeliveryExtension],
a.[Version],
sch.StartDate,
--e.[ParameterName],
--LEFT(e.[ParameterValue],LEN(e.[ParameterValue])-1) as [ParameterValue],
SUBSTRING(b.PATH,2,LEN(b.PATH)-(CHARINDEX('/',REVERSE(b.PATH))+1)) AS ProjectName
FROM
[Subscriptions] a
INNER JOIN [Catalog] AS b ON a.[Report_OID] = b.[ItemID]
Inner Join ReportSchedule as RS on rs.SubscriptionID = a.SubscriptionID
INNER JOIN Schedule AS Sch ON Sch.ScheduleID = rs.ScheduleID
LEFT OUTER JOIN [Users] AS c ON a.[OwnerID] = c.[UserID]
LEFT OUTER JOIN [Users] AS d ON a.MODIFIEDBYID = d.Userid
LEFT OUTER JOIN [SubscriptionsAnalysis] AS e ON a.SubscriptionID = e.SubscriptionID;
END
I reviewed a bunch of different solutions to this problem. And I finally found one that work best.
My solutions starts with the query in answer from Mike D. did not like his query at first because because it looked complicated and returned too much data to review-- But I chose to amend his query because it provides info beyond just subscriptions (Cache schedules/ Snapshots).
I modified his query as follows:
Exclude results of server content that do not use any scheduling
Improved the formatting to taste
Added useful fields that give more information about how the Schedule is being used.
ScheduleType:
Usage: Subscription/Snapshot/Cache
SubscriptionType: NULL if is not a subscription schedule
ScheduleName:
Resolved collation conflict error message: Cannot resolve the collation conflict between temp table and sys.objects --
My Solution (Tested: SSRS2008 and SSRS2016)
I might update this later once I've used other features such as "data-driven" subscription instead of "timed"
Or I might update this if I make improvements
Sample Data
NOTE: One thing I do not understand is why there are 2 TimedSubscriptions (row 7-8) because I looked in the portal and I see only there (row 8 with the shared schedule). Anyone know why?
+-----------------------------------+------------+-----------------------+-------------------+-------------------+--------------------------------------------------------------------------+---------------------+------------------+------------------+-----------------------------------------------------------------------+--------------+--------------------------------------+--------------------------------------+------------------+-------------------+------------------+------------+---------+--------------------------------------+---------------------------------------------------------------------+------------------+----------------+---------------------------------------------------------+----------------------------------------------------------------------+
| name | sched_type | ScheduleType | Usage | SubscriptionType | Elements_List | DeliveryExtension | UserOwnerSubs | UserCreatedSched | EmailRecipients | RenderFormat | ScheduleName | SubscriptionID | creationdate | modifieddate | modifieddate2 | StartDate | EndDate | sched_desc | sched_laststatus | sched_lastrun | sched_inactive | path | sched_pattern |
+-----------------------------------+------------+-----------------------+-------------------+-------------------+--------------------------------------------------------------------------+---------------------+------------------+------------------+-----------------------------------------------------------------------+--------------+--------------------------------------+--------------------------------------+------------------+-------------------+------------------+------------+---------+--------------------------------------+---------------------------------------------------------------------+------------------+----------------+---------------------------------------------------------+----------------------------------------------------------------------+
| PO Samples for Testing | Daily | TimedSubscription | TimedSubscription | TimedSubscription | TO CC BCC ReplyTo IncludeReport RenderFormat Subject Comment IncludeLink | Report Server Email | GEORGES\bl0040ep | GEORGES\bl0040ep | (x24) TO: brenda.metcalf#DOMAIN; | MHTML | bb53dfb1-6819-4a99-94bd-28ec3dcf3ecb | AF285C92-31E5-4BC4-9D88-284E0A3ED17B | 2/8/19 10:38 AM | 2/8/19 10:38 AM | 2/12/19 10:44 AM | 2/8/2019 | NULL | SUN Caryville PO Samples for Testing | Mail sent to brenda.metcalf#georgesinc.com; | 2/10/19 6:00 PM | 0 | /fsqa/PO Samples for Testing | Starting on Feb 8 2019 6:00PM repeat every Sunday Ending on Never |
| | | | | | Priority | | | | Shannon.Driggers#DOMAIN; Joseph.Davenport#DOMAIN; Lisa.Fude#DOMAIN; | | | | | | | | | | Shannon.Driggers#georgesinc.com; Joseph.Davenport#georgesinc.com; | | | | |
| | | | | | | | | | Amanda.Bourff#DOMAIN; Pam.Overton#DOMAIN; Brent.Lester#DOMAIN; | | | | | | | | | | Lisa.Fude#georgesinc.com; Amanda.Bourff#georgesinc.com; | | | | |
| | | | | | | | | | Jerry.McKnight#DOMAIN; Jacob.Phillips#DOMAIN; Ricky.Cole#DOMAIN; | | | | | | | | | | Pam.Overton#georgesinc.com | | | | |
| | | | | | | | | | Jeremy.Morris#DOMAIN; Bryan.Claiborne#DOMAIN; Harold.Webb#DOMAIN; | | | | | | | | | | | | | | |
| | | | | | | | | | Georgia.Roberts#DOMAIN; Chris.Malone#DOMAIN; Louis.Bargy#DOMAIN; | | | | | | | | | | | | | | |
| | | | | | | | | | Josh.Bills#DOMAIN; Larry.Reid#DOMAIN; Chris.Thompson#DOMAIN; | | | | | | | | | | | | | | |
| | | | | | | | | | Trenton.Marshall#DOMAIN; Willie.Baker#DOMAIN; Jack.Badon#DOMAIN; | | | | | | | | | | | | | | |
| | | | | | | | | | Susan.Delaney#DOMAIN CC: Suzanne.Beauchamp#DOMAIN | | | | | | | | | | | | | | |
+-----------------------------------+------------+-----------------------+-------------------+-------------------+--------------------------------------------------------------------------+---------------------+------------------+------------------+-----------------------------------------------------------------------+--------------+--------------------------------------+--------------------------------------+------------------+-------------------+------------------+------------+---------+--------------------------------------+---------------------------------------------------------------------+------------------+----------------+---------------------------------------------------------+----------------------------------------------------------------------+
| Sigma SO Loaded with Inventory | Daily | ReportHistorySchedule | ...ReportSnapshot | NULL | NULL | NULL | NULL | GEORGES\bl0040ep | NULL | NULL | 98a284df-3d03-445e-88d9-a44ed2d5c33a | NULL | 7/2/18 2:38 PM | 7/2/18 2:38 PM | NULL | 7/2/2018 | NULL | NULL | NULL | NULL | NULL | /Inventory/Sigma SO Loaded with Inventory (Cassville) | Starting on Jul 2 2018 6:20AM repeat every 1 days. Ending on Never |
| (Cassville) | | | | | | | | | | | | | | | | | | | | | | | |
+-----------------------------------+------------+-----------------------+-------------------+-------------------+--------------------------------------------------------------------------+---------------------+------------------+------------------+-----------------------------------------------------------------------+--------------+--------------------------------------+--------------------------------------+------------------+-------------------+------------------+------------+---------+--------------------------------------+---------------------------------------------------------------------+------------------+----------------+---------------------------------------------------------+----------------------------------------------------------------------+
| Customer Aging Report By Customer | Hourly | SharedSchedule | RefreshCache | RefreshCache | NULL | NULL | GEORGES\bl0040ep | GEORGES\bl0040ep | NULL | NULL | Hourly: Even Hours After 6AM | CF87DDDE-0F7F-416E-B403-E161AD0B14C1 | 10/25/18 1:55 PM | 12/13/18 12:46 PM | 11/29/18 3:55 PM | 11/30/2018 | NULL | Hourly: Even Hours After 6AM (625) | Cache refresh succeeded. | 2/12/19 10:00 AM | 0 | /Accounts Receivables/Customer Aging Report By Customer | Starting on Nov 30 2018 6:00AM |
| | | | | | | | | | | | | | | | | | | | | | | | repeat every 120 minutes. Ending on Never |
+-----------------------------------+------------+-----------------------+-------------------+-------------------+--------------------------------------------------------------------------+---------------------+------------------+------------------+-----------------------------------------------------------------------+--------------+--------------------------------------+--------------------------------------+------------------+-------------------+------------------+------------+---------+--------------------------------------+---------------------------------------------------------------------+------------------+----------------+---------------------------------------------------------+----------------------------------------------------------------------+
The Query (UPDATED: 2/12/2019)
This query is essentially the same but I have added more data element for analyzing the subscriptions. One issue resolved is [EmailRecipients] cutting and truncating the full list of recipients: value(N'(/ParameterValues/ParameterValue[Name="CC"]/Value)[1]', 'varchar(250)') changed to value(N'(/ParameterValues/ParameterValue[Name="CC"]/Value)[1]', 'varchar(max)').
subs.DeliveryExtension
subs.ExtensionSettings
CAST(CAST(subs.ExtensionSettings AS XML).query('data(ParameterValues/ParameterValue/Name)') as nvarchar(500))
AS Elements_List
'TO: '
+ CAST(subs.ExtensionSettings AS xml).value(N'(/ParameterValues/ParameterValue[Name="TO"]/Value)[1]', 'varchar(250)')
+ ' CC: '
+ ISNULL(CAST(subs.ExtensionSettings AS xml).value(N'(/ParameterValues/ParameterValue[Name="CC"]/Value)[1]', 'varchar(250)'), ' ')
as EmailRecipients
CAST(subs.ExtensionSettings AS xml).value(N'(/ParameterValues/ParameterValue[Name="RenderFormat"]/Value)[1]', 'varchar(250)')
as RenderFormat
subs.SubscriptionID
UserCreatedSched.UserName as [UserCreatedSched]
SQL:
----------------------------------------------------------------------------------------------------------------------------------------------------------
-- Get all schedule usage information: Subscription/ Snapshot/ Caching
-- queryGetScheduleDetails
-- https://stackoverflow.com/questions/25943877/is-there-a-way-to-query-future-ssrs-subscription-schedules/25944797#25944797
-- these CTEs are used to match the bitmask fields in the schedule to determine which days & months the schedule is triggered on
----------------------------------------------------------------------------------------------------------------------------------------------------------
IF #QueryCalled = 'queryGetScheduleDetails'
BEGIN
WITH wkdays AS (
SELECT
'Sunday' AS label, 1 AS daybit
UNION ALL
SELECT 'Monday', 2
UNION ALL
SELECT 'Tuesday', 4
UNION ALL
SELECT 'Wednesday', 8
UNION ALL
SELECT 'Thursday', 16
UNION ALL
SELECT 'Friday', 32
UNION ALL
SELECT 'Saturday', 64
)
,monthdays AS (
SELECT
CAST(number AS VARCHAR(2)) AS label
,POWER(CAST(2 AS BIGINT),number-1) AS daybit
FROM master.dbo.spt_values
WHERE type='P' AND number BETWEEN 1 AND 31
)
,months AS (
SELECT
DATENAME(MM,DATEADD(MM,number-1,0)) AS label
,POWER(CAST(2 AS BIGINT),number-1) AS mnthbit
FROM master.dbo.spt_values
WHERE type='P' AND number BETWEEN 1 AND 12
)
SELECT
cat.path
, cat.name
, cat.creationdate
, cat.modifieddate
, subs.ModifiedDate as ModifiedDate2
, subs.Description
, UserOwnerSubs.UserName as [UserOwnerSubs]
, subs.LastStatus
, subs.LastRunTime
, subs.InactiveFlags
, subs.EventType as [SubscriptionType]
, subs.DeliveryExtension
, subs.ExtensionSettings
, CAST(CAST(subs.ExtensionSettings AS XML).query('data(ParameterValues/ParameterValue/Name)') as nvarchar(max)) AS Elements_List
-- <RECIPIENTS function>
,
'TO: '
+ CAST(subs.ExtensionSettings AS xml).value(N'(/ParameterValues/ParameterValue[Name="TO"]/Value)[1]', 'varchar(max)')
+ ' CC: '
+ ISNULL(CAST(subs.ExtensionSettings AS xml).value(N'(/ParameterValues/ParameterValue[Name="CC"]/Value)[1]', 'varchar(max)'), ' ')
as EmailRecipients
-- </RECIPIENTS function>
, CAST(subs.ExtensionSettings AS xml).value(N'(/ParameterValues/ParameterValue[Name="RenderFormat"]/Value)[1]', 'varchar(max)')
as RenderFormat
, subs.SubscriptionID
, sched.Name as [ScheduleName]
, UserCreatedSched.UserName as [UserCreatedSched]
, sched.EventType as [ScheduleType]
--
, CASE RecurrenceType
WHEN 1 THEN 'Once'
WHEN 2 THEN 'Hourly'
WHEN 3 THEN 'Daily' --by interval
WHEN 4 THEN
CASE
WHEN WeeksInterval>1 THEN 'Weekly'
ELSE 'Daily' --by day of week
END
WHEN 5 THEN 'Monthly' --by calendar day
WHEN 6 THEN 'Monthly' --by day of week
END AS [sched_type]
, sched.StartDate
, sched.EndDate
, sched.MinutesInterval
, sched.RecurrenceType
, sched.DaysInterval
, sched.WeeksInterval
, sched.MonthlyWeek
, wkdays.label AS [wkday]
, wkdays.daybit AS [wkdaybit]
, monthdays.label AS [mnthday]
, monthdays.daybit AS [mnthdaybit]
, months.label AS [mnth]
, months.mnthbit
INTO #t
FROM
dbo.Catalog AS cat
LEFT JOIN dbo.ReportSchedule AS repsched ON repsched.ReportID=cat.ItemID
LEFT JOIN dbo.Subscriptions AS subs ON subs.SubscriptionID=repsched.SubscriptionID
LEFT JOIN dbo.Schedule AS sched ON sched.ScheduleID=repsched.ScheduleID
LEFT JOIN wkdays ON wkdays.daybit & sched.DaysOfWeek > 0
LEFT JOIN monthdays ON monthdays.daybit & sched.DaysOfMonth > 0
LEFT JOIN months ON months.mnthbit & sched.[Month] > 0
LEFT JOIN dbo.Users UserOwnerSubs ON subs.OwnerId = UserOwnerSubs.UserID
LEFT JOIN dbo.Users UserCreatedSched ON sched.CreatedByID = UserCreatedSched.UserID
WHERE cat.ParentID IS NOT NULL --all reports have a ParentID
/* THE PREVIOUS QUERY LEAVES MULTIPLE ROWS FOR SUBSCRIPTIONS THAT HAVE MULTIPLE BITMASK MATCHES *
* THIS QUERY WILL CONCAT ALL OF THOSE FIELDS TOGETHER AND ACCUMULATE THEM IN A TABLE FOR USE LATER. */
CREATE TABLE #c (type VARCHAR(16) COLLATE Latin1_General_CI_AS_KS_WS, name VARCHAR(255) COLLATE Latin1_General_CI_AS_KS_WS, path VARCHAR(255) COLLATE Latin1_General_CI_AS_KS_WS, concatStr VARCHAR(2000) COLLATE Latin1_General_CI_AS_KS_WS);
WITH d AS (
SELECT DISTINCT
path
, name
, mnthday AS lbl
, mnthdaybit AS bm
FROM #t
)
INSERT INTO #c (type,path,name,concatStr)
SELECT
'monthday' AS type
, t1.path,t1.name
, STUFF((
SELECT ', ' + CAST(lbl AS VARCHAR(MAX))
FROM d AS t2
WHERE t2.path=t1.path AND t2.name=t1.name
ORDER BY bm
FOR XML PATH(''),TYPE
).value('.','VARCHAR(MAX)'),1,2,'')
AS concatStr
FROM d AS t1
GROUP BY t1.path,t1.name;
WITH d AS (
SELECT DISTINCT path,
name,
wkday AS lbl,
wkdaybit AS bm
FROM #t
)
INSERT INTO #c (type,path,name,concatStr)
SELECT
'weekday' AS type
, t1.path,t1.name
, STUFF(
(
SELECT ', ' + CAST(lbl AS VARCHAR(MAX))
FROM d AS t2
WHERE t2.path=t1.path AND t2.name=t1.name
ORDER BY bm
FOR XML PATH(''),TYPE
).value('.','VARCHAR(MAX)'),1,2,'')
AS concatStr
FROM d AS t1
GROUP BY t1.path,t1.name;
WITH d AS (
SELECT DISTINCT
path
, name
, mnth AS lbl
, mnthbit AS bm
FROM #t
)
INSERT INTO #c (type,path,name,concatStr)
SELECT
'month' AS type
, t1.path,t1.name
, STUFF(
(
SELECT ', ' + CAST(lbl AS VARCHAR(MAX))
FROM d AS t2
WHERE t2.path=t1.path AND t2.name=t1.name
ORDER BY bm
FOR XML PATH(''),TYPE
).value('.','VARCHAR(MAX)'),1,2,'')
AS concatStr
FROM d AS t1
GROUP BY t1.path,t1.name;
/* PUT EVERYTHING TOGETHER FOR THE REPORT */
SELECT
a.name
, a.sched_type
, ScheduleType
, CASE
WHEN a.description IS NOT NULL THEN SubscriptionType
WHEN a.ScheduleType='ReportHistorySchedule' THEN '...ReportSnapshot'
ELSE '...ReportCache'
END AS [Usage]
, SubscriptionType
, a.Elements_List
, a.DeliveryExtension
, a.UserOwnerSubs
, a.UserCreatedSched
, a.EmailRecipients
, a.RenderFormat
-- , ExtensionSettings
, ScheduleName
, SubscriptionID
, a.creationdate
, a.modifieddate
, a.modifieddate2
, CAST(a.StartDate as date) as StartDate
, CAST(a.EndDate as date) as EndDate
, a.description AS sched_desc
, a.laststatus AS sched_laststatus
, a.lastruntime AS sched_lastrun
, a.inactiveflags AS sched_inactive
, a.path
, CASE RecurrenceType
WHEN 1 THEN 'Run once on '
ELSE 'Starting on '
END
+ CAST(StartDate AS VARCHAR(32)) + ' ' +
CASE RecurrenceType
WHEN 1 THEN ''
WHEN 2 THEN 'repeat every ' + CAST(MinutesInterval AS VARCHAR(255)) + ' minutes.'
WHEN 3 THEN 'repeat every ' + CAST(DaysInterval AS VARCHAR(255)) + ' days.'
WHEN 4 THEN
CASE
WHEN WeeksInterval>1 THEN 'repeat every ' + CAST(WeeksInterval AS VARCHAR(255)) + ' on ' + COALESCE(wkdays.concatStr,'')
ELSE 'repeat every ' + COALESCE(wkdays.concatStr,'')
END
WHEN 5 THEN 'repeat every ' + COALESCE(mnths.concatStr,'') + ' on calendar day(s) ' + COALESCE(mnthdays.concatStr,'')
WHEN 6 THEN 'run on the ' +
CASE
MonthlyWeek WHEN 1 THEN '1st' WHEN 2 THEN '2nd' WHEN 3 THEN '3rd' WHEN 4 THEN '4th' WHEN 5 THEN 'Last'
END
+ ' week of ' + COALESCE(mnths.concatStr,'') + ' on ' + COALESCE(wkdays.concatStr,'')
END
+ ' Ending on ' + ISNULL(CAST(EndDate AS VARCHAR(32)), 'Never')
AS sched_pattern
FROM
(
SELECT DISTINCT path,name,creationdate,modifieddate,modifieddate2,SubscriptionType,RenderFormat, /*ExtensionSettings,*/ ScheduleName, UserOwnerSubs,ScheduleType,SubscriptionID,description, UserCreatedSched,laststatus,lastruntime,StartDate,EndDate,inactiveflags,sched_type,recurrencetype,minutesinterval,daysinterval,weeksinterval,monthlyweek
,cast(Elements_List as nvarchar(500)) as Elements_List, DeliveryExtension
, '(x'
+ CAST((LEN(EmailRecipients) - LEN(REPLACE(EmailRecipients,'#',''))) / LEN('#') as nvarchar(10))
+ ') '
+ REPLACE(EmailRecipients,'#GEORGESINC.COM','#DOMAIN')
as EmailRecipients
FROM #t
) AS a
LEFT JOIN #c AS mnthdays ON mnthdays.path COLLATE DATABASE_DEFAULT =a.path COLLATE DATABASE_DEFAULT
AND mnthdays.name COLLATE DATABASE_DEFAULT =a.name COLLATE DATABASE_DEFAULT
AND mnthdays.type COLLATE DATABASE_DEFAULT ='monthday' COLLATE DATABASE_DEFAULT
LEFT JOIN #c AS wkdays ON wkdays.path COLLATE DATABASE_DEFAULT =a.path COLLATE DATABASE_DEFAULT
AND wkdays.name COLLATE DATABASE_DEFAULT=a.name COLLATE DATABASE_DEFAULT
AND wkdays.type COLLATE DATABASE_DEFAULT ='weekday' COLLATE DATABASE_DEFAULT
LEFT JOIN #c AS mnths ON mnths.path COLLATE DATABASE_DEFAULT =a.path COLLATE DATABASE_DEFAULT
AND mnths.name COLLATE DATABASE_DEFAULT =a.name COLLATE DATABASE_DEFAULT
AND mnths.type COLLATE DATABASE_DEFAULT ='month' COLLATE DATABASE_DEFAULT
WHERE
a.sched_type IS NOT NULL
AND (#ReportName = 'All Reports' OR a.Name like #ReportName)
DROP TABLE #t,#c;

SQL SUM in PIVOT that uses MAX

I am trying to get the SUM of 2 or more TIME fields within my PIVOT table, however because the SUM does not work with characters (converted so I can show EstimatedTime / ActualTime), I'm having difficulty.
The code below -
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' + ID + ',' + QUOTENAME(Name)
FROM JobPhases
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT #query = 'SELECT * FROM
(
SELECT j.JobID, c.Registration as ''Reg.'', p.Name,
CAST(MAX(j.EstimatedTime) as VARCHAR(MAX)) + ''/'' +
CAST(MAX(j.ActualTime) as VARCHAR(MAX)) as [x]
FROM JobDetails AS j
INNER JOIN JobPhases p ON p.ID = j.PhaseId
INNER JOIN Jobs job on job.ID = j.JobID
INNER JOIN Cars c on job.CarID = c.ID
WHERE (job.Status = 1 or job.Status = 0)
GROUP BY c.Registration, p.Name, j.JobID
) JobDetails
PIVOT
( MAX(x)
FOR Name IN (' + #cols + ')
) pvt'
execute(#query);
Generates -
JobID | Reg. | P13$ | Repair and Reshape | P15$ | Refit Stripped Parts
1065 | BJ11 2VT | NULL | 01:00:00.0000000/01:54:10.5387526 | NULL | NULL
Tables -
**JobDetails**
ID - PK Auto increment
JobID - Int (Joined to Jobs table)
PhaseID - String (joined to JobPhases table)
EstimatedTime - time(7)
ActualTime time(7)
**JobPhases****
ID - PK String
Name - VarChar(150)
The problem in this example is there are 2 JobDetails for JobID 1065 -
ID | JobID | PhaseID | EstimatedTime | ActualTime
25 | 1065 | P13$ | 01:00:00.0000000 | 01:54:10.5387526
26 | 1065 | P13$ | 00:30:00.0000000 | 00:00:00.0000000
So, the correct result should be (Note the 1:30 in the Repair & Reshape) -
JobID | Reg. | P13$ | Repair and Reshape | P15$ | Refit Stripped Parts
1065 | BJ11 2VT | NULL | 01:30:00.0000000/01:54:10.5387526 | NULL | NULL
Any ideas how I can get the total EstimatedTime for all rows for each phase id?
Thanks!
Summing TIME columns isn't straight forward, what you need is to rewrite your line;
CAST(MAX(j.EstimatedTime) as VARCHAR(MAX)) + ''/'' +
to something like (the untested)
CAST(CAST(DATEADD(ms, SUM(DATEDIFF(ms, '0:00:00', j.EstimatedTime)),
'00:00:00') AS TIME) AS VARCHAR(MAX)) + ''/'' +