How subtract two aliases which are result of two cases - sql-server

I'm struggling trying to subtract to results of a case within a SQL query. Do you guys can help me out?
Here is a "simplified" version of the query.
SELECT dbo.tbla.cola, dbo.tblb.colb, dbo.tblb.colc,
CASE WHEN
(SELECT TOP 1 dstStart
FROM tblDst
WHERE tblcd.Key = dbo.tblDst.Key) >= DTimeU AND
(SELECT TOP 1 dstEnd
FROM tblDst
WHERE tblcd.Key = dbo.tblDst.Key) <= DTimeU
THEN tblcd.ApUtc + 1 ELSE tblcd.ApUtc END AS DepDST, CASE WHEN
(SELECT TOP 1 dstStart
FROM tblDst
WHERE tblca.Key = dbo.tblDst.Key) >= ATimeU AND
(SELECT TOP 1 dstEnd
FROM tblDst
WHERE tblca.Key = dbo.tblDst.Key) <= ATimeU THEN tblca.ApUtc + 1 ELSE tblca.ApUtc END AS ArrDST
FROM ...
WHERE ...
How could I perform (ArrDST-DepDST) As DiffDST ?
Regards,
Dave

Simply wrap the query with another select :
SELECT t.*, t.ArrDST - t.DepDST as DiffDST
FROM (YOUR QUERY HERE) t
Then all the calculated columns will be available for use.

Related

GROUP BY vs DISTINCT with a constant value in SELECT inside a subquery - Performance Difference

I noticed a performance difference between GROUP BY and DISTINCT inside a subquery when a constant value is introduced is_issued = 1 (if this is removed both queries works same).
The following query with GROUP BY takes 15+ mins
Execution Plan - GROUP BY
/*Takes 10+ mins*/
SELECT ld.[LNum],
is_lease_insured = CAST(COALESCE(i.is_issued, 0) AS BIT)
FROM [dbo].[snapshot_ld] ld
LEFT JOIN
(
SELECT LNum = value,
i.snapshot_date,
is_issued = 1
FROM [dbo].[snapshot_ip] i
CROSS APPLY STRING_SPLIT(i.LNum, ',')
GROUP BY value,
i.snapshot_date
) i
ON ld.[LNum] = i.LNum
AND ld.snapshot_date = i.snapshot_date
WHERE ld.RowIsDeleted = 0
AND ld.bimonthly_snapshot_date_flag = 1;
And this one with the DISTINCT takes just 2 seconds
Execution Plan - DISTINCT
/*Takes 2seconds*/
SELECT ld.LNum,
is_lease_insured = CAST(COALESCE(i.is_issued, 0) AS BIT)
FROM [dbo].[snapshot_ld] ld
LEFT JOIN
(
SELECT DISTINCT
lno = value, /*Added DISTINCT and Removed GROUP BY*/
i.snapshot_date,
is_issued = 1
FROM [dbo].[snapshot_ip] i
CROSS APPLY STRING_SPLIT(i.LNum, ',')
--GROUP BY value, i.snapshot_date
) i
ON ld.LNum = i.lno
AND ld.snapshot_date = i.snapshot_date
WHERE ld.RowIsDeleted = 0
AND ld.bimonthly_snapshot_date_flag = 1;
Should I use the one with DISTINCT and hope the performance issue doesn't strike in the future?
Or Can I know if there is there is a way to tune this scenario with GROUP BY.
Any help is much appreciated.
Table and View Definitions

SQL - Finding Gaps in Coverage

I am running this problem on SQL server
Here is my problem.
have something like this
Dataset A
FK_ID StartDate EndDate Type
1 10/1/2018 11/30/2018 M
1 12/1/2018 2/28/2019 N
1 3/1/2019 10/31/2019 M
I have a second data source I have no control over with data something like this:
Dataset B
FK_ID SpanStart SpanEnd Type
1 10/1/2018 10/15/2018 M
1 10/1/2018 10/25/2018 M
1 2/15/2019 4/30/2019 M
1 5/1/2019 10/31/2019 M
What I am trying to accomplish is to check to make sure every date within each TYPE M record in Dataset A has at least 1 record in Dataset B.
For example record 1 in Dataset A does NOT have coverage from 10/26/2018 through 11/30/2018. I really only care about when the coverage ends, in this case I want to return 10/26/2018 because it is the first date where the span has no coverage from Dataset B.
I've written a function that does this but it is pretty slow because it is cycling through each date within each M record and counting the number of records in Dataset B. It exits the loop when it finds the first one but I would really like to make this more efficient. I am sure I am not thinking about this properly so any suggestions anyone can offer would be helpful.
This is the section of code I'm currently running
else if #SpanType = 'M'
begin
set #CurrDate = #SpanStart
set #UncovDays = 0
while #CurrDate <= #SpanEnd
Begin
if (SELECT count(*)
FROM eligiblecoverage ec join eligibilityplan ep on ec.plandescription = ep.planname
WHERE ec.masterindividualid = #IndID
and ec.planbegindate <= #CurrDate and ec.planenddate >= #CurrDate
and ec.sourcecreateddate = #MaxDate
and ep.medicaidcoverage = 1) = 0
begin
SET #Result = concat('NON Starting ',format(#currdate, 'M/d/yyyy'))
BREAK
end
set #CurrDate = #CurrDate + 1
end
end
I am not married to having a function it just could not find a way to do this in queries that wasn't very very slow.
EDIT: Dataset B will never have any TYPEs except M so that is not a consideration
EDIT 2: The code offered by DonPablo does de-overlap the data but only in cases where there is an overlap at all. It reduces dataset B to:
FK_ID SpanStart SpanEnd Type
1 10/1/2018 10/25/2018 M
instead of
FK_ID SpanStart SpanEnd Type
1 10/1/2018 10/25/2018 M
1 2/15/2019 4/30/2019 M
1 5/1/2019 10/31/2019 M
I am still futzing around with it but it's a start.
I would approach this by focusing on B. My assumption is that any absent record would follow span_end in the table. So here is the idea:
Unpivot the dates in B (adding "1" to the end dates)
Add a flag if they are present with type "M".
Check to see if any not-present records are in the span for A.
Check the first and last dates as well.
So, this looks like:
with bdates as (
select v.dte,
(case when exists (select 1
from b b2
where v.dte between b2.spanstart and b2.spanend and
b2.type = 'M'
)
then 1 else 0
end) as in_b
from b cross apply
(values (spanstart), (dateadd(day, 1, spanend)
) v(dte)
where b.type = 'M' -- all we care about
group by v.dte -- no need for duplicates
)
select a.*,
(case when not exists (select 1
from b b2
where a.startdate between b2.spanstart and b2.spanend and
b2.type = 'M'
)
then 0
when not exists (select 1
from b b2
where a.enddate between b2.spanstart and b2.spanend and
b2.type = 'M'
)
when exists (select 1
from bdates bd
where bd.dte between a.startdate and a.enddate and
bd.in_b = 0
)
then 0
when exists (select 1
from b b2
where a.startdate between b2.spanstart and b2.spanend and
b2.type = 'M'
)
then 1
else 0
end)
from a;
What is this doing? Four validity checks:
Is the starttime valid?
Is the endtime valid?
Are any intermediate dates invalid?
Is there at least one valid record?
Start by framing the problem in smaller pieces, in a sequence of actions like I did in the comment.
See George Polya "How To Solve It" 1945
Then Google is your friend -- look at==> sql de-overlap date ranges into one record (over a million results)
UPDATED--I picked Merge overlapping dates in SQL Server
and updated it for our table and column names.
Also look at theory from 1983 Allen's Interval Algebra https://www.ics.uci.edu/~alspaugh/cls/shr/allen.html
Or from 2014 https://stewashton.wordpress.com/2014/03/11/sql-for-date-ranges-gaps-and-overlaps/
This is a primer on how to setup test data for this problem.
Finally determine what counts via Ranking the various pairs of A vs B --
bypass those totally Within, then work with earliest PartialOverlaps, lastly do the Precede/Follow items.
--from Merge overlapping dates in SQL Server
with SpanStarts as
(
select distinct FK_ID, SpanStart
from Coverage_B as t1
where not exists
(select * from Coverage_B as t2
where t2.FK_ID = t1.FK_ID
and t2.SpanStart < t1.SpanStart
and t2.SpanEnd >= t1.SpanStart)
),
SpanEnds as
(
select distinct FK_ID, SpanEnd
from Coverage_B as t1
where not exists
(select * from Coverage_B as t2
where t2.FK_ID = t1.FK_ID
and t2.SpanEnd > t1.SpanEnd
and t2.SpanStart <= t1.SpanEnd)
),
DeOverlapped_B as
(
Select FK_ID, SpanStart,
(select min(SpanEnd) from SpanEnds as e
where e.FK_ID = s.FK_ID
and SpanEnd >= SpanStart) as SpanEnd
from SpanStarts as s
)
Select * from DeOverlapped_B
Now we have something to feed into the next steps, and we can use the above as a CTE
======================================
with SpanStarts as
(
select distinct FK_ID, SpanStart
from Coverage_B as t1
where not exists
(select * from Coverage_B as t2
where t2.FK_ID = t1.FK_ID
and t2.SpanStart < t1.SpanStart
and t2.SpanEnd >= t1.SpanStart)
),
SpanEnds as
(
select distinct FK_ID, SpanEnd
from Coverage_B as t1
where not exists
(select * from Coverage_B as t2
where t2.FK_ID = t1.FK_ID
and t2.SpanEnd > t1.SpanEnd
and t2.SpanStart <= t1.SpanEnd)
),
DeOverlapped_B as
(
Select FK_ID, SpanStart,
(select min(SpanEnd) from SpanEnds as e
where e.FK_ID = s.FK_ID
and SpanEnd >= SpanStart) as SpanEnd
from SpanStarts as s
),
-- find A row's coverage
ACoverage as (
Select
a.*, b.SpanEnd, b.SpanStart,
Case
When SpanStart <= StartDate And StartDate <= SpanEnd
And SpanStart <= EndDate And EndDate <= SpanEnd
Then '1within' -- starts, equals, during, finishes
When EndDate < SpanStart
Or SpanEnd < StartDate
Then '3beforeAfter' -- preceeds, meets, preceeded, met
Else '2overlap' -- one or two ends hang over spanStart/End
End as relation
From Coverage_A a
Left Join DeOverlapped_B b
On a.FK_ID = b.FK_ID
Where a.Type = 'M'
)
Select
*
,Case
When relation1 = '2' And StartDate < SpanStart Then StartDate
When relation1 = '2' Then DateAdd(d, 1, SpanEnd)
When relation1 = '3' Then StartDate
End as UnCoveredBeginning
From (
Select
*
,SUBSTRING(relation,1,1) as relation1
,ROW_NUMBER() Over (Partition by A_ID Order by relation, SpanStart) as Rownum
from ACoverage
) aRNO
Where Rownum = 1
And relation1 <> '1'

Second Order By overrides first in SQL Server

In the following code the purchase_price overrides the case order by statement.
SELECT
i.products_mpn, i.active,
i.distributor_code, i.sales_price
FROM
#duplicates d
LEFT JOIN
import i ON i.products_mpn = d.products_mpn
AND i.distributor_code = (SELECT TOP 1 distributor_code
FROM dbo.kting_ICECAT_import
WHERE products_mpn = d.products_mpn
ORDER BY
(SELECT
CASE
WHEN (i.distributor_code = 'x' or i.distributor_code = 'y') AND CAST(stock as int) > 0
THEN 2
WHEN CAST(stock as int) > 0
THEN 1
ELSE 0
END) DESC,
CAST(purchase_price AS decimal(28,12)))
Is there any way to get it to work with ordering by the case statement and then the purchase_price?
If you want the ordering of the CASE statement to be applied first followed by the ordering of the purchase_price, then your ORDER BY already has the terms in the right place. I don't know what SELECT is doing in your CASE expression, or even if your current query runs. Something like this may be what you had in mind:
ORDER BY CASE WHEN (i.distributor_code = 'x' or i.distributor_code = 'y') AND
CAST(stock as int) > 0 THEN 2
WHEN CAST(stock as int) > 0 THEN 1
ELSE 0
END DESC,
CAST(purchase_price AS DECIMAL(28,12))
The problem was in the ORDER BY SELECT. I had used columns from the left join "i.distributor_code" should just have been distributor_code

SQL Server Remove unwanted rows from a CASE statement

I do a SELECT with a CASE statement with this following:
SELECT DISTINCT
n.NiveauId, n.Description,
CASE WHEN n.NiveauId NOT IN (SELECT ccs.idNiveau WHERE ccs.centreCout = 60001) THEN 0 ELSE 1 END AS attribue
FROM pa.dbo.Niveau n
JOIN BDC.dbo.CentreCoutSecteur ccs ON n.NiveauId = ccs.idNiveau
Explication :
In case "NiveauId" is not present in the other table, the value of "attribue" is 0. Else, if it's present, the value is 1.
This works, but every rows that contains a 1 also shows the same row with a 0.
Exemple:
How would I change the SELECT query to remove the unwanted duplicate rows that contain 0?
Thanks in advance!
Try wrapping your select in a max (if you only want the rows with the highest value for attribue.
SELECT b.NiveauID, b.Description, MAX(b.attribue)
FROM
(SELECT DISTINCT
n.NiveauId, n.Description,
CASE WHEN n.NiveauId NOT IN (SELECT ccs.idNiveau WHERE ccs.centreCout = 60001) THEN 0 ELSE 1 END AS attribue
FROM pa.dbo.Niveau n
JOIN BDC.dbo.CentreCoutSecteur ccs ON n.NiveauId = ccs.idNiveau) b
Group By b.NiveauID, b.Description

Add ORDER BY statement to SELECT statement

I have the following SELECT statement and I need to add ORDER BY [UserName].
SELECT *
FROM [UserInfo]
WHERE ([AWSAccountID] = CASE WHEN #AWSAccountID = -1 THEN [AWSAccountID]
ELSE #AWSAccountID END)
I'm having some trouble figuring out where the ORDER BY needs to go, assuming it can be added at all.
Unless I am missing something you just add your ORDER BY to the end of the query:
SELECT *
FROM [UserInfo]
WHERE ([AWSAccountID] = CASE WHEN #AWSAccountID = -1 THEN [AWSAccountID]
ELSE #AWSAccountID END)
ORDER BY [UserName]

Resources