SQL Server 2012 Case statement cannot update what I need it to update - sql

I'm trying to figure out how to make this formula work for my SQL Server 2012, and it has me completely stumped. In the first case statement where I am trying to set the Dateupdated column, on the middle line, I have it as
WHEN standardunitcost > (averageunitcost + 2.000000) THEN GETDATE()
I need to add something extra in there to make sure that the (Averageunitcost + 2.000000) is greater than 22. When I try to set it up as ((Averageunitcost + 2.000000) > 22.000000) it is incompatible.
Can someone explain to me why I cannot do it the way I am currently trying, and how to make this work properly? Also, I'm sorry if this is in the incorrect place, or has been asked before, but I'm not really sure what to search for to solve this!
UPDATE [mas_wgd].[dbo].[CI_Item]
SET dateupdated = CASE
WHEN StandardUnitCost < AverageUnitCost THEN GETDATE()
WHEN standardunitcost > (AverageUnitCost + 2.000000) THEN GETDATE()
WHEN StandardUnitCost < 22.000000 THEN GETDATE()
ELSE dateupdated
END
WHERE ProductLine IN ('A010', 'A020', 'A030', 'A040', 'A050', 'A060', 'A070', 'A080', 'A090', 'A100', 'A110', 'A120', 'A130', 'A130', 'A140', 'A150', 'A200', 'A250', 'A300', 'A350', 'A400', 'A450', 'A500', 'A550', 'A600', 'AGNC', 'C010', 'C020', 'C030', 'C040', 'C050', 'C060', 'C070', 'C080', 'C090', 'C100', 'C110', 'C120', 'C130', 'C130', 'C140', 'C150', 'C200', 'C250', 'C300', 'C350', 'C400', 'C450', 'C500', 'C550', 'C600', 'CGNC')
UPDATE [mas_wgd].[dbo].[CI_Item]
SET Standardunitcost = CASE
WHEN (AverageUnitCost between 0.010000 and 22.000000) THEN 22.00000
WHEN AverageUnitCost > 22.000000 THEN AverageUnitCost + 2.000000
ELSE StandardUnitCost
END
WHERE ProductLine IN ('A010', 'A020', 'A030', 'A040', 'A050', 'A060', 'A070', 'A080', 'A090', 'A100', 'A110', 'A120', 'A130', 'A130', 'A140', 'A150', 'A200', 'A250', 'A300', 'A350', 'A400', 'A450', 'A500', 'A550', 'A600', 'AGNC', 'C010', 'C020', 'C030', 'C040', 'C050', 'C060', 'C070', 'C080', 'C090', 'C100', 'C110', 'C120', 'C130', 'C130', 'C140', 'C150', 'C200', 'C250', 'C300', 'C350', 'C400', 'C450', 'C500', 'C550', 'C600', 'CGNC')

The exact syntax that is not working has not been posted, but is implied as being:
WHEN standardunitcost > ((Averageunitcost + 2.000000) > 22.000000) THEN GETDATE()
You cannot do compound comparison operations in SQL like you can in many languages. These need to be broken out into individual operations combined with the logical operator AND.
CASE
WHEN StandardUnitCost < AverageUnitCost THEN GETDATE()
WHEN (AverageUnitCost + 2.0) > 22
AND StandardUnitCost > (AverageUnitCost + 2.0) THEN GETDATE()
WHEN StandardUnitCost < 22.0 THEN GETDATE()
ELSE DateUpdated
END
But what about when [StandardUnitCost] = 22.0? Currently if StandardUnitCost is not "<" AverageUnitCost (the first condition), then this logic is only checking for > 22.000002 (or something like that) and < 22.0. It just seems like at least one of those comparisons needs to be either <= or >=.

Related

How do I add conditional statements to test for a specific value in dynamic where clause in stored procedure

I have a stored procedure into which I pass a number of variables and I create a dynamic where clause using the "AND (#var IS NULL OR table.field = #var)" and it works great... EXCEPT
One of the variables (#statusLevel) can be either 1-9 or 10. When the value passed in is 10, I want to return ONLY those projects that have a statusLevel = 10. When the value passed in is between 1 & 9, I want to return all of the projects between that value (let's say '5') and less than 10.
I've got each part working perfectly independently but I'm lost on how to get them to work together.
AND ((#statusLevelID IS NULL OR project.statusLevelID >= #statusLevelID) AND (#statusLevelID IS NULL OR project.statusLevelID < 10))
AND (#statusLevelID IS NULL OR project.statusLevelID = 10)
Using an "OR" just gives me ALL of the projects.
AND ((#statusLevelID IS NULL OR project.statusLevelID >= #statusLevelID) AND (#statusLevelID IS NULL OR project.statusLevelID < 10)
OR (#statusLevelID IS NULL OR project.statusLevelID = 10))
I was thinking a CASE statement might work here but I'm not exactly sure how to implement that.
Any assistance is greatly appreciated. Thanks in advance.
You want one boolean expression connected by ORs:
AND ( (#statusLevelID IS NULL) OR
(#statusLevelID = project.statusLevelID) OR
(#statusLevelID <> 10 AND project.statusLevelID >= #statusLevelID AND project.statusLevelID < 10)
)
You can write the condition like so:
AND (
#statusLevelID IS NULL
OR
project.statusLevelID BETWEEN #statusLevelID AND IIF(#statusLevelID = 10, 10, 9)
)

MSSQL Stored Procedure with dynamically added WHERE?

I have this Stored Procedure, where i need to check if #DateChk == 1, THEN i want to add a WHERE-clause to the SQL statement in the SP. If its 0, there should not be any WHERE-clause.
How do i script such function? In a program i could just build in the string to pass to the server, but i have not found any way to do this in the SQL server.
SELECT dateDay, SUM(nok) as NOK, SUM(ok) as OK, (SUM(ok) + SUM(nok)) as 'Total'
FROM #st
SELECT CASE #DateChk
WHEN 1: WHERE dateDay BETWEEN '2016-08-01' AND '2016-08-31'
Something like this, if #DateChk = 1, the WHERE should be added, else fetch all records.
You can modify your condition like this:
SELECT dateDay, SUM(nok) as NOK, SUM(ok) as OK, (SUM(ok) + SUM(nok)) as 'Total'
FROM #st
WHERE
(#DateChk = 1 and (dateDay BETWEEN '2016-08-01' AND '2016-08-31'))
or #DateChk = 0
And it will exactly match your desired behaviour: condition on dateDay will be applied only when #DateChk = 1.

Set Date from another table in SQL Server

I have a code in VB.Net application which I would like to move to stored procedure.
VB code looks something like this :
if(id == 3)
{
var year = Year(invoiceDate)
updatedDate = DateSerial(dueYear, DueDateMonth, DueDateDay)
If updatedDate < invoiceDate Then
updatedDate += 1
updatedDate = DateSerial(updatedDate , getMonthFromDBTable, getDayFromDBTable)
End If
}
This is part of a condition which I am trying to resolve.
Currently in SQL I have the following
DECLARE #tmpCalendarDate DATETIME;
DECLARE #tmpYear int;
SET #tmpCalendarDate = convert(varchar(10), getdate(),120);
SET #tmpYear = DATEPART(yyyy, #tmpCalendarDate);
SELECT COALESCE (
CASE WHEN tt.ID = 1 THEN DATEADD(day, t.DaysUntilDue, r.InvoiceDate) END,
CASE WHEN tt.ID = 3 THEN -- This is where I need to add the condition.
I was thinking of setting the #tmpCalendarDate with the values to look something like
CASE WHEN tt.ID = 3 THEN #tmpCalendarDate = '#tmpYear-t.DueDateMonth-t.DueDateDay'
where t is a table.
This value cannot be changed, so I would rather calculate and fetch it once rather than calculating it every time binding changes (wpf application).
Any help is greatly appreciated.
UPDATE: I realized maybe I am vague with my question, so here it is
How do i set #tmpCalendarDate? I tried
SELECT #tmpCalendarDate = '#tmpYear-t.DueDateMonth-t.DueDateDay' FROM table t
and I get an error 'Conversion failed when converting date and/or time from character string.' Instead I am expecting something like #tmpCalendarDate to be set to '2016-03-12'
Also, can I add an If..Else condition inside CASE.Then
In my example:
CASE WHEN tt.ID = 3 THEN #tmpCalendarDate = '#tmpYear-t.DueDateMonth-t.DueDateDay'
IF (#tmpCalendarDate > InvoiceDate)
BEGIN
--Do some logic
END
ELSE
--Do some logic
BEGIN
END
You can use DATEFROMPARTS
#tmpCalendarDate = DATEFROMPARTS(#tmpyear, t.DueDateMonth, t.DueDateDay)
Your mistake in your original attempt is you are setting #tempCalendarDate to actual string #tmpYear-t.DueDateMonth-t.DueDateDay which results in a conversion error.

Divide by zero error in SQL even though I excluded the zero cases?

Here is the code that I've been trying to run:
SELECT C.* FROM
(SELECT
B.[OUTSIDE_ROW],
B.[INSIDE_ROW],
B.[r_HU_vac_ns],
B.[r_HU_vac_ns_MOE],
CASE WHEN B.[r_HU_vac_ns] = 0 THEN 999 ELSE B.[r_HU_vac_ns_MOE]/B.[r_HU_vac_ns] END AS [PCT]
FROM
(SELECT
A.[OUTSIDE_ROW],
A.[INSIDE_ROW],
(A.[HU_VACANT] - A.[HU_VACANT_SEASONAL_RECREATIONAL])/A.[HU_VACANT] AS [r_HU_vac_ns],
(1/A.[HU_VACANT]) * POWER(
CASE WHEN ((A.[HU_VACANT] - A.[HU_VACANT_SEASONAL_RECREATIONAL])/A.[HU_VACANT]) * POWER(A.[HU_VACANT_MOE], 2) < POWER(A.[HU_VACANT_MOE], 2) + POWER(A.[HU_VACANT_SEASONAL_RECREATIONAL_MOE], 2) THEN POWER(A.[HU_VACANT_MOE], 2) + POWER(A.[HU_VACANT_SEASONAL_RECREATIONAL_MOE], 2) - (((A.[HU_VACANT] - A. [HU_vACANT_SEASONAL_RECREATIONAL])/A.[HU_VACANT]) * POWER(A.[HU_VACANT_MOE], 2))
ELSE POWER(A.[HU_VACANT_MOE], 2) + POWER(A. [HU_VACANT_SEASONAL_RECREATIONAL_MOE], 2) + (((A.[HU_VACANT] - A. [HU_vACANT_SEASONAL_RECREATIONAL])/A.[HU_VACANT]) * POWER(A.[HU_VACANT_MOE], 2)) END, 0.5) AS [r_HU_vac_ns_MOE]
FROM
(SELECT
[OUTSIDE_ROW],
[INSIDE_ROW],
SUM([ESTIMATE_1]) AS [HU_VACANT],
POWER(SUM(POWER([MOE_1], 2)), 0.5) AS [HU_VACANT_MOE],
SUM([ESTIMATE_2]) AS [HU_VACANT_SEASONAL_RECREATIONAL],
POWER(SUM(POWER([MOE_2], 2)), 0.5) AS [HU_VACANT_SEASONAL_RECREATIONAL_MOE]
FROM #TEST_TABLE
GROUP BY [OUTSIDE_ROW], [INSIDE_ROW]) A
WHERE A.[HU_VACANT] > 0) B ) C
WHERE C.[PCT] < 0.2
Every time I run it, I get the following error:
Msg 8134, Level 16, State 1, Line 533
Divide by zero error encountered.
However, if I take off the last line of code (the following WHERE clause) the code runs fine:
WHERE C.[PCT] < 0.2
Just from looking at my query, can anyone tell me what I'm doing wrong? I thought I eliminated all PCT values that were zero with the CASE WHEN statement below so this error is baffling me:
CASE WHEN B.[r_HU_vac_ns] = 0 THEN 999 ELSE B.[r_HU_vac_ns_MOE]/B.[r_HU_vac_ns] END AS [PCT]
If it helps, PCT is cast as floating point.
Thanks.
SQL Server reserves the right to rearrange calculations. That means that the calculation in a SELECT can happen before filtering occurs. This is true even when the filters are in subqueries and CTEs.
The only way to guarantee order of calculation is CASE. However, I think it is easier to just use NULLIF(), an ANSI standard function. Instead of logic like this:
(A.[HU_VACANT] - A.[HU_VACANT_SEASONAL_RECREATIONAL])/A.[HU_VACANT] AS [r_HU_vac_ns],
do:
(A.[HU_VACANT] - A.[HU_VACANT_SEASONAL_RECREATIONAL])/NULLIF(A.[HU_VACANT], 0) AS [r_HU_vac_ns],
Instead of filtering out the records using
WHERE A.[HU_VACANT] > 0
You should filter out the records at root level
having SUM([ESTIMATE_1]) > 0
You could also use nullif function but that will result producing NULL where you have zero

SQL Refund Calculation Wrong

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
...