T - SQL variable programming like in R/C++ - sql

I have sql data of 2,907,735 rows and 32 columns.. and I want to perform simple mathematical calculations for each row using the attributes in that row.
Currently, I had to program this in R which is taking so much time, and I'm not sure SQL has the capability to do this simple programming calculations are not.
If it has the capability, I think SQL will be faster.
Please help.
q1=0
q2=0
q3=0
q4=0
frac2final=0
sumcnt = 0
cumcnt = 0
year = 0
startpoint1 = 0
startpoint2 = 0
sumexpect = 0
cntatmind = 0
cntatmaxd = 0
exatmind = 0
exatmaxd = 0
ex1=0
ex2=0
ex3=0
ex4=0
cumcntfirst = 0
for (i in 1:2907735)
{
frac2final = a[i,25]
sumcnt = a[i,31]
cumcnt = frac2final + sumcnt
year = a[i,12]
sumexpect = a[i,32]
cntatmind = a[i,4]
cntatmaxd = a[i,5]
exatmind = a[i,6]
exatmaxd = a[i,7]
if(year !=2016) {
startpoint1 = 0
startpoint2=0}
else
{startpoint1 = frac2final
startpoint2 = frac2final}
#cumcntfirst = startpoint2 + cntatmind
if (startpoint1<=0.25) q1 = max( (min(0.25,cumcnt) - startpoint1),0) else q1=0
startpoint1 = startpoint1 + q1
if(startpoint1<=0.5) q2 = max( (min(0.5,cumcnt) - startpoint1),0) else q2=0
startpoint1 = startpoint1 + q2
if(startpoint1<=0.75) q3 = max( (min(0.75,cumcnt) - startpoint1),0) else q3=0
startpoint1 = startpoint1 + q3
q4 = max(0,sumcnt-q1-q2-q3)
a[i,33] = q1
a[i,34] = q2
a[i,35] = q3
a[i,36] = q4
}

Remember in SQL we work with sets, not loops. An "Intermediate result" would be an in intermediate result set, which is synonymous with a subquery (for the most part).
As an example using your R as a starting point:
SELECT q1,
startpoint1 + q1 AS startpoint1
FROM (
startpoint1,
SELECT CASE
WHEN startpoint1 <= 0.25
THEN CASE
WHEN 0 > CASE
WHEN 0.25 > cumcnt
THEN 0.25
ELSE cumcnt
END - startpoint1
THEN 0
ELSE CASE
WHEN 0.25 > cumcnt
THEN 0.25
ELSE cumcnt
END - startpoint1
END
ELSE 0
END AS q1
FROM (
SELECT CASE
WHEN year <> 2016
THEN 0
ELSE frac2final
END AS startpoint1,
CASE
WHEN year <> 2016
THEN 0
ELSE frac2final
END AS startpoint2
FROM yourTable
) subquery1
) subquery2
There is no function to replicate your min and max here so we have to use CASE statements to do the logic. There are many examples of UDFs out there to give this functionality though. The trick is that min and max DO exist in tsql, but it takes the min/max of values in a column when aggregating many records together. Your use here is synonymous with UDFs generally called GREATEST() and LEAST() to compare two or more fields from the same record.
To get a grasp on how this is working, run the inner-most subquery and see what it produces, then run the next subquery (which has subquery1 inside of it) to see how it uses those results... then you can just reuse this logic to build your remaining fields for your final result set.

Related

CASE WHEN THEN Cannot perform an aggregate function on an expression containing an aggregate or a subquery

this is my code:
SELECT SUM
(CASE
WHEN (dbo.EMBARQUE.EmbEst) = 0 THEN
0
WHEN (dbo.EMBARQUE.EmbEst) = 3 THEN
0
WHEN (dbo.EMBARQUE.EmbEst) = 6 THEN
0
WHEN (dbo.EMBARQUE.EmbEst) = 7 THEN
CASE
WHEN (SELECT COUNT (dbo.CUMPLIDO.CumpCod) from dbo.CUMPLIDO where dbo.CUMPLIDO.EmbCod = dbo.EMBARQUE.EmbCod and dbo.CUMPLIDO.CumpVol = 0) > 0 THEN
0
ELSE
dbo.EMBARQUE.EmbVol
END
ELSE
dbo.EMBARQUE.EmbVol
END) FROM dbo.EMBARQUE
You have a subquery inside sum(). That isn't allowed. This version uses a subquery to calculate the flag you want and then moves the filtering logic to the WHERE clause:
SELECT SUM(e.EmbVol)
FROM (SELECT e.*,
(CASE WHEN EXISTS (SELECT 1 FROM dbo.CUMPLIDO c WHERE c.EmbCod = e.EmbCod AND c.CumpVol = 0)
THEN 1 ELSE 0
END) as is_CumpVol_0
FROM dbo.EMBARQUE e
WHERE e.EmbEst NOT IN (0, 3, 6)
) e
WHERE e.EmbEst <> 7 OR is_CumpVol_0 = 0;

RunningSum inside another

I have a report with the following data
IdSource 20170629 20170628 20170626 20170625 20170624 20170623
Id1. OK KO N/A KO OK KO
I want to count the number of days my data (status of a workflow) is KO. N/A means the worflow is not expected, so it should not be counted.
Expected results :
IdSource 20170629 20170628 20170626 20170625 20170624 20170623
Id1. OK KO(2) N/A KO(1) OK KO(1)
The count must be reset at each OK.
In SQL, I would do
select t.*,
sum(case when status = 'KO' then 1 else 0 end) over (partition by id, cume_ko order by date) as nbDayKO
from (select t.*,
sum(case when status = 'OK' then 1 else 0 end) over (partition by id order by date) as cume_ko
from t
) t
I tried to use the RunningSum function without success:
I need to inverse the sort on the date
I cannot use the result of a runningSum inside another.
Thanks for your help
It's ugly and not very efficient, but I did not find any other solutions. Here is how I did it :
If ([status] = 0) Then 0
Else (
(If (RelativeValue([status];([dayOfWeek]);1) = 1) Then
If (RelativeValue([status];([dayOfWeek]);2) = 1) Then
If (RelativeValue([status];([dayOfWeek]);3) = 1) Then
If (RelativeValue([status];([dayOfWeek]);4) = 1) Then
If (RelativeValue([status];([dayOfWeek]);5) = 1) Then
If (RelativeValue([status];([dayOfWeek]);6) = 1) Then
If (RelativeValue([status];([dayOfWeek]);7) = 1) Then
If (RelativeValue([status];([dayOfWeek]);8) = 1) Then
If (RelativeValue([status];([dayOfWeek]);9) = 1) Then
If (RelativeValue([status];([dayOfWeek]);10) = 1) Then
If (RelativeValue([status];([dayOfWeek]);11) = 1) Then
If (RelativeValue([status];([dayOfWeek]);12) = 1) Then
If (RelativeValue([status];([dayOfWeek]);13) = 1) Then
If (RelativeValue([status];([dayOfWeek]);14) = 1) Then
If (RelativeValue([status];([dayOfWeek]);15) = 1) Then 15
Else 14
Else 13
Else 12
Else 11
Else 10
Else 9
Else 8
Else 7
Else 6
Else 5
Else 4
Else 3
Else 2
Else 1
Else 0)+[status])

Rewrite subquery with calculation in SQL to CASE statement

I have, as a part of a bigger query, some subqueries that I would like to convert to CASE statements instead.
The subquery looks like this (and works):
(SELECT (((SUM(DAm)-(SUM(StcCst)*-1))*100)/NULLIF(SUM(DAm),0)) AS 'DG' FROM [F0001].[dbo].[ProdTr] WHERE AcYrPr = '201601' AND ProdTr.TrTp = 1 AND [F0001].[dbo].[ProdTr].CustNo = '12773') AS dg_period_1
However, I don't seem to find any logical way to put this into a CASE-statement.
Any help would be appreciated!
(
SELECT CASE
WHEN SUM(t1.DAm) <> 0
THEN (SUM(t1.DAm) + SUM(t1.StcCst)) * 100 / SUM(t1.DAm)
ELSE 0 /* or whatever you want to have in this case */
END AS 'DG'
FROM [F0001].[dbo].[ProdTr] t1
WHERE t1.AcYrPr = '201601' AND
t1.TrTp = 1 AND
t1.CustNo = '12773'
) AS dg_period_1
I also removed some unneeded parentheses and simplified an operation (x - (y * -1) = x + y)
You could use the following statement with CASE provided you want to return a null when SUM(DAm) is null or 0.
(SELECT CASE
WHEN SUM(DAm) IS NOT NULL and SUM(DAm) <> 0 THEN (((SUM(DAm) - (SUM(StcCst) * -1)) * 100) /SUM(DAm))
ELSE NULL
END AS 'DG'
FROM [F0001].[dbo].[ProdTr]
WHERE AcYrPr = '201601'
AND ProdTr.TrTp = 1
AND [F0001].[dbo].[ProdTr].CustNo = '12773') AS dg_period_1

Combining Case Statements in a View

I have these two case statements and can not for the life of me figure out how to combine them to show in a MSSQL view. Any help would be great.
CASE WHEN [ordertype] = '2' THEN [CommissionAmt1] * - 1 ELSE [CommissionAmt1] END
and
CASE WHEN (is_member('Buyer') = 1 OR is_member('CustomerService') = 1) THEN 0 ELSE CommissionAmt1 END
Just adding the first case to wherever the CommissionAmt1 is referenced in the second statement.
CASE WHEN (is_member('Buyer') = 1 OR is_member('CustomerService') = 1) THEN
0
ELSE
CASE WHEN [ordertype] = '2' THEN
[CommissionAmt1] * - 1
ELSE
[CommissionAmt1]
END
END
Or going the other way. It was hard to understand which way the calculation needs to be performed. The only hint was []
CASE WHEN [ordertype] = '2' THEN
(
CASE WHEN (is_member('Buyer') = 1 OR is_member('CustomerService') = 1) THEN
0
ELSE
CommissionAmt1
END
) * - 1
ELSE
CASE WHEN (is_member('Buyer') = 1 OR is_member('CustomerService') = 1) THEN
0
ELSE
CommissionAmt1
END
END
Either way, you would be able to save some calculations by sub querying the dependent value.
SELECT
*,
ValueWithDependant=CASE WHEN (Dependant>0) THEN (SomeValue / Dependant) ELSE NULL END
FROM
(
SELECT
X,Y,Z,
Dependant=CASE WHEN SomeValue=1 THEN 1 ELSE 0 END
FROM
SomeTable
)AS DETAIL

Understanding case expression in the "Where" clause

I've got this code here and you can see from my Pseudocode what I'm trying to accomplish
select *
from dbo.BenefitsForms
inner join Dependents on BenefitsForms.UserId = Dependents.BenefitsForm_UserId
inner join CoverageLevels on BenefitsForms.MedicalId = CoverageLevels.Id
where (BenefitsForms.MedicalId > 0 AND BenefitsForms.MedicalId < 13)
AND Dependents.IsSpouse = CASE when CoverageLevels.[Level] = 2 then 1
when CoverageLevels.[Level] = 3 then 0 end
when CoverageLevels.[Level] = 4 then [any, it doesnt matter] <--- my desire but it doesn't work.
What can I do to get the effect I desire in the brackets? If Coverage Level = 4 then I don't care what Dependents.IsSpouse is, I don't even need to sort by it anymore.
Assuming that isSpouse can only be 0 or 1... if CoverageLevels.Level is 4, then compare isSpouse to itself, which will always result in true:
AND Dependents.IsSpouse = CASE
when CoverageLevels.[Level] = 2 then 1
when CoverageLevels.[Level] = 3 then 0
when CoverageLevels.[Level] = 4 then Dependents.IsSpouse
END
Alternately, this can also be expressed without the CASE:
WHERE
BenefitsForms.MedicalId > 0
AND BenefitsForms.MedicalId < 13
AND (
(Dependents.IsSpouse = 1 AND CoverageLevels.[Level] = 2)
OR (Dependents.IsSpouse = 0 AND CoverageLevels.[Level] = 3)
OR CoverageLevels.[Level] = 4
)