SQL Refund Calculation Wrong - sql

I was running a query to check datausage for one company
and stumbled upon a problem, I have noticed that KB usage in final state is more than it should be. Refund script is working wrong.
I have diagnosed the problem and noticed that:
In spare 1 (refund) there is values that are not "-800" sometimes there is values that are > 0 which is a problem since refund should be minus always.
How can I implement that? I have written this but I have no idea how to continue:
SELECT callclass,redirectingnumber,spare1,spare2
FROM [CDR_Week_43].[dbo].[CDR-2013-10-20]
where 1=1
and mvno_id = 7
and callclass = 29
if [spare1] = 'Refund' and [spare2] > 0
then
In spare1 we will get 'refund' string and in spare2 there will be the value.
What I want to do is if the value is greater than 0, for example 300 it will be shown as -300 or something like that.

This query always return spare2 less than 0:
SELECT callclass,redirectingnumber,spare1,
case when spare2 > 0 then spare2 * -1 else spare2 end as spare2
FROM [CDR_Week_43].[dbo].[CDR-2013-10-20]
where mvno_id = 7 and callclass = 29
using case statement you can manipulate value in the query

SELECT
CALLCLASS
, REDIRECTINGNUMBER
, SPARE1
, CASE SPARE2 > 0 THEN SPARE2*-1 ELSE SPARE2 END AS SPARE2
FROM
[CDR_Week_43].[dbo].[CDR-2013-10-20]
WHERE
1=1
AND mvno_id = 7
AND callclass = 29

To offer another option - use the Abs() function
A mathematical function that returns the absolute (positive) value of the specified numeric expression.
SELECT ...
, Abs(spare2) * -1 As spare2
...

Related

Percentage of two values returning NULL

Same as yesterdays question which has been answered successfully but different problem. I have two values, 1 and 0 for which I need to calculate the percent change. Based on this website http://www.percent-change.com/index.php?y1=1&y2=0 the percent change between 1 and 0 is -100%. Based on the suggested formula which is (((y2- y1))/ y1) my code looks like this.
DefinedYearVSPriorYearIndividual = ((( CTEDefinedYear.IndividualCases - CTEPreviousYear.IndividualCasesLastYear ))
/ ( CTEPreviousYear.IndividualCasesLastYear ) ) * 100
which returns NULL.
The two numbers are
CTEDefinedYear.IndividualCases = 1
CTEPreviousYear.IndividualCasesLastYear = 0
The desired result should be -100%.
Can anybody see what I'm doing wrong?
Here is the answer.
Declare #y1 as int =1;
Declare #y2 as int =0;
select (((#y2- #y1))/ #y1)*100
Output is -100. You missed the *100 part.
In your case, You switched variables. attached formula is right one.
select ((0 - 1) / 1)*100;
But you used select ((1 - 0) / 0)*100;
so, you will get an error:
Msg 8134, Level 16, State 1, Line 1
Divide by zero error encountered.
You have to handle 0 in the division side, with CASE logic, to avoid divide by zero error.
DECLARE #CTEDefinedYear_IndividualCases INT = 1
DECLARE #CTEPreviousYear_IndividualCasesLastYear INT = 0
SELECT ((#CTEDefinedYear_IndividualCases - #CTEPreviousYear_IndividualCasesLastYear) / (CASE WHEN #CTEPreviousYear_IndividualCasesLastYear = 0 THEN 1 ELSE #CTEPreviousYear_IndividualCasesLastYear END)) * 100
Got it to work with this code.
DefinedYearVSPriorYearIndividual = ISNULL(100.0 *
(ISNULL(CTEDefinedYear.IndividualCases,0)
- ISNULL(CTEPreviousYear.IndividualCasesLastYear,0))
/ NULLIF(CTEPreviousYear.IndividualCasesLastYear,0),0)

Using CASE statement name as another reference filed in another CASE statement

Is it possible to refer to another case statement name in another case statement within SQL query?
Example: I have 3 case statements. The first 2 case statements are returning values based off coded fields. My 3rd case statement I would like to refer to the ending case name to return a sum of quantity.
However, I cannot figure how to get the case statement to refer to the previous case names I created. I hope I am explaining this correctly.
Any assistance would be greatly appreciated. Please see attached image for more detail.
SELECT CI_ITEM.ITEMCODE
, CI_ITEM.ITEMCODEDESC
, CASE WHEN DATEDIFF("M",CI_ITEM.DATECREATED,GETDATE()) <60 THEN DATEDIFF("M",CI_ITEM.DATECREATED,GETDATE())
ELSE 60 END AS NO_OF_MONTHS
, CASE WHEN DATEDIFF("M",IM_ITEMTRANSACTIONHISTORY.TRANSACTIONDATE,GETDATE()) <=60
AND IM_ITEMTRANSACTIONHISTORY.TRANSACTIONCODE IN ('BI','II','SO','WI')
THEN IM_ITEMTRANSACTIONHISTORY.TRANSACTIONQTY *-1 ELSE '0' END AS QTY_CONSUMED_60_MONTHS
, CASE WHEN NO_OF_MONTHS = 0 THEN 0 ELSE SUM([QTY_CONSUMED_60_MONTHS])/ [NO_OF_MONTHS] END AS MONTHLY_AVE_ON_60MONTHS_DATA
FROM CI_ITEM
INNER JOIN IM_ITEMTRANSACTIONHISTORY ON CI_ITEM.ITEMCODE = IM_ITEMTRANSACTIONHISTORY.ITEMCODE
Simply wrap your dependent cases within a sub query and reference them as fields of the sub query result.
SELECT
*,
CASE WHEN NO_OF_MONTHS = 0 THEN 0 ELSE SUM([QTY_CONSUMED_60_MONTHS])/ [NO_OF_MONTHS] END AS MONTHLY_AVE_ON_60MONTHS_DATA
FROM
(
SELECT CI_ITEM.ITEMCODE
, CI_ITEM.ITEMCODEDESC
, CASE WHEN DATEDIFF("M",CI_ITEM.DATECREATED,GETDATE()) <60 THEN DATEDIFF("M",CI_ITEM.DATECREATED,GETDATE())
ELSE 60 END AS NO_OF_MONTHS
, CASE WHEN DATEDIFF("M",IM_ITEMTRANSACTIONHISTORY.TRANSACTIONDATE,GETDATE()) <=60
AND IM_ITEMTRANSACTIONHISTORY.TRANSACTIONCODE IN ('BI','II','SO','WI')
THEN IM_ITEMTRANSACTIONHISTORY.TRANSACTIONQTY *-1 ELSE '0' END AS QTY_CONSUMED_60_MONTHS
FROM CI_ITEM
INNER JOIN IM_ITEMTRANSACTIONHISTORY ON CI_ITEM.ITEMCODE = IM_ITEMTRANSACTIONHISTORY.ITEMCODE
)AS X

case statement in where clause SQLSERVER

I tried searching around but couldn't find anything that would help me out.
I'm trying to do this in SQL:
DECLARE #onlyMM INT
SET #onlyMM = 1
SELECT *
FROM cdn.magnag
WHERE CASE #onlyMM
WHEN 1
THEN man_zrdtyp NOT IN (
1616
,2001
)
ELSE - 1
END
I have a problem with:
where case #onlyMM when 1 then man_zrdtyp not in (1616,2001) else -1 end
how to properly make a case for the operator not in?
I think you need to formulate the WHERE clause in a different way. You could use OR instead of case statement. Like this:
WHERE
(#onlyMM=1 AND man_zrdtyp not in (1616,2001))
OR #onlyMM<>1
You don't want to do this?
where (case when #onlyMM = 1 then man_zrdtyp else -1 end) not in (1616,2001)

Get work time in minutes based on shift schedule

In production we have 3 shifts. Each Shift timing is described in table tbl_ShiftSched:
WT - work time, PT - break time.
ShiftTmID - schedule for 2 and for 3 shifts.
I am looking for easy way to get work time in minutes having start and end time.
For example, having input between #2015.05.29 06:10:00# and #2015.05.29 09:30:00# and tbl_WorkStations.WksID='GRD' (Workstation code with relation on ShiftTmID ='3P') should give output 190 min.
I have function in MS Access which gives me needed output. But when migrated to T-SQL it becomes very complicated because I do not find easy way how to use alias in T-SQL. Here is the code:
USE [STRDAT]
GO
declare
#strWks varchar(3),
#dteIN datetime='2013.08.05 03:30',
#dteOUT datetime='2013.08.05 05:30',
#strShf varchar(12)=null,--'2013.08.04-3',
#strInd varchar(2) = 'WT',
#dteFTm datetime,
#dteShf date
--#PrdS datetime,
--#PrdE datetime
select top 1
#dteFTm =
case
when #strShf is not null
then (select shiftstart from tbl_ShiftSched where ShiftTmID=(select ShiftTiming from tbl_WorkStations where WksID=#strWks) and shift=right(#strshf,1) and sortind=1)
else #dteIN-dateadd(day,datediff(day,0,#dteIN),0) --CAST(#dteIN-cast(floor(#dteIN) as float) as datetime)
end,
#dteShf=
case
when #strShf is not null
then left(#strShf,10)
else convert(varchar,dateadd(day,datediff(day,0,#dteIN),0),102)
end
--select #dteftm,#dteShf
SELECT tbl_ShiftSched.Shift,
tbl_ShiftSched.SortInd,
[ShiftStart]+
case
when #dteFTm>[shiftstart]
then DateAdd(day,1,#dteShf)
else #dteShf
end AS PrdS,
[ShiftEnd]+
case
when #dteFTm>[shiftend]
then DateAdd(day,1,#dteShf)
else #dteShf
end AS PrdE,
case
when #dteIN>=[PrdS] AND [PrdE]>=#dteOUT
then DateDiff(minute,#dteIN,#dteOUT)
else case
when #dteIN<=[PrdS] AND [PrdE]<=#dteOUT
then DateDiff(minute,[PrdS],[PrdE])
else case
when [PrdS]<=#dteIN AND #dteIN<=[PrdE]
then DateDiff(minute,#dteIN,[Prde])
else case
when [PrdS]<=#dteOUT AND #dteOUT<=[PrdE]
then DateDiff(minute,[Prds],#dteOUT)
else 0
end
end
end
end AS Tm,
#dteIN AS S,
#dteOUT AS E,
tbl_ShiftSched.ShiftType,tbl_ShiftSched.ShiftStart,tbl_ShiftSched.ShiftEnd
FROM tbl_WorkStations
INNER JOIN tbl_ShiftSched ON tbl_WorkStations.ShiftTiming = tbl_ShiftSched.ShiftTmID
WHERE (((tbl_WorkStations.WksID)=#strWks))
Off course it gives me an error Invalid column name 'PrdS' and 'PrdE' because I use alias.
Must be some more easy way to achieve it. Maybe I am on wrong direction?...
Whenever I have to calculate a field and use the results in a second field, I use a common table expression to make the first calculation. Given this query, it could look like this:
with cte_preprocess as
(
SELECT tbl_ShiftSched.Shift,
tbl_ShiftSched.SortInd,
[ShiftStart]+
case
when #dteFTm>[shiftstart]
then DateAdd(day,1,#dteShf)
else #dteShf
end AS PrdS,
[ShiftEnd]+
case
when #dteFTm>[shiftend]
then DateAdd(day,1,#dteShf)
else #dteShf
end AS PrdE,
tbl_ShiftSched.ShiftType,tbl_ShiftSched.ShiftStart,tbl_ShiftSched.ShiftEnd
FROM tbl_WorkStations
INNER JOIN tbl_ShiftSched ON tbl_WorkStations.ShiftTiming = tbl_ShiftSched.ShiftTmID
WHERE (((tbl_WorkStations.WksID)=#strWks))
)
SELECT [Shift]
, SortInd
, PrdS
, PrdE
, case
when #dteIN>=[PrdS] AND [PrdE]>=#dteOUT
then DateDiff(minute,#dteIN,#dteOUT)
else case
when #dteIN<=[PrdS] AND [PrdE]<=#dteOUT
then DateDiff(minute,[PrdS],[PrdE])
else case
when [PrdS]<=#dteIN AND #dteIN<=[PrdE]
then DateDiff(minute,#dteIN,[Prde])
else case
when [PrdS]<=#dteOUT AND #dteOUT<=[PrdE]
then DateDiff(minute,[Prds],#dteOUT)
else 0
end
end
end
end AS Tm
, #dteIN
, #dteOUT
, ShiftEnd
FROM cte_preprocess
More on CTE's here

SQL simplifying case in case in case

I got the following SQL code (part of a select Statement):
Case
When HilfsTab2.Gruppe = 'HST' And Basis.Breite_FLA = Basis.Breite Then 0
Else Case When HilfsTab2.Gruppe = 'SA' Or HilfsTab2.Gruppe = 'HO / TB' Or
HilfsTab2.Gruppe = 'PR' Then 0 Else Case
When HilfsTab2.Gruppe Is Null Then -1 Else 1 End End
End As IsHST_Fluegel
Now, I run this over a table of several million entries. From my understanding, SQL checks the first case when for all rows, then the second for all entries and so on. This takes ages. Now I was thinking, there needs to be an easier way to do this.
I was thinking of a stored procedure / custom function that basically outputs -1, 0 or 1 depending on the entry.
Thanks in advance
For a possible speed improvement, do the NULL check first, the column comparison last and refactor to remove the nested CASE:
CASE WHEN HilfsTab2.Gruppe IS NULL
THEN -1
WHEN HilfsTab2.Gruppe IN ('SA', 'HO / TB', 'PR')
OR (HilfsTab2.Gruppe = 'HST' AND Basis.Breite_FLA = Basis.Breite)
THEN 0
ELSE 1
END AS IsHST_Fluegel
Your case could be simplified as:
Case
When HilfsTab2.Gruppe = 'HST' And Basis.Breite_FLA = Basis.Breite Then 0
When HilfsTab2.Gruppe in ('SA', 'HO / TB', 'PR') Then 0
When HilfsTab2.Gruppe Is Null Then -1
Else 1
End As IsHST_Fluegel
But this will not speed up your query. If you want to select millions of rows, it would take time anyway.