SSRS Predicament with expressions - reporting-services

I have an SSRS dataset that looks like this:
The dataset rows are generated independent of each other using UNION ALL.
I need to display these rows in my report as is, but I need to add an additional row that will calculate Total Won / Total Lost, so the result should look like this:
This is just sample as I have more columns (1 per month) and the whole thing is broken down by product, so if I have 10 different products, I will have 10 different tablix tables.
Basically I need to somehow create an expression that will only calculate values in 2 rows of the tablix out of 3 (based on the value of the Status column) and take into consideration that some values can be zeroes.
Here's the query (I simplified it a bit for better understanding):
select * from
(
select 'Created' as 'State', fo.groupidname, fo.businessidname ' Business', fo.opportunityid
from FilteredOpportunity fo
where fo.regionidname = 'Americas Region'
and fo.createdon >= dateadd(year, -1, getdate())
and fo.regionalfeeincome >= 250000
) created
pivot
(
count(created.opportunityid)
for created.groupidname in ([Boston], [Chicago], [Colombia], [Group D.C.], [Houston], [Los Angeles], [New York], [San Francisco], [Seattle], [Toronto])
) pivCreated
union all
select * from
(
select 'Won' as 'State', fo.groupidname, fo.businessidname ' Business', fo.opportunityid
from FilteredOpportunity fo
where regionidname = 'Americas Region'
and fo.actualclosedate >= dateadd(year, -1, getdate())
and regionalfeeincome >= 250000
and fo.jna is not null
) won
pivot
(
count(won.opportunityid)
for won.groupidname in ([Boston], [Chicago], [Colombia], [Group D.C.], [Houston], [Los Angeles], [New York], [San Francisco], [Seattle], [Toronto])
) pivWon
union all
select * from
(
select 'Lost' as 'State', fo.groupidname, fo.businessidname ' Business', fo.opportunityid
from FilteredOpportunity fo
where fo.regionidname = 'Americas Region'
and fo.actualclosedate >= dateadd(year, -1, getdate())
and fo.regionalfeeincome >= 250000
and fo.sys_phasename <> 'Pre-Bid'
) lost
pivot
(
count(lost.opportunityid)
for lost.groupidname in ([Boston], [Chicago], [Colombia], [Group D.C.], [Houston], [Los Angeles], [New York], [San Francisco], [Seattle], [Toronto])
) pivLost
TIA
-TS.

I can't fully test this as I don't have time to build sample data but it should work...
If you use this as your report's dataset query then you should be able to add a simple matrix with a row group by State and a column group by City
/*
You can optimise this a bit but I've kept it fairly procedural so it's easier to follow
*/
-- First do your 3 basic queries but this time we don't pivot and we dump the results into temp tables
-- I've also removed columns that don't appear to be used based on your sample output and remaned a column to City to make it easier to read
select 'Total Created' as 'State', fo.groupidname as City, COUNT(*) AS Cnt
INTO #Created
from FilteredOpportunity fo
where fo.regionidname = 'Americas Region'
and fo.createdon >= dateadd(year, -1, getdate())
and fo.regionalfeeincome >= 250000
select 'Total Won' as 'State', fo.groupidname as City, COUNT(*) AS Cnt
INTO #Won
from FilteredOpportunity fo
where fo.regionidname = 'Americas Region'
and fo.createdon >= dateadd(year, -1, getdate())
and fo.regionalfeeincome >= 250000
and fo.jna is not null
select 'Total Lost' as 'State', fo.groupidname as City, COUNT(*) AS Cnt
INTO #Lost
from FilteredOpportunity fo
where fo.regionidname = 'Americas Region'
and fo.createdon >= dateadd(year, -1, getdate())
and fo.regionalfeeincome >= 250000
and fo.sys_phasename <> 'Pre-Bid'
-- Now we calculate your Ratio
SELECT
'Win Ratio' as 'State'
, coalesce(w.City, l.City) as City -- use coalesce in case 1 side of join is null
, CASE WHEN ISNULL(l.cnt,0) = 0 THEN 0 ELSE w.Cnt/l.Cnt END as Cnt -- if lost is null or 0 return 0 else calc ratio
into #Ratio
FROM #Won w
full join #Lost l on w.City = l.City
-- finaly, get the results and add a sort to help the report row sorting.
SELECT 1 as Sort, * FROM #Created
UNION SELECT 2, * FROM #Won
UNION SELECT 3, * FROM #Lost
UNION SELECT 4, * FROM #Ratio

Related

SSRS expression to calculate total based on daily counts that have conditions

In a totals row (location is row group, date is the column group), I'm not sure how to calculate a total based on the below expression that I've been using to calculate "overcapacity" daily totals. I'm trying to total up the daily overcap counts.
The below expression works fine when grouped under the "date" column grouping. So each day in the range picked by the user displays with an "overcapacity" count (if the visitscounts > 7, then the result is visitscounts - 7, otherwise it is 0).
But I'm not sure how to total up the resultant overcapacity counts (I can total up visitcounts fine). The issue is that it takes the FULL daily count and THEN applies the -7, instead of just summing all the previously calculated daily counts (if the daily account exceeds 7, then it subtracts 7 from the full daily count, to come up with an "overcapacity" count).
=IIF(SUM(IIF(Fields!Location.Value = "LOC3" OR Fields!Location.Value = "LOC4",Fields!VisitsCount.Value,0)) > 7,
SUM(SUM(IIF(Fields!Location.Value = "LOC3" OR Fields!Location.Value = "LOC4",Fields!VisitsCount.Value,0))-7),
0)
ADDITIONAL INFORMATION
Dataset Query:
SELECT
L.Location
, D.[date]
, COUNT(DISTINCT CAST(V.VisitID AS VARCHAR(10))+V.Location+V.[Room-Bed]) AS VisitsCount
FROM dbo.DateTable(#StartDate, #EndDate) AS D
CROSS JOIN (
SELECT DISTINCT Location FROM dbo.vHIMOverFlowBedReport2)
AS L LEFT JOIN dbo.vHIMOverFlowBedReport2 AS V ON D.[date] BETWEEN
V.EffectiveDate AND ISNULL(V.ServiceEndDate, #EndDate) AND V.Location = L.Location
WHERE V.EffectiveDate IS NULL OR
(V.EffectiveDate <= #EndDate OR
V.ServiceEndDate >= #StartDate OR
V.ServiceEndDate IS NULL)
GROUP BY
L.Location
, D.[date]
ORDER BY L.Location, D.[date]
OverCap New Column Testing
Dataset Query with Added OverCap Column:
SELECT
x.Location
, x.[date]
, x.VisitsCount
, OverCap = IIF(VisitsCount-7 <0 ,0, VisitsCount-7)
FROM (
SELECT
L.Location
, D.[date]
, COUNT(DISTINCT CAST(V.VisitID AS VARCHAR(10))+V.Location+V.[Room-Bed]) AS VisitsCount
FROM dbo.DateTable(#StartDate, #EndDate) AS D
CROSS JOIN (
SELECT DISTINCT Location FROM dbo.vHIMOverFlowBedReport2)
AS L LEFT JOIN dbo.vHIMOverFlowBedReport2 AS V ON D.[date] BETWEEN
V.EffectiveDate AND ISNULL(V.ServiceEndDate, #EndDate) AND V.Location = L.Location
WHERE V.EffectiveDate IS NULL OR
(V.EffectiveDate <= #EndDate OR
V.ServiceEndDate >= #StartDate OR
V.ServiceEndDate IS NULL)
GROUP BY
L.Location
, D.[date]
) x
ORDER BY x.Location, x.[date]
Full Report Layout with OverCap added
Grouped by Location (row) and [date] (column), with a totals row outside row group for combined location.
report layout
Current Resultset with OverCap Column
CurrentResultSet
NOTES:
Result for LOC3-4 is 129 (see CurrentResultSet) if I use:
OverCap = IIF(VisitsCount-7 <0 ,0, VisitsCount-7)
Result for LOC3-4 is 34 if I use:
OverCap = IIF(Location = 'LOC3' OR Location = 'LOC4', VisitsCount,0)
Result for LOC3-4 is 24 if I use:
OverCap = IIF((Location = 'LOC3' OR Location = 'LOC4') AND VisitsCount > 7, VisitsCount,0)
Expressions Used Successfully for GROUPED locations:
DailyVisitorCount (used for both DailyVisitorCount and TotalVisitorCount).
=Sum(Fields!VisitsCount.Value)
DailyOverCapacityCount (used for both DailyOverCapacityCount and TotalOverCapacityCount):
=SWITCH(
Fields!Location.Value = "LOC1" AND Fields!VisitsCount.Value > 24, SUM(Fields!VisitsCount.Value - 24),
Fields!Location.Value = "LOC2" AND Fields!VisitsCount.Value > 16, SUM(Fields!VisitsCount.Value - 16),
Fields!Location.Value = "LOC3" AND Fields!VisitsCount.Value > 7, SUM(Fields!VisitsCount.Value - 7),
Fields!Location.Value = "LOC4" AND Fields!VisitsCount.Value > 7, SUM(Fields!VisitsCount.Value - 7),
Fields!Location.Value = "LOC5" AND Fields!VisitsCount.Value > 11, SUM(Fields!VisitsCount.Value - 11),
True, 0)
Averages were calculated by using the above expressions but adding to the end:
/CountDistinct(Fields!date.Value)
Expressions Used for combined location (outside grouped location row)
DailyVisitorCount (used successfully for both DailyVisitorCount and TotalVisitorCount).
=IIF(Fields!Location.Value = "LOC3" OR Fields!Location.Value = "LOC4", Sum(Fields!VisitsCount.Value), 0)
TotalOverCapCount (used successfully with DAILY TotalOverCapCount, but not the Total TotalOverCapCount
=IIF(SUM(IIF(Fields!Location.Value = "LOC3" OR Fields!Location.Value = "LOC4",Fields!VisitsCount.Value,0)) > 7,
SUM(SUM(IIF(Fields!Location.Value = "LOC3" OR Fields!Location.Value = "LOC4",Fields!VisitsCount.Value,0))-7),
0)
Expressions still needed:
Total TotalOverCapCount (adds up daily totals for the duration)
Average TotalOverCapCount (average of daily totals for the duration)
As the expression you are trying to sum requires two scoped expression parts, it's actually difficult to then sum these.
What you need to do is
=SUM(
SUM(Fields!.MyField.Value, "ColumnGroup")
, "RowGroup")
This is probably not possible in your scenario. I abandoned the approach quickly and just updated the dataset query to return the data I needed instead
So the dataset query looked like this (using you sample data)
DECLARE #t TABLE([Location] varchar(10), [Date] Date, [VisitsCount] int)
INSERT INTO #t VALUES
('LOC1', '2022-10-31', 18), ('LOC1', '2022-11-01', 19),
('LOC1', '2022-11-02', 19), ('LOC2', '2022-10-31', 34),
('LOC2', '2022-11-01', 30), ('LOC2', '2022-11-02', 35),
('LOC3', '2022-10-31', 8), ('LOC3', '2022-11-01', 8),
('LOC3', '2022-11-02', 8), ('LOC4', '2022-10-31', 5),
('LOC4', '2022-11-01', 5), ('LOC4', '2022-11-02', 7),
('LOC5', '2022-10-31', 11), ('LOC5', '2022-11-01', 11),
('LOC5', '2022-11-02', 11)
SELECT
[Location], [Date], VisitsCount
, OverCap = IIF(VisitsCount-7 <0 ,0, VisitsCount-7)
FROM #t
As you can see, I added an OverCap column. Now all we need to do is sum that in the report.
The report design looks like this..
and the final report looks like this...
Obviously you might need to adapt this to suit whatever grouping you have going but I think it's probably a much simpler approach.
Edit after update by OP
You can wrap your original query in a SELECT and then move the order clause of of the sub query. That should give you the same results.
SELECT
[Location], [Date], VisitsCount
, OverCap = IIF(VisitsCount-7 <0 ,0, VisitsCount-7)
FROM (
SELECT
L.Location
, D.[date]
, COUNT(DISTINCT CAST(V.VisitID AS VARCHAR(10))+V.Location+V.[Room-Bed]) AS VisitsCount
FROM dbo.DateTable(#StartDate, #EndDate) AS D
CROSS JOIN (
SELECT DISTINCT Location FROM dbo.vHIMOverFlowBedReport2)
AS L LEFT JOIN dbo.vHIMOverFlowBedReport2 AS V ON D.[date] BETWEEN
V.EffectiveDate AND ISNULL(V.ServiceEndDate, #EndDate) AND V.Location = L.Location
WHERE V.EffectiveDate IS NULL OR
(V.EffectiveDate <= #EndDate OR
V.ServiceEndDate >= #StartDate OR
V.ServiceEndDate IS NULL)
GROUP BY
L.Location
, D.[date]
) x
ORDER BY [Location], [date]
If you want to just get LOC3+4 at the end of the table
Then you can do this in SQL. All I've done here is taken the existing query, dumped the results to a temp table , then returned the results plus an extra row that only contains LOC3 and LOC4 data.
Note: I added a GroupOrder column so you can sort on this in the report to make sure the combined row appears at the end.
SELECT
[Location], [Date], VisitsCount
, OverCap = IIF(VisitsCount-7 <0 ,0, VisitsCount-7)
INTO #t
FROM (
SELECT
L.Location
, D.[date]
, COUNT(DISTINCT CAST(V.VisitID AS VARCHAR(10))+V.Location+V.[Room-Bed]) AS VisitsCount
FROM dbo.DateTable(#StartDate, #EndDate) AS D
CROSS JOIN (
SELECT DISTINCT Location FROM dbo.vHIMOverFlowBedReport2)
AS L LEFT JOIN dbo.vHIMOverFlowBedReport2 AS V ON D.[date] BETWEEN
V.EffectiveDate AND ISNULL(V.ServiceEndDate, #EndDate) AND V.Location = L.Location
WHERE V.EffectiveDate IS NULL OR
(V.EffectiveDate <= #EndDate OR
V.ServiceEndDate >= #StartDate OR
V.ServiceEndDate IS NULL)
GROUP BY
L.Location
, D.[date]
) x
SELECT
GroupOrder = 1
, [Location], [Date], VisitsCount, OverCap
FROM #t
UNION ALL
SELECT
GroupOrder = 2
, [Location] = 'LOC3+4', MIN([Date]), SUM(VisitsCount), SUM(OverCap)
FROM #t
WHERE [Location] IN ('LOC3', 'LOC4')
GROUP BY YEAR([Date]), MONTH([Date])

Convert mysql query to sqlite

I am new to sqlite3.I am currently using mysql. But I will be migrating it to sqlite3.
I am calculating month end balance
SELECT c.country,
Date_format(Last_day(Str_to_date(dt.date, '%m/%d/%Y')), '%Y/%m/%d')
AS Month_End_Balance,
Sum(dt.amount) AS in_Euro
FROM deposit_transactions AS dt
LEFT JOIN customers AS c
ON c.customer_id = dt.customer_id
GROUP BY c.country,
Month_End_Balance
order by Month_End_Balance desc
Need help in converting it to sqlite
Question
Need help in Last_Day function alternative in sqlite
Refer below query for SQLITE -
Please make adjustment as per needed date format.
with new_dep_trx as (
select deposit_id,customer_id,
transaction_type,amount,currency,
case when (length(dt.date)=8 or length(dt.date)=9) and instr(substr(dt.date,1,2),'/')>0
then
date(substr(dt.date,length(dt.date)-3,4)||'-0'||substr(dt.date,1,1)||'-0'||substr(dt.date,3,1))
when length(dt.date)=9 and instr(substr(dt.date,1,2),'/')=0
then
date(substr(dt.date,length(dt.date)-3,4)||'-'||substr(dt.date,1,2)||'-0'||substr(dt.date,4,1))
else
date(substr(dt.date,length(dt.date)-3,4)||'-'||substr(dt.date,1,2)||'-'||substr(dt.date,4,2)) end date_col
from deposit_transactions dt
)
select
c.country,
strftime('%Y-%m',dt.date_col) as month,
strftime('%m/%d/%Y',date(dt.date_col,'start of month','+1 month','-1 day')) as last_day_of_month,
strftime('%Y/%m/%d',date(dt.date_col,'start of month','+1 month','-1 day')) as last_day_of_month_your_format,
SUM(
dt.amount *
(CASE WHEN dt.currency = 'GBP' THEN .85 ELSE 1 END) *
(CASE WHEN dt.transaction_type = 'pay_in' THEN 1 ELSE -1 END)
) amount_eur
FROM new_dep_trx dt
LEFT JOIN customers c ON c.customer_id = dt.customer_id
GROUP BY c.country, last_day_of_month_your_format;
Modified DB fiddle.
First, you must update the column date of the table deposit_transactions so that it has the format YYYY-mm-dd the only text date format that you can use with SQLite's datetime functions:
UPDATE deposit_transactions
SET date = SUBSTR(date, -4) || '-' ||
printf('%02d', date + 0) || '-' ||
printf('%02d', SUBSTR(date, INSTR(date, '/') + 1, 2) + 0);
Now, you can use the function date() to get the last day of each month with:
date(date, 'start of month', '+1 month', '-1 day')
So, your query should be:
SELECT c.country,
date(dt.date, 'start of month', '+1 month', '-1 day') AS Month_End_Balance,
SUM(dt.amount *
CASE WHEN dt.currency = 'GBP' THEN .85 ELSE 1 END *
CASE WHEN dt.transaction_type = 'pay_in' THEN 1 ELSE -1 END
) AS amount_eur
FROM deposit_transactions AS dt LEFT JOIN customers AS c
ON c.customer_id = dt.customer_id
GROUP BY c.country, Month_End_Balance
ORDER BY Month_End_Balance DESC;
If you want to format the dates of the resultset to mm/dd/YYYY and sort properly by the date and not the formatted date which would sort incorrectly:
SELECT c.country,
strftime('%m/%d/%Y', date(dt.date, 'start of month', '+1 month', '-1 day')) AS Month_End_Balance,
SUM(dt.amount *
CASE WHEN dt.currency = 'GBP' THEN .85 ELSE 1 END *
CASE WHEN dt.transaction_type = 'pay_in' THEN 1 ELSE -1 END
) AS amount_eur
FROM deposit_transactions AS dt LEFT JOIN customers AS c
ON c.customer_id = dt.customer_id
GROUP BY c.country, date(dt.date, 'start of month', '+1 month', '-1 day')
ORDER BY date(dt.date, 'start of month', '+1 month', '-1 day') DESC;
See the demo.

Case When Exists In Subquery

I am trying to check whether an ID is present in a subquery. I have ran just the subquery and it produces a list of all the ID's which have a fee against it, so what I want to do is check whether the ID in the main query is present in the subquery. If it's present then return 1, else return 0.
This is an easy query but I have no idea where i'm going wrong, I tried using exists rather than in but this does not work either.
case when debtor._rowid in (
select distinct note.debtorid from note
left join debtor on note.debtorid = debtor._rowid
left join fee on fee.debtorid = debtor._rowid
where fee.type = "Enforcement" and note.type = "Stage")
then 1 else 0 end) as `Enforcement`
Below is the entire code, when I remove the above code from the main query below, it works perfectly, so there's something wrong in my case statement.
with cte_1
as
(
select
debtor._rowid as casref
,concat(date_format(date_sub(debtor._createddate, interval 3 month), '%y'), '/', date_format(date_add(debtor._createddate, interval 9 month), '%y')) as `F/Y`
,date_format(debtor._createddate, '%M %Y') as `Loaded Month`
,ifnull(concat(date_format(date_sub(debtor.offence_date, interval 3 month), '%y'), '/', date_format(date_add(debtor.offence_date, interval 9 month), '%y')),'-') as `LO F/Y`
,coalesce(date_format(debtor.offence_date,'%M %Y'),'-') as `Liability Order Month`
,scheme.name as `Scheme`
,branch.name as `Branch`
,count(debtor._rowid) as `Cases Received`
,count(debtor.linkid) as `LinkID`
,(case
when concat(date_format(date_sub(debtor._createddate, interval 3 month), '%y'), '/', date_format(date_add(debtor._createddate, interval 9 month), '%y'))
= ifnull(concat(date_format(date_sub(debtor.offence_date, interval 3 month), '%y'), '/', date_format(date_add(debtor.offence_date, interval 9 month), '%y')),'-')
then 1 else 0 end ) as `Same Year`
, case when debtor._rowid in (
select distinct note.debtorid from note
left join debtor on note.debtorid = debtor._rowid
left join fee on fee.debtorid = debtor._rowid
where fee.type = "Enforcement"
and note.type = "Stage")
then 1 else 0 end) as `Enforcement`
from debtor
left join clientscheme on debtor.clientschemeID = clientscheme._rowid
left join scheme on clientscheme.schemeID = scheme._rowid
left join branch on clientscheme.branchID = branch._rowid
left join fee on debtor._rowid = fee.debtorid
left join note on debtor._rowid = note.debtorid
where clientscheme.branchID in (1,10,24)
and debtor._createddate >= '2017-04-01'
group by debtor._rowid
)
,
cte_2
as
(
select
`F/Y`
,`Loaded Month`
,`LO F/Y`
,`Liability Order Month`
,`Scheme`
,`Branch`
,sum(`Cases Received`) as `Case Count`
,sum(`LinkID`) as `Linked Accounts`
,sum(`Same Year`) as `In Year LO`
,sum(Enforcement) as `Enforcement Applied`
from cte_1
group by
`Loaded Month`
,`Liability Order Month`
,`Scheme`
, `Branch`
)
select
`F/Y`
,`Loaded Month`
,`LO F/Y`
,`Liability Order Month`
,`Scheme`
,`Branch`
,`Case Count`
,`Linked Accounts`
,round((`Linked Accounts`/`Case Count`),2) * 100 as `% of Linked Accounts`
,round((`In Year LO`/`Case Count`),2) * 100 as `In Year LO's`
,`Enforcement Applied`
from cte_2
It appears that you want to logically check if, for a given record in the result set, a _noteid value from the debtor table matches to a debtors from the note table. You could rephrase your query as follows:
SELECT
(d._rowid = n.debtorid) AS `Enforcement Allocated`
FROM note n
LEFT JOIN debtor d
ON n.debtorid = d._rowid
LEFT JOIN fee f
ON f.debtorid = d._rowid
WHERE
f.type = 'Enforcement' AND n.type = 'Stage';
Note that since the output of your CASE expression is just 1 or 0, you may take advantage of that MySQL allows boolean expressions as values.

SQL Query Issue - Picking the minimum time when there is a maximum number

SQL God...I need some help!
I have a data table that has a route_complete_percentage column and a created_at column.
I need two pieces of data:
the time stamp (within created_at column) when the route_complete_percentage is at its minimum but not zero
the time stamp (within created_at column) when the route_complete_percentage is at its maximum, it might be 100% or not, but when its at its highest.
Here is the kicker, there might be multiple time stamps for the highest route completion column. For example,
Example Table
I have multiple values when the route_completion_percentage is at its maximum, but I need the minimum time stamp value.
Here is the query so far...but the two time stamps are the same.
SELECT
A.fc,
A.plan_id,
A.route_id,
mintime.first_scan AS First_Batch_Scan,
min(route_complete_percentage),
maxtime.last_scan AS Last_Batch_Scan,
max(route_complete_percentage)
FROM
(SELECT
fc,
plan_id,
route_id,
route_complete_percentage,
CONCAT(plan_id, '-', route_id) AS JOINKEY
FROM
houdini_ops.BATCHINATOR_SCAN_LOGS_V2
WHERE
fc <> ''
AND order_id <> 'Can\'t find order'
AND source = 'scan'
AND created_at > DATE_ADD(CURDATE(), INTERVAL - 3 DAY)) A
LEFT JOIN
(SELECT
l.fc,
l.route_id,
l.plan_id,
CONCAT(l.plan_id, '-', l.route_id) AS JOINKEY,
CASE
WHEN MIN(route_complete_percentage) THEN CONVERT_TZ(l.created_at, 'UTC', s.time_zone)
END AS first_scan
FROM
houdini_ops.BATCHINATOR_SCAN_LOGS_V2 l
JOIN houdini_ops.O_SERVICE_AREA_ATTRIBUTES s ON l.fc = s.default_station_code
WHERE
l.fc <> ''
AND l.order_id <> 'Can\'t find order'
AND l.source = 'scan'
AND l.created_at > DATE_ADD(CURDATE(), INTERVAL - 3 DAY)
GROUP BY fc , plan_id , route_id) mintime ON A.JOINKEY = mintime.JOINKEY
LEFT JOIN
(SELECT
l.fc,
l.route_id,
l.plan_id,
CONCAT(l.plan_id, '-', l.route_id) AS JOINKEY,
CASE
WHEN MAX(route_complete_percentage) THEN CONVERT_TZ(l.created_at, 'UTC', s.time_zone)
END AS last_scan
FROM
houdini_ops.BATCHINATOR_SCAN_LOGS_V2 l
JOIN houdini_ops.O_SERVICE_AREA_ATTRIBUTES s ON l.fc = s.default_station_code
WHERE
l.fc <> ''
AND l.order_id <> 'Can\'t find order'
AND l.source = 'scan'
AND l.created_at > DATE_ADD(CURDATE(), INTERVAL - 3 DAY)
GROUP BY fc , plan_id , route_id) maxtime ON mintime.JOINKEY = maxtime.JOINKEY
GROUP BY fc , plan_id , route_id
I don't want to meddle with the rest of your query. Here is something that will do what it sounds like you need. There's sample data included. -- I interpreted your blank values as nulls from your sample data.
Basically, what you are looking for is the Minimum created_at value, inside each of the route_complete_percentage groups. So I treated route_complete_percentage as a group identifier. But you only care about two of the groups, so I identify those groups first in the cte, and use them to filter the aggregate query.
if object_id('tempdb.dbo.#Data') is not null drop table #Data
go
create table #Data (
route_complete_percentage int,
created_at datetime
)
insert into #Data (route_complete_percentage, created_at)
values
(0, '20170531 19:58'),
(1, null),
(2, null),
(3, null),
(4, null),
(5, null),
(6, null),
(7, null),
(80, null),
(90, null),
(100, '20170531 20:10'),
(100, '20170531 20:12'),
(100, '20170531 20:15')
;with cteMinMax(min_route_complete_percentage, max_route_complete_percentage) as (
select
min(route_complete_percentage),
max(route_complete_percentage)
from #Data D
-- This ensures the condition that you don't get the timestamp for 0
where D.route_complete_percentage > 0
)
select
route_complete_percentage,
min_created_at = min(created_at)
from #Data D
join cteMinMax MM on D.route_complete_percentage in (MM.min_route_complete_percentage, MM.max_route_complete_percentage)
group by route_complete_percentage

How to query last 2 business days only

I'm running a query that pulls the correct information I'm looking for, but I need it to pull the last 2 business days rather than the last 2 days. This comes into play when it's Monday and my results show information for Monday and Sunday rather than Monday and Friday. How can I change my query to pull in business days only?
USE [LetterGeneration]
SELECT g.LetterGenerationPrintJobId
,CAST(t.[TemplateKey] AS VarChar) AS LetterCode
,convert(char(12),r.CreatedDate,101) AS CreatedDate
,s.LetterGenerationStatusId AS Status
,s.StatusKey AS StatusDesc
,count(g.LetterGenerationId) as LetterCount
,c.BankingDateYorN
FROM [LetterGenerationTemplateRequest] AS r
INNER JOIN [LetterGenerationTemplate] AS t
ON t.[LetterGenerationTemplateId] = r.LetterGenerationTemplateId
INNER JOIN LetterGeneration g
ON g.LetterGenerationTemplateRequestId = r.LetterGenerationTemplateRequestId
INNER JOIN LetterGenerationStatus s
ON g.LetterGenerationStatusId = s.LetterGenerationStatusId
INNER JOIN Enterprise..Calendar C
ON c.BeginDate = g.LetterDate
WHERE ((DATEDIFF(d, r.CreatedDate, GETDATE()) = 0) OR (DATEDIFF(d, r.CreatedDate, GETDATE()) = 1))
--BankingDateYorN = 1
--AND RelativeTimeValue_BusinessDates =-1
AND t.[TemplateKey] NOT LIKE '%PLTV1%'
AND s.LetterGenerationStatusId NOT LIKE '4'
AND s.LetterGenerationStatusId NOT LIKE '16'
AND s.LetterGenerationStatusId NOT LIKE '19'
AND s.LetterGenerationStatusId NOT LIKE '20'
AND s.LetterGenerationStatusId NOT LIKE '38'
GROUP BY r.[LetterGenerationTemplateRequestId]
,r.LetterGenerationTemplateId
,g.Lettergenerationprintjobid
,t.[TemplateKey]
,r.[Loan_no]
,r.CreatedDate
,r.[CreatedBy]
,s.LetterGenerationStatusId
,s.StatusKey
,c.BankingDateYorN
ORDER BY r.CreatedDate DESC
UPDATE: I've recently discovered how to join a calendar table to my current query. The calendar query has a column called BusinessDayYorN with 1's for a business day and 0's for weekends and holidays. I've also updated the old query to now include the join.
select *
from LetterGenerationTemplateRequest
where createddate >= (
getdate() -
case datename(dw,getdate())
when 'Tuesday' then 5
when 'Monday' then 4
else 3
end
)
--and datename(dw,createdDate) not in ('Saturday','Sunday',datename(dw,getdate()))
and datename(dw,createdDate) not in ('Saturday','Sunday')
;
Assuming that you always want to include the last two non-weekend days you can try this:
; with aux as (
select diff = case
when datename(weekday, getdate()) in ('Tuesday', 'Wednesday ', 'Thursday', 'Friday') then 1
else
case datename(weekday, getdate())
when 'Saturday' then 2
when 'Sunday' then 3
when 'Monday' then 4
end
end
)
SELECT --r.[LetterGenerationTemplateRequestId]
--,r.LetterGenerationTemplateId
g.LetterGenerationPrintJobId
,CAST(t.[TemplateKey] AS VarChar) AS LetterCode
,r.[Loan_no]
,convert(char(12),r.CreatedDate,101) AS CreatedDate
-- ,g.ModifiedDate
-- ,convert(varchar(18), g.ModifiedDate - r.CreatedDate, 108) AS TimeSpan
,s.LetterGenerationStatusId AS Status
,s.StatusKey AS StatusDesc
,count(g.LetterGenerationId) as LetterCount
FROM [LetterGenerationTemplateRequest] AS r
INNER JOIN [LetterGenerationTemplate] AS t
ON t.[LetterGenerationTemplateId] = r.LetterGenerationTemplateId
INNER JOIN LetterGeneration g
ON g.LetterGenerationTemplateRequestId = r.LetterGenerationTemplateRequestId
INNER JOIN LetterGenerationStatus s
ON g.LetterGenerationStatusId = s.LetterGenerationStatusId
WHERE
DATEDIFF(day, r.CreatedDate, GETDATE()) <= (select diff from aux)
AND t.[TemplateKey] NOT LIKE '%PLTV1%'
AND s.LetterGenerationStatusId NOT LIKE '4'
AND s.LetterGenerationStatusId NOT LIKE '16'
AND s.LetterGenerationStatusId NOT LIKE '19'
AND s.LetterGenerationStatusId NOT LIKE '20'
AND s.LetterGenerationStatusId NOT LIKE '38'
GROUP BY r.[LetterGenerationTemplateRequestId]
,r.LetterGenerationTemplateId
,g.Lettergenerationprintjobid
,t.[TemplateKey]
,r.[Loan_no]
,r.CreatedDate
-- ,g.ModifiedDate
,r.[CreatedBy]
,s.LetterGenerationStatusId
,s.StatusKey
ORDER BY r.CreatedDate DESC
The CTE aux returns a dataset with only one record and only one field, the value of which is the number of days you need to go back in your WHERE statement.