Any other way to avoid if else condition - sql

I have a following stored procedure. I have variable #PercentCleared .
IF #PercentCleared <= 70 then I have to subtract PercentCleared-10 else use as it is. Can you please advise me the right way to do?
DECLARE #PercentCleared INT
DECLARE #TenPercent int
SET #TenPercent = 10
IF(#PercentCleared <=70)
BEGIN
SELECT
#I, dbo.tblV.VegTypeCode, dbo.tblV.VegTypeName
FROM
dbo.tblVegetationType
INNER JOIN
dbo.tblVegFormationLink ON dbo.tblV.VegTypeID = dbo.tblVegFormationLink.VegTypeID
WHERE
dbo.tblVegetationType.PercentageCleared >=(#PercentCleared - #TenPercent)
WHERE
a.VegTypeID = dbo.tblVegetationType.VegTypeID
AND dbo.tblVegetationType.VegTypeID <> (SELECT VegTypeID
FROM #EcosystemCredits eco
WHERE eco.theID = #I)
END
ELSE IF
BEGIN
SELECT
#I, dbo.tblV.VegTypeCode, dbo.tblV.VegTypeName
FROM
dbo.tblVegetationType
INNER JOIN
dbo.tblVegFormationLink ON dbo.tblV.VegTypeID = dbo.tblVegFormationLink.VegTypeID
WHERE
dbo.tblVegetationType.PercentageCleared >=#PercentCleared
WHERE
a.VegTypeID = dbo.tblVegetationType.VegTypeID
AND dbo.tblVegetationType.VegTypeID <> (SELECT VegTypeID
FROM #EcosystemCredits eco WHERE eco.theID = #I)
End

I think you can do this by using a CASE statement in the WHERE clause
SELECT #I, dbo.tblV.VegTypeCode, dbo.tblV.VegTypeName FROM dbo.tblVegetationType
INNER JOIN dbo.tblVegFormationLink
ON dbo.tblV.VegTypeID = dbo.tblVegFormationLink.VegTypeID
WHERE dbo.tblVegetationType.PercentageCleared
>= #PercentCleared
- CASE WHEN (#PercentCleared <=70) THEN #TenPercent ELSE 0 END -- change here
WHERE a.VegTypeID = dbo.tblVegetationType.VegTypeID
AND dbo.tblVegetationType.VegTypeID
<> (SELECT VegTypeID FROM #EcosystemCredits eco WHERE eco.theID = #I)

You can put the logic in the where clause.
SELECT #I, dbo.tblV.VegTypeCode, vt.VegTypeName
FROM dbo.tblVegetationType vt INNER JOIN
dbo.tblVegFormationLink vfl
ON vt.VegTypeID = vlt.VegTypeID
WHERE (vt.PercentageCleared >= #PercentCleared - (CASE WHEN #PercentCleared <= 70 THEN #TenPercent ELSE 0 END)) AND
(vt.VegTypeID <> (SELECT VegTypeID FROM #EcosystemCredits eco WHERE eco.theID = #I) );
I simplified the query by using table aliases. Also, you had two where clauses and the second was redundant.

You can achieve this without a CASE or IF statement by re-writing your SQL like this...
WHERE
(#PercentCleared <=70 AND dbo.tblVegetationType.PercentageCleared >=(#PercentCleared - #TenPercent))
OR
(#PercentCleared > 70 AND dbo.tblVegetationType.PercentageCleared >= #PercentCleared)
Hope it helps not only in this situation but many similar situtations.

Related

How to update table based on the values in other columns

Here is a sample below, I want to update AvailableAmt column based on the amount entered on UI.
Requirement
Update the value from the last row to the first row,
If entered 500 on UI, then the table will be like
If entered 1000 on UI, then the table will be like
Thank you for your help in advance !
Can't test it on a Sybase somewhere.
But in theory something like this might work:
DECLARE #Group VARCHAR(8) = 'a';
DECLARE #Amount INT = 1100;
UPDATE t
SET t.AvailableAmt =
CASE
WHEN q.PrevRemain > 0 AND t.AvailableAmt <= q.PrevRemain THEN 0
WHEN q.PrevRemain > 0 THEN t.AvailableAmt - q.PrevRemain
ELSE t.AvailableAmt
END
FROM YourTable t
JOIN
(
select [Group], [Row],
#Amount-(SUM(AvailableAmt) OVER (PARTITION BY [Group] ORDER BY AvailableAmt, [Row] desc) - AvailableAmt) as PrevRemain
from YourTable
where AvailableAmt > 0
and [Group] = #Group
) AS q
ON (q.[Group] = t.[Group] and q.[Row] = t.[Row]);
For a Sybase flavor that doesn't support the window function of SUM, something like this might work.
DECLARE #Group VARCHAR(8) = 'a';
DECLARE #Amount INT = 1200;
UPDATE t
SET t.AvailableAmt =
CASE
WHEN q.PrevRemain > 0 AND t.AvailableAmt <= q.PrevRemain THEN 0
WHEN q.PrevRemain > 0 THEN t.AvailableAmt - q.PrevRemain
ELSE t.AvailableAmt
END
FROM YourTable t
JOIN
(
select t1.[Group], t1.[Row],
#Amount - (SUM(t2.AvailableAmt)-t1.AvailableAmt) as PrevRemain
from YourTable t1
left join YourTable t2 on (t2.[Group] = t1.[Group] and t2.AvailableAmt <= t1.AvailableAmt and t2.[Row] >= t1.[Row])
where t1.AvailableAmt > 0
and t1.[Group] = #Group
group by t1.[Group], t1.[Row], t1.AvailableAmt
) AS q
ON (q.[Group] = t.[Group] and q.[Row] = t.[Row]);

SQL: LEFT OUTER JOIN not returning any rows

I have a query that is using a LEFT OUTER JOIN to merge 2 data sets. I know both data sets should return data because I ran the superquery and the subquery separately. For some reason, the query is returning zero results. Anyone know why?
Left data:
item FG_lots
447845 E2211
Right data:
candy_lot_check candy_item
L2211 835116
Intended result:
item FG_lots candy_lot_check candy_item
447845 E2211 null null
The result from my broken query (no results):
item FG_lots candy_lot_check candy_item
The query:
--Initialization--
DECLARE #Item NVARCHAR(30) = '447845'
DECLARE #Date datetime = '6/13/2016'
SET DATEFIRST 1;
DECLARE #client NVARCHAR(20)
SET #client = (SELECT i.Uf_ClientName FROM item AS i WHERE i.item = #Item)
DECLARE #count integer
--Query--
SET #count = (CASE
WHEN (#client = 'A' OR #client = 'B')
THEN 4
WHEN #client = 'C'
THEN 3
WHEN #client = 'D'
THEN 5
ELSE
4
END)
SELECT DISTINCT
t.item,
LEFT(t.lot,#count) AS FG_lots,
(CASE
WHEN candylot.candy_lots IS NULL
THEN 'NO MATCH'
ELSE candylot.candy_lots
END) AS candy_lot_check,
(CASE
WHEN candylot.item IS NULL
THEN 'NO MATCH'
ELSE candylot.item
END) AS candy_item
FROM
ISW_LPTrans AS t
LEFT OUTER JOIN
(
SELECT
t.item,
LEFT(t.lot,#count) AS candy_lots,
t.ref_num AS job,
t.ref_line_suf AS suffix
FROM
ISW_LPTrans AS t
INNER JOIN item AS i on i.item = t.item
WHERE
i.product_code = 'RM-Candy' AND
t.trans_date = #Date AND
t.trans_type = 'I' AND
t.ref_num IN
(
SELECT TOP 1
j.job
FROM
job AS j
WHERE
j.item = #Item AND
j.job_date = (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, #Date), #Date))
ORDER BY
j.job
)
AND t.ref_line_suf IN
(
SELECT TOP 1
j.suffix
FROM
job AS j
WHERE
j.item = #Item AND
j.job_date = (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, #Date), #Date))
)
GROUP BY
t.item,
t.lot,
t.ref_num,
t.ref_line_suf
) AS candylot ON LEFT(t.lot, #count) = candylot.candy_lots
WHERE
t.ref_num = candylot.job AND
t.ref_line_suf = candylot.suffix AND
t.trans_type = 'F' AND
t.item = #Item AND
t.trans_date = #Date
You've got two 't' aliases, try altering it.
It seems you could rewrite it to make it more readable (joinwise, not indentwise), it could be that something's not right in the logic as well

fastest update with sql

I have the following query that it took days to be executed
DECLARE #cnt BIGINT
SET #cnt = 1
WHILE #cnt * 1000 < 92746339
BEGIN
UPDATE TOP (1000) [dbo].[Vente]
SET Promo =
CASE
WHEN [Code Article] IN (
SELECT [Code Article]
FROM [Promotion]
WHERE datecol BETWEEN [Date Debut Promo] AND [Date Fin Promo]
)
THEN 1
ELSE 0
END
WHERE promo IS NULL
PRINT '#cnt: ' + CONVERT(VARCHAR, #cnt)
SET #cnt = #cnt + 1
END
Number of rows : Vente = 92 millions and promotion =419187
The execution plan :
How to make it faster ?
Why not using a JOIN instead IN clause ?
UPDATE v
SET v.Promo = CASE
WHEN p.[Code Article] IS NOT NULL THEN 1
ELSE 0
END
FROM [dbo].[Vente] v
LEFT JOIN [Promotion] p
ON v.[Code Article] = p.[Code Article]
AND (datecol between [Date Debut Promo] AND [Date Fin Promo])
WHERE v.Promo IS NULL;
How many rows in your tables ?

Right way to subtract in a stored procedure

I have the following query in my stored procedure
DECLARE #I INT
DECLARE #TenPercent int
DECLARE #RowsCount int
SET #TenPercent =10
SET #I = 1
SELECT
#I, dbo.tblVegetationType.VegTypeCode, dbo.tblVegetationType.VegTypeName
FROM
dbo.tblVegetationType
INNER JOIN
dbo.tblVegTypeVegFormationLink ON dbo.tblVegetationType.VegTypeID = dbo.tblVegTypeVegFormationLink.VegTypeID
INNER JOIN
tblCMAVegTypeLink ON dbo.tblVegetationType.VegTypeID = dbo.tblCMAVegTypeLink.VegTypeID
WHERE
dbo.tblVegetationType.PercentageCleared >= (#PercentCleared - #TenPercent)
AND dbo.tblVegTypeVegFormationLink.VegetationFormationID = #VegetationFormationID
AND dbo.tblCMAVegTypeLink.CMAID = #CMAID
I have following condition
dbo.tblVegetationType.PercentageCleared >= (#PercentCleared - #TenPercent)
What I am trying to do here: if PercentCleared is 60% then I want to query to pick the list from 50 %.
So I just add the SET #TenPercent = 10 and subtract from the condition.
Is that a right way to do?
Another way of writing the query can be:
SELECT #I,
VT.VegTypeCode,
VT.VegTypeName
FROM dbo.tblVegetationType VT
INNER JOIN dbo.tblVegTypeVegFormationLink VTVF
ON VT.VegTypeID = VTVF.VegTypeID
INNER JOIN tblCMAVegTypeLink CVT
ON VT.VegTypeID = CVT.VegTypeID
WHERE 1= case when #PercentCleared >= 60 and VT.PercentageCleared <= 50 then 1
-- you can add condition when #PercentCleared < 60 then what values of
-- VT.PercentageCleared are to be considered
when #PercentCleared < 60 and VT.PercentageCleared <= 50 then 1
end
AND VTVF.VegetationFormationID = #VegetationFormationID
AND CVT.CMAID = #CMAID

How to update records based on sum of a field then use the sum to calc a new value in sql

Below is what I'm trying to do with by iterating through the records.
I would like to have a more elegant solution if possible since I'm sure this is not the best way to do it in sql.
set #counter = 1
declare #totalhrs dec(9,3), #lastemp char(7), #othrs dec(9,3)
while #counter <= #maxrecs
begin
if exists(select emp_num from #tt_trans where id = #counter)
begin
set #nhrs = 0
set #othrs = 0
select #empnum = emp_num, #nhrs = n_hrs, #othrs = ot_hrs
from #tt_trans
where id = #counter
if #empnum = #lastemp
begin
set #totalhrs = #totalhrs + #nhrs
if #totalhrs > 40
begin
set #othrs = #othrs + #totalhrs - 40
set #nhrs = #nhrs - (#totalhrs - 40)
set #totalhrs = 40
end
end
else
begin
set #totalhrs = #nhrs
set #lastemp = #empnum
end
update #tt_trans
set n_hrs = #nhrs,
ot_hrs = #othrs
where id = #counter and can_have_ot = 1
end
set #counter = #counter + 1
end
Thx
This is close to what you want, but will need to be tuned a bit once you answer my comment about what you are really trying to achieve.
update #tt_trans
set n_hrs = CASE WHEN T2.totHrs>40
THEN 40
ELSE T2.totHrs END,
ot_hrs= CASE WHEN T2.totHrs>40
THEN T2.totHrs-40
ELSE 0 END
FROM #tt_trans trans T1
INNER JOIN (SELECT SUM(#nhrs) totHrs, EmpNum
FROM #tt_trans
WHERE can_have_ot=1
GROUP BY EmpNum) T2 ON (T1.EmpNum=T2.EmpNum)
WHERE can_have_ot = 1
It looks like you are iterating because you have to keep track of the total hours for a given employee across multiple records. You can instead use an interior select to sum the hours for each employee, and join that select to your #tt_trans table. Write your update from that join, and put your logic in CASE statements for the updating columns.
update #tt_trans
set n_hrs = case
when t2.totHrs > 40
then n_hrs - (t2.totHrs -40)
else n_hrs
end,
ot_hrs = case
when t2.totHrs > 40
then ot_hrs + (t2.totHrs -40)
else ot_hrs
end
from #tt_trans t1
join (select sum (n_hrs) as totHrs, emp_num from #tt_trans where can_have_ot =1 group by emp_num) t2 on t1.emp_num = t2.emp_num where t1.post_date = (select max(post_date)from #tt_trans where emp_num = t1.emp_num)
Basically I took the modified the hours of the last date in the period and adjusted accoringly. Thanks to the both of you who responded. Both replies led me to mine.