Find median between 2 dates - sql

Anyone know how I can change the Total Median near bottom to show an average of the median instead? For some reason, the Total Median is always 100. Not sure what I should do.
Thanks in advance for any ideas! Current results also below.
WITH CTE AS (
SELECT DISTINCT c.CaseID AS CaseID,
DATEDIFF(d, c.CaseAddDt, coip.DispoDt) AS DaysApart
, DATEPART(month,c.CaseAddDt) AS [Month]
, DATEPART(year,c.CaseAddDt) AS [Year]
, CAST(DATEPART(year,c.CaseAddDt) AS varchar) + '|' + CASE WHEN DATEPART(month,c.CaseAddDt) IN (10,11,12) THEN CAST(DATEPART(month,c.CaseAddDt) AS varchar) ELSE '0' + CAST(DATEPART(month,c.CaseAddDt) AS varchar) END AS Srt
FROM jw50_Case c
JOIN jw50_CaseInvPers def ON def.CaseID = c.CaseID
AND def.InvolveTypeMasterCode = 1
JOIN
jw50_CountInvPers coip ON coip.CaseID = c.CaseID
AND coip.CaseInvPersID = def.CaseInvPersID
AND coip.DispoCode IN ('CODE','CODE')
AND coip.CountNum > 0
OUTER APPLY (
SELECT TOP 1 caz.CaseAgencyID
FROM jw50_CaseAgency caz
WHERE caz.CaseID = c.CaseID
AND caz.AgencyCode = 'ABC'
AND caz.NumberTypeCode IN ('i#','in#')) caz
WHERE
EXISTS (SELECT 1 FROM jw50_CaseAttributes ca WHERE ca.CaseID = c.CaseID AND ca.CaseAttributeCode = 'oa7')
AND caz.CaseAgencyID IS NOT NULL
AND c.CaseStatusCode <> 'AAA'
AND c.CaseAddDt BETWEEN '01/01/2017' AND '08/01/2017'
AND c.CaseAddDt <= coip.DispoDt)
SELECT a.CaseID,
a.Month
, a.Year
, a.DaysApart
, a.Srt
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY a.DaysApart) OVER (PARTITION BY a.Month, a.Year) AS MonMedian
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY a.DaysApart) OVER (PARTITION BY 1) AS TotalMedian
FROM CTE a
Results:

Related

SQL Case When Slowing Down Query

What I'm looking to do is quantify the total value of purchases and the number of months in which a purchase was made within three different timeframes by account. I only want to look at accounts who made a purchase between 1-1-2020 and 4-1-2021.
I'm wondering if there is a more streamlined way to pull in the fields I'm creating using CASE WHEN below (maybe through a series of queries to create the calculations and the left joining?). This query is taking extremely long to pull back, so I'd like to enhance this code where I can. All of my code and desired output is listed below. Thank you!
Creating a temporary table to pull account numbers:
DROP TABLE IF EXISTS #accounts
SELECT DISTINCT s.account_no, c.code, c.code_desc
INTO #accounts
FROM sales AS s
LEFT JOIN customer AS c ON s.account_no = c.account_no
WHERE s.tran_date BETWEEN '2020-01-01' AND '2021-04-01'
GROUP BY s.account_no, c.code, c.code_desc;
Confirming row counts:
SELECT COUNT (*)
FROM #accounts
ORDER BY account_no;
Creating Sales and Sales period count columns for three timeframes:
SELECT
s.account_no, c.code, c.code_desc
SUM(CASE
WHEN s.tran_date BETWEEN '2020-01-01' AND '2021-04-01'
THEN VALUE_USD
END) AS Total_Spend_Pre,
SUM(CASE
WHEN s.tran_date BETWEEN '2021-04-01' AND '2022-03-31'
THEN VALUE_USD
END) Total_Spend_During,
SUM(CASE
WHEN s.tran_date > '2022-04-01'
THEN VALUE_USD
END) Total_Spend_Post,
COUNT(DISTINCT CASE WHEN s.tran_date BETWEEN '2020-01-01' AND '2021-04-01' THEN CONCAT(s.bk_month, s.bk_year) END) Pre_Periods,
COUNT(DISTINCT CASE WHEN s.tran_date BETWEEN '2021-04-01' AND '2022-03-31' THEN CONCAT(s.bk_month, s.bk_year) END) During_Periods,
COUNT(DISTINCT CASE WHEN s.tran_date > '2022-04-01' THEN CONCAT(s.bk_month, s.bk_year) END) Post_Periods
FROM
sales AS s
LEFT JOIN
customer AS c ON s.account_no = c.account_no
WHERE
c.account_no IN (SELECT DISTINCT account_no
FROM #accounts)
GROUP BY
s.account_no, c.code, c.code_desc;
Desired output:
account_no
code
code_desc
Total_Spend_Pre
Total_Spend_During
Total_Spend_Post
Pre_Periods
During_Periods
Post_Periods
25
1234
OTHER
1000
2005
500
2
14
5
11
5678
PC
500
100
2220
5
11
2
You may use your date ranges to join with dataset, and 'Tag' your result like below, this will result in 3 rows, for each group. If you need them in a single row, have PIVOTE over it
;With DateRanges AS (
SELECT CAST('2020-01-01' AS DATE) StartDate, CAST('2021-04-01' AS DATE) EndDate, 'Pre' Tag UNION
SELECT '2021-04-01', '2022-03-31', 'During' UNION
SELECT '2022-04-01', Null, 'Post'
)
SELECT s.account_no, c.code, c.code_desc, d.Tag,
SUM(VALUE_USD) AS Total_Spend,
COUNT(DISTINCT CONCAT(s.bk_month, s.bk_year)) RecordCount
FROM sales as s
LEFT JOIN customer as c
INNER JOIN DateRanges D ON s.tran_date BETWEEN D.StartDate AND ISNULL(D.EndDate,s.tran_date)
ON s.account_no = c.account_no
WHERE c.account_no IN (SELECT DISTINCT account_no FROM #accounts)
GROUP BY s.account_no, c.code, c.code_desc;
with [cte_accountActivityPeriods] as (
select [PeriodOrdinal] = 1, [PeriodName] = 'Total Spend Pre', [PeriodStart] = convert(date,'2020-01-01',23) , [PeriodFinish] = convert(date,'2021-03-31',23) union
select [PeriodOrdinal] = 2, [PeriodName] = 'Total Spend During', [PeriodStart] = convert(date,'2021-04-01',23) , [PeriodFinish] = convert(date,'2022-03-31',23) union
select [PeriodOrdinal] = 3, [PeriodName] = 'Total Spend Post', [PeriodStart] = convert(date,'2022-04-01',23) , [PeriodFinish] = convert(date,'9999-12-31',23)
)
, [cte_allsalesForActivityPeriod]
SELECT s.account_no, bk_month, bk_year, [PeriodOrdinal], s.tran_date, s.value_usd
FROM sales as s
cross join [cte_accountActivityPeriods]
on s.[tran_date] between [cte_ActivityPeriods].[PeriodStart] and [cte_ActivityPeriods].[PeriodFinish]
)
, [cte_uniqueAccounts] as ( /*Unique and qualifying Accounts*/
select distinct account_no from [cte_allsalesForActivityPeriod]
inner join #accounts accs on accs.[account_no] = [cte_allsalesForActivityPeriod].[account_no]
)
, [cte_AllSalesAggregatedByPeriod] as (
select account_no, [PeriodOrdinal], bk_month, bk_year, [PeriodTotalSpend] = sum([value_usd])
from [cte_allsalesForActivityPeriod]
group by s.account_no, [PeriodOrdinal], bk_month, bk_year
)
, [cte_PeriodAnalysis] as (
select account_no, [PeriodOrdinal], [ActivePeriods] = count(distinct concat(bk_month, bk_year))
from [cte_AllSalesAggregatedByPeriod]
group by s.account_no, [PeriodOrdinal]
)
, [cte_pivot_clumsily] as (
/* Aggregations already done - so simple pivot */
select [cte_uniqueAccounts].[account_no]
, [Total_Spend_Pre] = case when [SaleVal].[PeriodOrdinal] in (1) then [SaleVal].[PeriodTotalSpend] else 0 end
, [Total_Spend_During] = case when [SaleVal].[PeriodOrdinal] in (2) then [SaleVal].[PeriodTotalSpend] else 0 end
, [Total_Spend_Post] = case when [SaleVal].[PeriodOrdinal] in (3) then [SaleVal].[PeriodTotalSpend] else 0 end
, [Pre_Periods] = case when [SalePrd].[PeriodOrdinal] in (1) then [SalePrd].[ActivePeriods] else 0 end
, [During_Periods] = case when [SalePrd].[PeriodOrdinal] in (2) then [SalePrd].[ActivePeriods] else 0 end
, [Post_Periods] = case when [SalePrd].[PeriodOrdinal] in (3) then [SalePrd].[ActivePeriods] else 0 end
from [cte_uniqueAccounts]
left join [cte_AllSalesAggregatedByPeriod] [SaleVal] on [SaleVal].[account_no] = [cte_uniqueAccounts].[account_no]
left join [cte_PeriodAnalysis] [SalePrd] on [SalePrd].[account_no] = [cte_uniqueAccounts].[account_no]
)
select c.code, c.code_desc, [cte_pivot_clumsily].*
from [cte_pivot_clumsily]
LEFT JOIN customer as c
ON [cte_pivot_clumsily].account_no = c.account_no

The query I ran returns 2 of the same column which isn't allowed in tableau and I can't fix the query

I need to be able to get rid of one of the workdate and one of the sr_name columns but I can't figure out how to.
I'm getting the query returned like this:
Query
I'm also getting this error message when entered into tableau:
The column 'sr_name' was specified multiple times for 'Custom SQL Query'.
Below is the code I have. If I remove a sr_name from either subquery there will be an error in the join clause.
select *
from
(
select s.sr_name, cast(punchdatetime as date) as workdate,
((datediff(second, min(case when p.InOut = 1 then punchdatetime end),
max(case when p.InOut = 0 then punchdatetime end))/3600) - .5) as
hoursworked
from PunchClock p join ServiceReps s on p.ServRepID = s.ServRepID
where punchyear >= 2019
group by s.sr_name, cast(punchdatetime as date)
) v
join
(
select sr_name, t.*,
calls = (select count(*) from CRM_Correspondence cr where
cast(cr.DateCreated as date) = workdate and StatusType like '%call%' and
cr.ServRepID = t.servrepid),
reaches = (select count(*) from CRM_Correspondence cr where
cast(cr.DateCreated as date) = workdate and (StatusType = 'call reached'
or StatusType like '%SCHEDULE%') and cr.ServRepID = t.servrepid),
books = (select count(*) from os_appointments o where cast(o.DateCreated
as date) = workdate and isnull(o.confirmedby, o.booked_by) =
t.servrepid),
attends = (select count(*) from os_appointments o where
cast(o.DateCreated as date) = workdate and isnull(o.confirmedby,
o.booked_by) = t.servrepid and o.appointmentStatus = 'attended')
from
(
select cast(cor.datecreated as date) workdate, cor.ServRepID
from CRM_Correspondence cor
where cor.datecreated > '2019-01-01'
group by cast(cor.datecreated as date), cor.servrepid
) t
join ServiceReps sr on t.ServRepID = sr.ServRepID
) u on v.sr_name = u.sr_name and v.workdate = u.workdate
I need the same results just without the duplicate column so I can enter the query into tableau.
This is challenging because you have so many subqueries here. This could be refactored to use a single query which is what I would do. But using the existing query you could do something along these lines.
I had to format this very differently so I could isolate each piece.
select v.sr_name
, v.workdate
, v.hoursworked
, u.ServRepID
, u.calls
, u.reaches
, u.books
, u.attends
from
(
select s.sr_name
, cast(punchdatetime as date) as workdate
, ((datediff(second, min(case when p.InOut = 1 then punchdatetime end), max(case when p.InOut = 0 then punchdatetime end))/3600) - .5) as hoursworked
from PunchClock p
join ServiceReps s on p.ServRepID = s.ServRepID
where punchyear >= 2019
group by s.sr_name
, cast(punchdatetime as date)
) v
join
(
select sr_name
, t.*
, calls =
(
select count(*)
from CRM_Correspondence cr
where cast(cr.DateCreated as date) = workdate
and StatusType like '%call%'
and cr.ServRepID = t.servrepid
)
, reaches =
(
select count(*)
from CRM_Correspondence cr
where cast(cr.DateCreated as date) = workdate
and (StatusType = 'call reached' or StatusType like '%SCHEDULE%')
and cr.ServRepID = t.servrepid
)
, books =
(
select count(*)
from os_appointments o
where cast(o.DateCreated as date) = workdate and isnull(o.confirmedby, o.booked_by) = t.servrepid
)
, attends =
(
select count(*)
from os_appointments o
where cast(o.DateCreated as date) = workdate
and isnull(o.confirmedby, o.booked_by) = t.servrepid
and o.appointmentStatus = 'attended'
)
from
(
select cast(cor.datecreated as date) workdate
, cor.ServRepID
from CRM_Correspondence cor
where cor.datecreated > '2019-01-01'
group by cast(cor.datecreated as date)
, cor.servrepid
) t
join ServiceReps sr on t.ServRepID = sr.ServRepID
) u on v.sr_name = u.sr_name
and v.workdate = u.workdate

Can't use SQL lag sum

My query is like this
SELECT
[day], [time],AvaliableTimes,
CASE
WHEN AvaliableTimes > 0
THEN SUM(AvaliableTimes) OVER (ORDER BY [day], [time], AvaliableTimes)
ELSE 0
END AS SumValue
FROM
[AvailableTimes]
WHERE
[day] = 1 AND BranchAreaId = 1
ORDER BY
[day], [time], AvaliableTimes
I want to start sum from 0 if value is null or 0.
Results:
you can use a recursive CTE to do it. Perform the cumulative sum in the rcte and if AvailableTimes = 0, reset it
; with
cte as
(
select *, rn = row_number() over (order by time)
from yourtable
),
rcte as
(
select *, sumvalues = AvailableTimes
from cte
where rn = 1
union all
select c.*, sumvalues = case when c.AvailableTimes <> 0
then r.sumvalues + c.AvailableTimes
else c.AvailableTimes
end
from cte c
inner join rcte r on c.rn = r.rn + 1
)
select day, time, AvailableTimes, sumvalues
from rcte
order by time

Retrieve last record from current month and previous month

I need to get the last recorded value from the current month and the previous month. There are roughly 4,600 records per month.
The following is the code I have tried, however it returns '0' for the two months and not the value:
SELECT a.LogPoint as [Meter]
,max(CASE WHEN c.DateTimeStamp = dateadd(MM,-1,getdate()) THEN c.FloatVALUE ELSE 0 END) as [Total LAST Month]
,max(CASE WHEN c.DateTimeStamp = getdate() THEN c.FloatVALUE ELSE 0 END) as [Total This Month]
FROM
SWR.dbo.LoggedEntities a
,SWR.dbo.TrendLogRelation b
,SWR.dbo.LogTimeValues c
WHERE
a.GUID = b .GUID
AND a.Type LIKE 'trend.ETLog'
AND a.LogPoint = 'WsumOut_Trnd'
AND b.EntityID = c.ParentID
GROUP BY a.LogPoint
Any help would be greatly appreciated.
Cheers.
I assume the LogPoint is the primary key. correct? In that case check following:
SELECT mainA.LogPoint AS [Meter],
lastMonth.FloatValue AS [Total LAST Month],
thisMonth.FloatValue AS [Total This Month]
FROM SWR.dbo.LoggedEntities mainA
CROSS APPLY
(
SELECT TOP 1 c.FloatVALUE
FROM SWR.dbo.LoggedEntities a
JOIN SWR.dbo.TrendLogRelation b ON a.GUID = b.GUID
JOIN SWR.dbo.LogTimeValues c ON b.EntityID = c.ParentID
WHERE a.LogPoint = mainA.LogPoint
ORDER BY c.DateTimeStamp DESC
) thisMonth
CROSS APPLY
(
SELECT TOP 1 c.FloatVALUE
FROM SWR.dbo.LoggedEntities a
JOIN SWR.dbo.TrendLogRelation b ON a.GUID = b.GUID
JOIN SWR.dbo.LogTimeValues c ON b.EntityID = c.ParentID
WHERE a.LogPoint = mainA.LogPoint AND c.DateTimeStamp <= DATEADD(MM,-1,GETDATE())
ORDER BY c.DateTimeStamp DESC
) lastMonth
WHERE a.Type LIKE 'trend.ETLog'
AND a.LogPoint = 'WsumOut_Trnd';
Just realized that I missed the last month date check. added now. try that :)
getdate() includes both the time and the date, which is why you aren't getting any matches.
One option is to cast both values to dates and then do the comparison.
Two important points before I start:
Never use commas in the FROM clause. Always use explicit JOIN syntax.
Table aliases should be abbreviations for the table.
Then, you want to use row_number():
SELECT LogPoint as [Meter],
max(CASE WHEN seqnum = 1 AND
DATEDIFF(month, DateTimeStamp, getdate()) = 1
THEN cltv.FloatVALUE
END) as [Total LAST Month],
max(CASE WHEN seqnum = 1 AND
DATEDIFF(month, DateTimeStamp, getdate()) = 0
THEN ltv.FloatVALUE
END) as [Total This Month]
FROM (SELECT le.LogPoint, ltv.DateTimeStamp,
ROW_NUMBER() OVER (PARTITION BY YEAR(DateTimeStamp), MONTH(DateTimeStamp)
ORDER BY DateTimeStamp DESC
) as seqnum
FROM SWR.dbo.LoggedEntities le JOIN
SWR.dbo.TrendLogRelation tlr
ON le.GUID = tlr.GUID JOIN
SWR.dbo.LogTimeValues ltv
ON ltr.EntityID = ltv.ParentID
WHERE le.Type LIKE 'trend.ETLog' AND
le.LogPoint = 'WsumOut_Trnd' AND
DATEDIFF(month, ltv.DateTimeStamp, getdate()) IN (0, 1)
) x
WHERE seqnum = 1;

How can I change these into columns?

I've tried using CTE, but haven't been able to figure it out. I want to change the multiple rows into one row with multiple columns going accross. Any way to go about this...
Current Result
ern CostPool
111 NULL
111 5
Desired Result
ern CostPool1 CostPool2
111 NULL 5
SELECT first_name, last_name, ern, pc, title, TitleDesc, OfficeTitle, SUM(earned) earned, fypaydate, q
, [RMTS, Support, or Partial Quarter], SUM(CAST([Staff Employment Status] AS INT)) sumEmpStatus, SUM(CAST(countisMHy AS INT)) sumcountisMHy, SUM(CAST(sumisMHy AS INT)) sumisMHy1
, SUM(CAST(sumEligible AS INT)) sumEligible1
, CostPool
FROM (
SELECT
e.first_name, e.last_name
, fss.ern
, fss.pc
, fss4.title
, u.OfficeTitle
, t.TitleDesc
, SUM(fss.gross*fss.[percent]) earned
, fss.fypaydate, fss.q
, cpayfss3, cpaypdq
, CASE WHEN cpayfss3 = cpaypdq THEN '1' --full q
WHEN cpayfss3 < cpaypdq THEN '2' --part q
ELSE 'Check'
END [RMTS, Support, or Partial Quarter]
, CASE WHEN COUNT(DISTINCT rc.isMHy) = 2 THEN '9' --split
WHEN fss.pc = 'A' AND COUNT(DISTINCT rc.isMHy) = 1 AND SUM(CAST(rc.isMHy AS INT)) > 0 THEN '1' --full
WHEN fss.pc IN ('X', 'O', 'W', 'L', 'K') AND SUM(CAST(rc.isMHy AS INT)) > 0 THEN '2' --part
ELSE '0'
END [Staff Employment Status]
, COUNT(DISTINCT rc.isMHy) countisMHy
, SUM(CAST(rc.isMHy AS INT)) sumisMHy
, SUM(CAST(rc.Eligible AS INT)) sumEligible --count distinct too?
, rc.CostPool
FROM [FIN_DataMart].[dbo].[FSSpaydetl_NEW] fss
LEFT JOIN FIN_DataMart.[dbo].[FSSRC_NEW] rc
ON fss.newrc = rc.RC
AND fss.fypaydate = rc.FY
INNER JOIN
(
SELECT ern, fypaydate, q, COUNT(DISTINCT paydate) cpayfss3
FROM [FIN_DataMart].[dbo].[FSSpaydetl_NEW]
GROUP BY fypaydate, q, ern
) fss3
ON fss.ern = fss3.ern
AND fss.fypaydate = fss3.fypaydate
AND fss.q = fss3.q
LEFT JOIN
(
SELECT COUNT(DISTINCT paydate) cpaypdq, fy, q
FROM [FIN_DataMart].[dbo].[FSSPayDateQ]
GROUP BY fy, q
) pdq
ON fss.fypaydate = pdq.fy
AND fss.q = pdq.q
LEFT JOIN
[FIN_DataMart].[dbo].FSSEmployeeInfo e
ON fss.ern = e.ern
INNER JOIN
(
SELECT DISTINCT ern, title, tlvl, fy, q, ROW_NUMBER() OVER (PARTITION BY ern, fy, q ORDER BY title DESC) rn
FROM [FIN_DataMart].[dbo].[FSSpaydetl_NEW]
) fss4
ON fss.ern = fss4.ern
AND fss.fypaydate = fss4.fy
AND fss.q = fss4.q
AND fss4.rn = '1'
LEFT JOIN
(
SELECT TCode, TLevel, GenericTDesc as TitleDesc, EED,
ROW_NUMBER() OVER (PARTITION BY TCode, TLevel ORDER BY EED DESC) rn
FROM [FIN_DataMart].[dbo].FSATitle
) t
ON fss4.title = t.TCode
AND case when fss4.tlvl = '' THEN '01' WHEN fss4.tlvl IS NULL THEN '01' ELSE fss4.tlvl END = t.TLevel
AND t.rn = 1
LEFT JOIN FIN_DataMart.[dbo].[FSSUserERN] u
ON fss.ern = u.ern
WHERE fss.fypaydate = 2015
AND fss.q = 1
AND fss.obj <> '049' AND fss.obj NOT LIKE 'x%'
AND fss.title NOT IN ('10209', '1020B', '10234', '10232', '20202', '21205', '30086', '34201')
GROUP BY
fss.ern
, fss.pc
, fss4.title
, fss.fypaydate, fss.q
, cpayfss3, cpaypdq
, rc.CostPool
, t.TitleDesc
, e.first_name
, e.last_name
, u.OfficeTitle
HAVING SUM(CAST(rc.Eligible AS INT)) >=1
) A
GROUP BY
first_name, last_name, ern, pc, title, fypaydate, q
, [RMTS, Support, or Partial Quarter]
, OfficeTitle
, TitleDesc
, CostPool
ORDER BY first_name, last_name, fypaydate, q
You can look into using the Pivot operator to convert your rows into columns.
https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx
That method would work, although your sample data and expected result do not quite match the massive query you have posted so I cannot provide a more specific example until you provide more test data/expected outputs (and table schema).