Stock ageing with SQL Server - sql

I have a table content as below, where 'ItemName' is the name of the items, 'CurrentStock' is the current stock quantity of items and all other columns are the sum of stock-in and stock-out on that year. Now I want to replace all negative value with 0 and adjust those negative value with the positive value in FIFO order. Can any one guide me how do that in SQL Server.
Here is the Expected Result
Initially I tried like this
select ItemName,CurrentStock,
case when (Qnty2018+Qnty2017+Qnty2016+Qnty2015+Qnty2014+Qnty2013)<0 and (Qnty2018+Qnty2017+Qnty2016+Qnty2015+Qnty2014+Qnty2013+Qnty2012andBefore)>=0 then (Qnty2018+Qnty2017+Qnty2016+Qnty2015+Qnty2014+Qnty2013+Qnty2012andBefore)
when (Qnty2017+Qnty2016+Qnty2015+Qnty2014+Qnty2013)<0 and (Qnty2017+Qnty2016+Qnty2015+Qnty2014+Qnty2013+Qnty2012andBefore)>=0 THEN (Qnty2017+Qnty2016+Qnty2015+Qnty2014+Qnty2013+Qnty2012andBefore)
when (Qnty2016+Qnty2015+Qnty2014+Qnty2013)<0 and (Qnty2016+Qnty2015+Qnty2014+Qnty2013+Qnty2012andBefore)>=0 THEN (Qnty2016+Qnty2015+Qnty2014+Qnty2013+Qnty2012andBefore)
when (Qnty2015+Qnty2014+Qnty2013)<0 and (Qnty2015+Qnty2014+Qnty2013+Qnty2012andBefore)>=0 THEN (Qnty2015+Qnty2014+Qnty2013+Qnty2012andBefore)
when (Qnty2014+Qnty2013)<0 and (Qnty2014+Qnty2013+Qnty2012andBefore)>=0 THEN (Qnty2014+Qnty2013+Qnty2012andBefore)
when Qnty2013 <0 and Qnty2013+Qnty2012andBefore >=0 then Qnty2013+Qnty2012andBefore
else Qnty2012andBefore end as Qnty2012andBefore,
case when Qnty2013<0 then 0
when (Qnty2018+Qnty2017+Qnty2016+Qnty2015+Qnty2014)<0 and (Qnty2018+Qnty2017+Qnty2016+Qnty2015+Qnty2014+Qnty2013)>=0 then (Qnty2018+Qnty2017+Qnty2016+Qnty2015+Qnty2014+Qnty2013)
when (Qnty2017+Qnty2016+Qnty2015+Qnty2014)<0 and (Qnty2017+Qnty2016+Qnty2015+Qnty2014+Qnty2013)>=0 THEN (Qnty2017+Qnty2016+Qnty2015+Qnty2014+Qnty2013)
when (Qnty2016+Qnty2015+Qnty2014)<0 and (Qnty2016+Qnty2015+Qnty2014+Qnty2013)>=0 THEN (Qnty2016+Qnty2015+Qnty2014+Qnty2013)
when (Qnty2015+Qnty2014)<0 and (Qnty2015+Qnty2014+Qnty2013)>=0 THEN (Qnty2015+Qnty2014+Qnty2013)
when (Qnty2014)<0 and (Qnty2014+Qnty2013)>=0 THEN (Qnty2014+Qnty2013)
else Qnty2013 end as Qnty2013,
case when Qnty2014<0 then 0
when (Qnty2018+Qnty2017+Qnty2016+Qnty2015)<0 and (Qnty2018+Qnty2017+Qnty2016+Qnty2015+Qnty2014)>=0 then (Qnty2018+Qnty2017+Qnty2016+Qnty2015+Qnty2014)
when (Qnty2017+Qnty2016+Qnty2015)<0 and (Qnty2017+Qnty2016+Qnty2015+Qnty2014)>=0 THEN (Qnty2017+Qnty2016+Qnty2015+Qnty2014)
when (Qnty2016+Qnty2015)<0 and (Qnty2016+Qnty2015+Qnty2014)>=0 THEN (Qnty2016+Qnty2015+Qnty2014)
when (Qnty2015)<0 and (Qnty2015+Qnty2014)>=0 THEN (Qnty2015+Qnty2014)
else Qnty2014 end as Qnty2014,
case when Qnty2015<0 then 0
when (Qnty2018+Qnty2017+Qnty2016)<0 and (Qnty2018+Qnty2017+Qnty2016+Qnty2015)>=0 then (Qnty2018+Qnty2017+Qnty2016+Qnty2015)
when (Qnty2017+Qnty2016)<0 and (Qnty2017+Qnty2016+Qnty2015)>=0 THEN (Qnty2017+Qnty2016+Qnty2015)
when (Qnty2016)<0 and (Qnty2016+Qnty2015)>=0 THEN (Qnty2016+Qnty2015)
else Qnty2015 end as Qnty2015,
case when Qnty2016<0 then 0
when (Qnty2018+Qnty2017)<0 and (Qnty2018+Qnty2017+Qnty2016)>=0 then (Qnty2018+Qnty2017+Qnty2016)
when (Qnty2017)<0 and (Qnty2017+Qnty2016)>=0 THEN ( Qnty2017+Qnty2016)
else Qnty2016 end as Qnty2016,
case when Qnty2017<0 then 0
when (Qnty2018)< 0 and (Qnty2018+Qnty2017)>=0 then (Qnty2018+Qnty2017)
else Qnty2017 end as Qnty2017,
case when Qnty2018<0 then 0 else Qnty2018 end as Qnty2018 FROM StockTable
but it gave wrong output like this
Thanks

There could be two solutions for this.
Using #Temp table as shown below
SELECT ItemName,CurrentStock,
CASE when Qnty2018<0 THEN 0 ELSE Qnty2018 END as Qnty2018,
CASE when Qnty2017<0 THEN 0 ELSE Qnty2017 END as Qnty2017,
CASE when Qnty2016<0 THEN 0 ELSE Qnty2016 END as Qnty2016,
CASE when Qnty2015<0 THEN 0 ELSE Qnty2015 END as Qnty2015,
CASE when Qnty2014<0 THEN 0 ELSE Qnty2014 END as Qnty2014,
CASE when Qnty2013<0 THEN 0 ELSE Qnty2013 END as Qnty2013,
CASE when Qnty2012andBefore<0 THEN 0 ELSE Qnty2012andBefore END as Qnty2012andBefore INTO #Temp FROM StockTable
update #Temp set Qnty2018=CurrentStock WHERE Qnty2018<>0 AND Qnty2017=0 AND Qnty2016=0 AND Qnty2015=0 AND Qnty2014=0 AND Qnty2013=0 AND Qnty2012andBefore=0
update #Temp set Qnty2017=CurrentStock-Qnty2018 WHERE Qnty2017<>0 AND Qnty2016=0 AND Qnty2015=0 AND Qnty2014=0 AND Qnty2013=0 AND Qnty2012andBefore=0
update #Temp set Qnty2016=CurrentStock-Qnty2018+Qnty2017 WHERE Qnty2016<>0 AND Qnty2015=0 AND Qnty2014=0 AND Qnty2013=0 AND Qnty2012andBefore=0
update #Temp set Qnty2015=CurrentStock-Qnty2018+Qnty2017+Qnty2016 WHERE Qnty2015<>0 AND Qnty2014=0 AND Qnty2013=0 AND Qnty2012andBefore=0
update #Temp set Qnty2014=CurrentStock-Qnty2018+Qnty2017+Qnty2016+Qnty2015 WHERE Qnty2014<>0 AND Qnty2013=0 AND Qnty2012andBefore=0
update #Temp set Qnty2013=CurrentStock-Qnty2018+Qnty2017+Qnty2016+Qnty2015+Qnty2014 WHERE Qnty2013<>0 AND Qnty2012andBefore=0
update #Temp set Qnty2012andBefore=CurrentStock-Qnty2018+Qnty2017+Qnty2016+Qnty2015+Qnty2014+Qnty2013 WHERE Qnty2012andBefore<>0
SELECT * FROM #Temp
2.Using Cursor, You could iterate on row basis and write the logic. since this is not recommended in SQL, use it only if you don't have other option.

What do you think you need the sums in the CASEs for? Given your example, it seems to me, that one CASE on each individual column has the effect you want. For the calculation of Qnty2012andBefore subtract from CurrentStock again individually applying the CASE on the summands. Like that:
SELECT ItemName,
CurrentStock,
CASE
WHEN Qnty2018 < 0
THEN 0
ELSE
Qnty2018
END Qnty2018,
...
CASE
WHEN Qnty2013 < 0
THEN 0
ELSE
Qnty2013
END Qnty2013,
CurrentStock
-
CASE
WHEN Qnty2018 < 0
THEN 0
ELSE
Qnty2018
END
...
-
CASE
WHEN Qnty2013 < 0
THEN 0
ELSE
Qnty2013
END Qnty2012andBefore
FROM StockTable;

Related

I need help defining a case statement in SQL db2-400

I am using SQL, IBM Data Studio, db2-400. I need help writing a case statement that looks for the length of a field and returns a blank if it is not equal to 14, I have tried many ways without success, below is my latest attempt.
CASE
WHEN LENGTH(TRIM(FFIUPCN) <> '14'
THEN ''
ELSE
FFIUPCN
END AS "UPC (if applicable)"
The error I get is that the token "<>" is not valid.
Main issue is that you are missing a )
CASE
WHEN LENGTH(TRIM(FFIUPCN)) <> 14
THEN ''
ELSE
FFIUPCN
END AS "UPC (if applicable)"
but you shouldn't be comparing a numeric, returned by length(), to a sring '14'. But Db2 is implicitly converting it.
For multiple conditions you can nest your case statements
Select
case when FIUPCN+FFIUPCN2 = 0
then case when FIUPCN >= value then FIUPCN + 1
else FIUPCN + 2 end
else
case when FIUPCN >= value
then case when FIUPCN <> ''
then FIUPCN + 3
else prvca1 end
else
case
when FIUPCN >= FIUPCN2 and FIUPCN3 <> 0 then FIUPCN + 4
when FIUPCN >= FIUPCNX and FIUPCNY <> 0 then FIUPCN + 5
else prvca1 end
end
end
from table

How to compare two columns in the CASE statement

I have two columns Speed_A and Speed_B.
Now I will compare both columns and will select the higher one in a new table.
Something like this:
SELECT ...
CASE
WHEN a.Speed_A > a.Speed_B THEN a.Speed_A
WHEN a.Speed_A < a.Speed_B THEN a.Speed_B
ELSE 0 --unknown
END as SpeedLimit,
How does it work?
Assuming your speeds are numerically typed you might get this as easy as:
SELECT CASE WHEN a.Speed_A>a.Speed_B THEN a.Speed_A ELSE a.Speed_B END AS SpeedLimit
[...FROM SomeWhere...]
Your ELSE will only occur, when A and B are equal, In this case it doesn't matter, which one you return.
UPDATE
columnĀ“s data type is integer. And yes there are nulls
If A is null return B, If b is null return A (works for A and B is null implicitly). Otherwise both are not null and therefore the statement above should be perfect
SELECT CASE WHEN a.Speed_A IS NULL THEN a.Speed_B
ELSE CASE WHEN a.Speed_B IS NULL THEN a.Speed_A
ELSE CASE WHEN a.Speed_A>a.Speed_B THEN a.Speed_A ELSE a.Speed_B
END
END
END AS SpeedLimit
FROM Dummy
[...FROM SomeWhere...]
You can create a inline max function that return the max between two values something like:
create function dbo.InlineMax(#val1 int, #val2 int)
returns int
as
begin
if #val1 > #val2
return #val1
return isnull(#val2,#val1)
end
and you can use it like this:
SELECT dbo.InlineMax(a.Speed_A, a.Speed_B)
FROM ....
Nested Case and Case without Column Name
select
CASE ColumnName
WHEN 'enter value on which you want to execute Than Block'
THEN
CASE ColumnName
WHEN 1 THEN 'return value or Column Name'
ELSE 'return value or Column Name in case of else'
END
WHEN 'another condition, value of column on which you want to execute then block'
THEN
CASE WHEN 'Condition etc => ColumnName > 5 or ColumnName ='abc' ' THEN 'return value or column name' ELSE 'return value or column name' END
ELSE 'return value or column name'
END as status
FROM TableName

Nested Case Then in SQL

I'm trying to do the following which involves a complex query;
1. First I try to select the column based on some logic
2. then based on the value of the selected column a value is selected
3. finally based on the previous value a logic is applied to get the final value
How can I have the result from 2 in the ELSE of the 3rd Case..Then statement ?
CASE
CASE
CASE
WHEN MDC.Network ='I' THEN INNBenefitID ELSE OONBenefitID
END
WHEN 'INNDWO' THEN CASE WHEN DWO.Description IS NOT NULL THEN DWO.Description ELSE MDC.CostShareValue END
WHEN 'OONDWO' THEN CASE WHEN DWO.Description IS NOT NULL THEN DWO.Description ELSE MDC.CostShareValue END
ELSE isnull(dbo.fn_FormatText(MDC.CostShareValue, CostShareType),'''')
END
WHEN '0%' THEN 'Covered 100%'
WHEN '$0' THEN 'Covered 100%'
ELSE ????
END
Are you looking for something like that? :
declare #value varchar(255) = (
CASE
WHEN MDC.Network ='I' THEN INNBenefitID ELSE OONBenefitID
WHEN 'INNDWO' THEN CASE WHEN DWO.Description IS NOT NULL THEN DWO.Description ELSE MDC.CostShareValue
WHEN 'OONDWO' THEN CASE WHEN DWO.Description IS NOT NULL THEN DWO.Description ELSE MDC.CostShareValue
ELSE isnull(dbo.fn_FormatText(MDC.CostShareValue, CostShareType),'''')
END
)
CASE
WHEN '0%' THEN 'Covered 100%'
WHEN '$0' THEN 'Covered 100%'
ELSE #value
END
Really, really hard to do this right without a schema or sample data. In the future consider creating a SqlFiddle for us. But one approach you might consider is using a Common Table Expression (CTE) to define an intermediary structure which you then query.
;WITH theCTE AS (SELECT
CASE
CASE
WHEN MDC.Network ='I' THEN INNBenefitID ELSE OONBenefitID
END
WHEN 'INNDWO' THEN COALESCE(DWO.Description, MDC.CostShareValue)
WHEN 'OONDWO' THEN COALESCE(DWO.Description, MDC.CostShareValue)
ELSE COALESCE(dbo.fn_FormatText(MDC.CostShareValue, CostShareType), '')
END AS foo
FROM
bar
)
SELECT
CASE
WHEN foo IN ('0%', '$0') THEN 'Covered 100%'
ELSE '' -- Do something with foo --
END AS finalColumn
FROM
theCTE

Stored procedure to return data based on sum of 3 columns

I have a stored procedure as follows:
SELECT DiscountId
,CompanyId
,Discount1
,Discount2
,Discount3
,(Discount1+Discount2+Discount3) as Total
FROM PriceDiscount
This can return one or more rows.
I also need to check the aggregate of Discount1, Discount2 and Discount3. If the sum for any of the rows is greater than 0, I want to set a column isDiscounted = true and return it also.
Please help me - how can I achieve this?
I do not want to check this in the code or create another stored procedure for this. Hence wanted to return both the results from this stored procedure.
You can use case to calculate/set the isDiscounted column.
with x as (
SELECT DiscountId
,CompanyId
,Discount1
,Discount2
,Discount3
,case when (Discount1+Discount2+Discount3) > 0 then 'True'
else 'False' end as isDiscounted
FROM PriceDiscount)
, y as (select case when isDiscounted = 'True' then count(*) end as true_count,
case when isDiscounted = 'False' then count(*) end as false_count
from x group by isDiscounted)
select case when true_count > 0 then 'True'
when falsecount > 0 and truecount = 0 then 'False' end
as final_status
from y
Edit:
with x as (
SELECT DiscountId
,CompanyId
,Discount1
,Discount2
,Discount3
,case when (Discount1+Discount2+Discount3) > 0 then 'True'
else 'False' end as isDiscounted
FROM PriceDiscount)
, y as (select sum(case when isDiscounted = 'True' then 1 else 0 end) as true_count,
sum(case when isDiscounted = 'False' then 1 else 0 end) as false_count
from x)
select case when true_count > 0 then 'True'
when false_count > 0 and true_count = 0 then 'False' end
as final_status
from y

SQL Server Check for IsNull and for Zero

I have the following:
set #SomeVariable = #AnotherVariable/isnull(#VariableEqualToZero,1) - 1
If #VariableEqualToZero is null it substitutes the 1. I need it to substitute 1 if #VariableEqualToZero = 0 as well. How do I do this?
If you're using SQL Server, you can probably use a NULLIF statement?
i.e. set the value to NULL if it's 0 then set it to 1 if it's NULL - should catch for both 0's and NULLs:
SET #SomeVariable = #AnotherVariable/ISNULL(NULLIF(#VariableEqualToZero,0),1) - 1
SET #SomeVariable = #AnotherVariable / COALESCE(
CASE
WHEN #VariableEqualToZero = 0 THEN 1
ELSE #VariableEqualToZero
END, 1) - 1
set #SomeVariable = #AnotherVariable /
(case when isnull(#VariableEqualToZero, 0) = 0 then 1 else
#VariableEqualToZero end) - 1
You use CASE
instead of
ISNULL(#VariableEqualToZero,1)
use
CASE WHEN #VariableEqualToZero IS NULL OR #VariableEqualToZero = 0 THEN 1 ELSE #VariableEqualToZero END
COALESCE and ISNULL are essentially just shortcuts for a CASE statement.
You can consult the help for the syntax of CASE.