Select Case determines Exit code or run Update statement - sql-server

Trying to get the select case statement to control whether nothing happens or a table is updated based on the sum of three fields from two different tables. One of the tables is a temp table (#tempGLsum). This holds the id field and the sum amount. The "amt" field in the tblPcardGL table should never go below 0 (zero). If it would, then the flow should stop. If it will still be > 0, then the next block of code would run, which updates the tblPcardGL table.
Any assistance would be appriciated!
Thanks
declare #glID int
create table #tempGLsum
(glID int, sumAmt decimal(18,2))
insert into #tempGLsum
(glID, sumAmt)
select tblPcardReclass.glID,
sum(tblPcardReclass.reclassAmt)
from tblPcardReclass
where tblPcardReclass.glID = #glID
group by tblPcardReclass.glID
select
case when (tblPcardGL.orgAmt - tblPcardGL.amt - #tempGLsum.sumAmt) < 0
then 'stop here and let the user know it's below zero'
else
'run the code_below'
end
from tblPcardGL
left outer join #tempGLsum ON
tblPcardGL.glID = #tempGLsum.glID
where tblPcardGL.glID = #glID
-- code_below
update tblPcardGL
set amt =
(
select
case (select COUNT(*) as numRecs from #tempGLsum)
when 0 then
tblPcardGL.orgAmt
else
(tblPcardGL.orgAmt - #tempGLsum.sumAmt)
end
)
from tblPcardGL
left outer join #tempGLsum ON
tblPcardGL.glID = #tempGLsum.glID
where tblPcardGL.glID = #glID

You can't really do what you want with a case statement. You just have to do it in two steps:
First run the select with a where clause to show the user all the problems:
select tblPcardGL.*, 'Below Zero!' Error
from tblPcardGL
left outer join #tempGLsum ON
tblPcardGL.glID = #tempGLsum.glID
where tblPcardGL.glID = #glID
and (tblPcardGL.orgAmt - tblPcardGL.amt - #tempGLsum.sumAmt) < 0
Then do the update with another where clause:
update tblPcardGL
set amt =
(
select
case (select COUNT(*) as numRecs from #tempGLsum)
when 0 then
tblPcardGL.orgAmt
else
(tblPcardGL.orgAmt - #tempGLsum.sumAmt)
end
)
from tblPcardGL
left outer join #tempGLsum ON
tblPcardGL.glID = #tempGLsum.glID
where tblPcardGL.glID = #glID
and (tblPcardGL.orgAmt - tblPcardGL.amt - #tempGLsum.sumAmt) >= 0
You should consider wrapping all your #tempGLsum.sumAmt fields in isnull(#tempGLsum.sumAmt,0) because you used a left join so that column might evaluate to null, which will make any expression it is in become null.

Related

How to store result of CASE expression into (temporary/not) variable and use it to calculate concurrently inside the same SELECT statement

In other programing language we can do this:
A = 5
B = A + 7
But anyone know how to do this in SQL, something like this:
SELECT
(CASE WHEN (CASE WHEN t.[Id] IS NULL THEN 0 ELSE 1 END) = 1 THEN a.[123]
ELSE a.[432] END) AS 'Points',
#'Points' + 5 AS 'FinalPoints' ---Does any way to do this
FROM DeliveryOrder AS do
LEFT JOIN Transaction AS t ON t.DOId = do.Id
LEFT JOIN Amount AS a ON do.Id = a.Id
I really appreciate if anyone have any ideas how to do this
P/S: Since I can use SubQuery to simulate this but in my case, each columns have many CASE..WHEN expression and inside it have Case expression too so after all when combine all of them into single SubQuery make thing so terrible to read :(
You can't do exactly what you want. Aliases defined in the select clause cannot be reused in the same clause, so you need to either repeat the expression, or use a derived table (subquery or cte).
Your nested case seems overkill - I think that your code can be simplified as:
SELECT
CASE WHEN t.[Id] IS NULL THEN 10 ELSE 5 END AS points,
CASE WHEN t.[Id] IS NULL THEN 15 ELSE 10 END finalPoints
FROM DeliveryOrder AS do
LEFT JOIN Transaction AS t ON t.DOId = do.Id
Or using a subquery:
SELECT
points,
points + 5 finalPoints
FROM (
SELECT CASE WHEN t.[Id] IS NULL THEN 10 ELSE 5 END AS points
FROM DeliveryOrder AS do
LEFT JOIN Transaction AS t ON t.DOId = do.Id
) t
One another way can be to use cross apply,
SELECT
p.Points
,p.Points+5 'FinalPoints'
FROM DeliveryOrder AS do
LEFT JOIN dbo.[Transaction] AS t ON t.DOId = do.Id
cross apply (
select CASE WHEN T.Id IS NOT NULL THEN 5 ELSE 10 END AS 'Points'
) p
Using a SubQuery
SELECT Points, Points + 5 AS FinalPoints
FROM
(
SELECT CASE WHEN (CASE WHEN T.Id IS NULL THEN 0 ELSE 1 END) = 1 THEN 5 ELSE 10 END Points
FROM DeliveryOrder AS DO
LEFT JOIN [Transaction] AS T ON DO.Id = T.DOId
) T
You could get ride of the nested CASE expression and directly use
CASE WHEN T.Id IS NOT NULL THEN 5 ELSE 10 END Points

SQL Case Statement with SELECT inside INNER JOIN. Error of multi-part could not be bound

I am writing an INNER JOIN that added fields like CompanyId etc..
But in my CASE inside the INNER JOIN I am getting an error after the WHERE
The error say on the IR.MyId and ICB1.MyId
"multi-part identifier could not be bound"
My intention for this query is to add a CASE inside the INNER JOIN.
So the first column is A.CompanyId. The second column will be the CASE statement to check if the ID exists in another table. If not, it will do another SELECT statement, ELSE just MyID.
But I get an error on the SELECT COUNT(*) inside the CASE WHEN.
Any help is appreciated. Thanks.
INNER JOIN
(SELECT DISTINCT
A.CompanyId,
CASE
WHEN (SELECT count(*)
FROM Table1 IBC1
WHERE IR.MyId = ICB1.MyId) == 0
THEN 1
ELSE 0
END
FROM
cmp.CompanyNews A) E ON NP.CompanyId = E.CompanyId
I don't have your full query, but if it's viable I'd take the following approach to this:
...
CASE
WHEN ICB1_ID.ID IS NULL
THEN 1
ELSE 0
END [ColumnName]
FROM
...
INNER JOIN
(
SELECT DISTINCT A.CompanyId
FROM cmp.CompanyNews A
) E
ON NP.CompanyId = E.CompanyId
OUTER APPLY
(
SELECT TOP 1 ICB1.MyID ID
FROM Table1 IBC1
WHERE ICB1.MyId = IR.MyId
) ICB1_ID

How to Update a Table for a same matching row

I have a Table TBLmaterial where current Stock is defined for particular Materailid .
And i have a tbldrawingtable where required quantity is listed for a particular material . It should update present column as required quantity and status to Available if current stock is available .
for example : Materialid =2 have 4 requiredQTY in 102=drawid and 2 requiredQTY in 105=drawid . IT should update because total 6 CurrentStock is present for the material id 2.
As per latest update of code .below result will displayed which is correct.
If i check for material id 1 once again . it should update drawing id 107 for the material id 1 to Not available because no more current stock is available to update .
my code below :
Alter procedure dbo.FetchInto(#Matid int)
as
begin
declare #CurrentStock int
declare #required Int
declare #present int
select #CurrentStock=M.CurrentStock
from Tblmaterial M
inner join
TblDrawingTable D
on M.Matid=D.Matid
where M.Matid =#Matid
select top 1 #required=d.RequiredQty from Tblmaterial M
inner join
TblDrawingTable D
on M.Matid=D.Matid
where m.Matid =#Matid
select top 1 #present=(m.CurrentStock-isnull(d.Present,0))
from TblDrawingTable D
inner join
Tblmaterial M
on D.Matid=m.Matid
where D.Matid=#Matid
if exists(select 1 from TblDrawingTable where Matid=#Matid and Present is
null)
begin
if (#required<=#CurrentStock and #present >0)
UPDATE TblDrawingTable SET present=#required,status='Available' where Drawid
= (select top 1 Drawid from TblDrawingTable where
Matid=#Matid) and Matid=#Matid
end
else if(#present=#required)
update TblDrawingTable SET status='Not Available',Present=#present where
Drawid <> (select top 1 Drawid from TblDrawingTable where
Matid=#Matid) and Matid=#Matid
if exists(select 1 from TblDrawingTable where Matid=#Matid and Present is
null)
begin
if (#required<=#CurrentStock and #present>0)
UPDATE TblDrawingTable SET present=(#CurrentStock-
#required),status='Available' where Drawid <> (select top 1 Drawid from
TblDrawingTable where
Matid=#Matid) and Matid=#Matid
end
else if(#present=#required)
update TblDrawingTable SET status='Not Available',Present=#present where
Matid=#Matid
end
I didn't check your code, but if I understood correctly you need to:
collect all the existing material from drawings
compare with in stock
update consequentially
I would work with CTE
Edit:
I add some partial code that can be used to solve the issue
;WITH ExistingMat AS (
SELECT Matid, SUM(RequiredQty) ExistingQty
FROM TBLDrawing
GROUP BY Matid
),
CompareMat AS (
SELECT m.*, ISNULL(e.ExistingQty, 0) ExistingQty
FROM TBLMaterial m LEFT OUTER JOIN ExistingMat e ON m.Matid = e.Matid
)
SELECT d.*, c.CurrentStock, c.ExistingQty, CASE WHEN c.ExistingQty <= c.CurrentStock THEN 'Available' ELSE 'Not Available' END UpdStatus, ExistingQty UpdPresent
FROM TBLDrawing d INNER JOIN CompareMat c ON d.Matid = c.Matid

Compare values in SQL, if match return true else false

I have an application which allows users to contact one another, look at it as a dating site. I'm adding some security around the contact part, whereby the user can limit who can contact him/her either by setting a certain age / height range and gender.
Say for example I click on UserId-2 profiles, this will then make a call to the DB, pass in the ID or the chosen profile and also pass my ID in to, I then call my function passing in both of these values. Function is as follows:
ALTER FUNCTION [dbo].[Can_User_Contact]
(
#UserId1 int = 2, -- UserId
#UserId2 int = 1 -- Requested by Id
)
RETURNS bit
AS
BEGIN
RETURN (
SELECT CASE WHEN up.Id IS NULL THEN 0 ELSE 1 END AS does_data_match
FROM [user].User_Settings us
LEFT OUTER JOIN [User].[User_Profile] up ON us.UserId = #UserId1
LEFT OUTER JOIN [User].[User_Details] d ON up.Id = d.UserId
AND up.id = #UserId2
AND d.Height between ISNULL(us.HeightFrom, d.height) and ISNULL(us.HeightTo, d.Height)
AND up.Age between ISNULL(us.AgeFrom, up.age) and ISNULL(us.AgeTo, up.Age)
AND up.Gender = ISNULL(us.Gender, up.Gender)
)
END
Inside this function I compare the values UserId-2 has saved in the settings table to the values of my self by joining on the user profile table and the user details table, the problem with this is every time I execute it I get the following message:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I have two records in the setting table as shown here:
I'm only interested in the second record.
Can someone shed some light into what I might be doing wrong?
#UserId1 is the profile Id,
#UserId2 is the user who's requesting to view it.
Bare in mind, there may not be a record in the settings table for #UserId1 as well as this functionality is optional.
Assuming you have a single entry for user_setting,User_Profile and User_Details for each user, this should work.
Based on your result, it looks like a problem with your join conditions. Some of your join conditions should ideally be part of WHERE clause like up.id = #UserId2.
Query
SELECT TOP 1 CASE WHEN us.UserId IS NULL THEN 0 ELSE 1 END AS does_data_match
FROM [User].[User_Profile] up
INNER JOIN [User].[User_Details] d ON up.Id = d.UserId
LEFT OUTER JOIN [user].User_Settings us
ON us.UserId = #UserId1
AND d.Height between ISNULL(us.HeightFrom, d.height) and ISNULL(us.HeightTo, d.Height)
AND up.Age between ISNULL(us.AgeFrom, up.age) and ISNULL(us.AgeTo, up.Age)
AND up.Gender = ISNULL(us.Gender, up.Gender)
WHERE up.id = #UserId2
ORDER BY up.id ASC
Note: If assumption is true, then ideally TOP is not required. Just added it for additional safety
multiple rows are being returned by SELECT query.
Since you are interested in a single value use like this:
ALTER FUNCTION [dbo].[Can_User_Contact]
(
#UserId1 int = 2, -- UserId
#UserId2 int = 1 -- Requested by Id
)
RETURNS bit
AS
BEGIN
RETURN
(
SELECT CASE WHEN EXISTS
(
SELECT 1 FROM [user].User_Settings us1
LEFT OUTER JOIN [User].[User_Profile] up ON up.id = #UserId2
LEFT OUTER JOIN [User].[User_Details] d ON up.Id = d.UserId
LEFT OUTER JOIN [user].[User_Settings] us2 ON us2.UserId=up.id
WHERE
d.Height between ISNULL(us1.HeightFrom, d.height) and ISNULL(us1.HeightTo, d.Height)
AND us2.Age between ISNULL(us1.AgeFrom, up.age) and ISNULL(us1.AgeTo, up.Age)
AND us1.Gender = ISNULL(us2.Gender, up.Gender)
AND up.Id IS NOT NULL
AND us1.UserId = #UserId1
) THEN 1 ELSE 0 END AS does_data_match
END

SQL Server query that contains a derived table

I have created a select query that contains one regular table and two derived tables (subqueries). The derived tables are both joined with the regular table with left joins. The regular table contains over 7000 rows, but the query output is around 3000 rows. It has to be equal to the number of records in the regular table. What is my mistake?
SELECT T0.[ItemCode],
T0.[ItemName],
CASE T0.[PrcrmntMtd] WHEN 'B' THEN 'Inkoop' ELSE 'Productie' END AS Verwervingsmethode,
T0.[OnHand] AS Voorraad_excl_grondstof_reeds_verwerkt,
T1.[Reeds_geproduceerd] AS Grondstof_reeds_verwerkt,
CASE WHEN T1.[Reeds_geproduceerd] IS NULL
THEN T0.[OnHand]
ELSE T0.[OnHand]-T1.[Reeds_geproduceerd]
END AS Voorraad_incl_grondstof_reeds_verwerkt,
T2.[Nog_te_produceren] AS Geplande_productie_halffabrikaat_eindproduct,
T1.[Nog_te_produceren] AS Gereserveerd_voor_productie_grondstof_halffabrikaat,
CASE WHEN T1.[Reeds_geproduceerd] IS NULL
THEN (T0.[OnHand]/T2.[Nog_te_produceren])*30
ELSE ((T0.[OnHand]-T1.[Reeds_geproduceerd])/T2.[Nog_te_produceren])*30
END AS Dagen_voorraad_halffabrikaat_eindproduct,
CASE WHEN T1.[Reeds_geproduceerd] IS NULL
THEN (T0.[OnHand]/T1.[Nog_te_produceren])*30
ELSE ((T0.[OnHand]-T1.[Reeds_geproduceerd])/T1.[Nog_te_produceren])*30
END AS Dagen_voorraad_grondstof_halffabrikaat
FROM OITM T0
LEFT JOIN (
SELECT T1.[ItemCode],
SUM(T0.[PlannedQty]*T1.[BaseQty]) AS Geplande_productie,
CASE WHEN SUM(T0.CmpltQty) IS NULL THEN SUM(T0.[PlannedQty]*T1.[BaseQty]) ELSE SUM(T0. [CmpltQty]*T1.[BaseQty]) END AS Reeds_geproduceerd,
CASE WHEN SUM(T0.CmpltQty) IS NULL THEN SUM(T0.[PlannedQty]*T1.[BaseQty]) ELSE SUM(T0.[PlannedQty]*T1.[BaseQty])-SUM(T0.[CmpltQty]*T1.[BaseQty]) END AS Nog_te_produceren
FROM OWOR T0
INNER JOIN WOR1 T1 ON T0.DocEntry = T1.DocEntry
WHERE T0.DueDate <= getdate()+30
AND (T0.[Status] LIKE 'p'
OR T0.[Status] LIKE 'r')
GROUP BY T1.[ItemCode]
) AS T1
ON T0.ItemCode = T1.ItemCode
LEFT JOIN (
SELECT T0.[ItemCode],
SUM(T0.[PlannedQty]) AS Geplande_productie,
SUM(T0.[CmpltQty]) AS Reeds_geproduceerd,
SUM(T0.[PlannedQty])-SUM(T0.[CmpltQty]) AS Nog_te_produceren
FROM OWOR T0
INNER JOIN WOR1 T1 ON T0.DocEntry = T1.DocEntry
WHERE T0.DueDate <= getdate()+30
AND (T0.[Status] LIKE 'p'
OR T0.[Status] LIKE 'r')
GROUP BY T0.[ItemCode]
) AS T2
ON T0.ItemCode = T2.ItemCode
I mentioned all the where clauses. If I red the linked page correct, that cant be the problem.
I also changed the table names and column names of the derived tables. Now all table names and column names are unique.
But still the same problem. When i delete the last two case statements in select, i do get all the output lines, but i dont see any problems in these case statements.
SELECT T0.[ItemCode],
T0.[ItemName],
CASE T0.[PrcrmntMtd] WHEN 'B' THEN 'Inkoop' ELSE 'Productie' END AS Verwervingsmethode,
T0.[OnHand] AS Voorraad_excl_grondstof_reeds_verwerkt,
T3.[Reeds_geproduceerd_grond] AS Grondstof_reeds_verwerkt,
CASE WHEN T3.[Reeds_geproduceerd_grond] IS NULL
THEN T0.[OnHand]
ELSE T0.[OnHand]-T3.[Reeds_geproduceerd_grond]
END AS Voorraad_incl_grondstof_reeds_verwerkt,
T6.[Nog_te_produceren_eind] AS Geplande_productie_halffabrikaat_eindproduct,
T3.[Nog_te_produceren_grond] AS Gereserveerd_voor_productie_grondstof_halffabrikaat,
CASE WHEN T3.[Reeds_geproduceerd_grond] IS NULL
THEN 30*(T0.[OnHand]/T6.[Nog_te_produceren_eind])
ELSE 30*((T0.[OnHand]-T3.[Reeds_geproduceerd_grond])/T6.[Nog_te_produceren_eind])
END AS Dagen_voorraad_halffabrikaat_eindproduct,
CASE WHEN T3.[Reeds_geproduceerd_grond] IS NULL
THEN 30*(T0.[OnHand]/T3.[Nog_te_produceren_grond])
ELSE 30*((T0.[OnHand]-T3.[Reeds_geproduceerd_grond])/T3.[Nog_te_produceren_grond])
END AS Dagen_voorraad_grondstof_halffabrikaat
FROM OITM T0
LEFT JOIN (
SELECT T2.[ItemCode] AS ItemCode_grond,
SUM(T1.[PlannedQty]*T2.[BaseQty]) AS Geplande_productie_grond,
CASE WHEN SUM(T1.CmpltQty) IS NULL
THEN SUM(T1.[PlannedQty]*T2.[BaseQty])
ELSE SUM(T1.[CmpltQty]*T2.[BaseQty])
END AS Reeds_geproduceerd_grond,
CASE WHEN SUM(T1.CmpltQty) IS NULL
THEN SUM(T1.[PlannedQty]*T2.[BaseQty])
ELSE SUM(T1.[PlannedQty]*T2.[BaseQty])-SUM(T1.[CmpltQty]*T2.[BaseQty])
END AS Nog_te_produceren_grond
FROM OWOR T1
INNER JOIN WOR1 T2 ON T1.DocEntry = T2.DocEntry
WHERE T1.DueDate <= getdate()+30
AND (T1.[Status] LIKE 'p'
OR T1.[Status] LIKE 'r')
GROUP BY T2.[ItemCode]
) AS T3
ON T0.ItemCode = T3.ItemCode_grond
LEFT JOIN (
SELECT T4.[ItemCode] AS ItemCode_eind,
SUM(T4.[PlannedQty]) AS Geplande_productie_eind,
SUM(T4.[CmpltQty]) AS Reeds_geproduceerd_eind,
SUM(T4.[PlannedQty])-SUM(T4.[CmpltQty]) AS Nog_te_produceren_eind
FROM OWOR T4
INNER JOIN WOR1 T5 ON T4.DocEntry = T5.DocEntry
WHERE T4.DueDate <= getdate()+30
AND (T4.[Status] LIKE 'p'
OR T4.[Status] LIKE 'r')
GROUP BY T4.[ItemCode]
) AS T6
ON T0.ItemCode = T6.ItemCode_eind

Resources