case statement to select multiple rows at once - sql-server

I am looking to pull the same columns from two different tables, based on a conditional argument.
So i have stumbled upon the CASE statement which I have not used much before. I have found this will work for me in this mannor, but I would like it if I could do one CASE statement and then select the columns i need, rather then doing it per column.
Here is an example of what I have and working, just seems a little redundant.
SELECT TOP(10)
u1.userid as userid,
version = CASE
WHEN (u2.userid IS NULL OR u1.enabled = 0)
THEN 3
ELSE 4
END,
nameOrg = CASE
WHEN (u2.userid IS NULL OR u1.enabled = 0)
THEN CONVERT(NVARCHAR, u1.title)
ELSE CONVERT(NVARCHAR, u2.title)
END,
nameContact = CASE
WHEN (u2.userid IS NULL OR u1.enabled = 0)
THEN CONVERT(NVARCHAR, u1.contact)
ELSE CONVERT(NVARCHAR, u2.contact)
END,
pltName = CASE
WHEN (u2.userid IS NULL OR u1.enabled = 0)
THEN p1.name
ELSE p2.name
END
FROM
usr1 u1
LEFT OUTER JOIN
usr2 u2
ON u1.userid = u2.userid
LEFT OUTER JOIN
plt2 p2
ON u2.pltid = p2.pltid
LEFT OUTER JOIN
plt1 p1
ON u1.pltid = p1.pltid
Any advise?
Edit mov 7, 5:22: added join to plt table and pltName case, to add to required functionality.

In the case that there is no matching userid in the usr2 dataset, all the fields will be null. You could use the isnull function to make it a little less verbose as I have done below, but you won't get down to a single line.
SELECT TOP(10)
u1.userid as userid
,version = CASE
WHEN (u2.userid IS NULL OR u1.enabled = 0)
THEN 3
ELSE 4
END
,CONVERT(NVARCHAR,isnull(u2.title,u1.title)) nameOrg
,CONVERT(NVARCHAR,isnull(u2.contact,u1.contact)) nameContact
FROM
usr1 u1
LEFT OUTER JOIN
usr2 u2
ON u1.userid = u2.userid

Related

CASE Statement causing execute time to sky rocket

There are two distinct databases where I work. In creating a report (utilizing TSQL) to share between departments, it was requested to have a field to show the information from the primary database (information kept on the college's database) had also been inputted into a second database (that a specific department uses for information communications with federal program). Without checking the second database with the case statement the query for the rest of the information takes less than a second. With the case statement (in which CTEs where created to conduct the check), it has run for 15 minutes and not finished before I manually ended the execution. Here is the code (CASE statement currently commented out):
With POWERFAIDS_CHECK as
(
Select distinct NAME_MASTER.ID_NUM,
(CAST (NAME_MASTER.ID_NUM as VARCHAR) + CAST (EX_SCHOLARSHIP_RECIPIENTS.AID_ELEMENT as VARCHAR) ) as CHECK_ID
From NAME_MASTER
JOIN EX_SCHOLARSHIP_RECIPIENTS on NAME_MASTER.ID_NUM = EX_SCHOLARSHIP_RECIPIENTS.ID_NUM
JOIN SCHOLARSHIP on EX_SCHOLARSHIP_RECIPIENTS.AID_ELEMENT = SCHOLARSHIP.AID_ELEMENT
JOIN PF_FUND_CDE_MSTR on EX_SCHOLARSHIP_RECIPIENTS.AID_ELEMENT = PF_FUND_CDE_MSTR.RPT_CATEGORY
JOIN PowerFAIDS_Production.dbo.student on NAME_MASTER.ID_NUM = PowerFAIDS_Production.dbo.student.alternate_id
JOIN PowerFAIDS_Production.dbo.funds on PF_FUND_CDE_MSTR.FUND_CDE = PowerFAIDS_Production.dbo.funds.fund_ledger_number
JOIN PowerFAIDS_Production.dbo.stu_award_year on PowerFAIDS_Production.dbo.student.student_token = PowerFAIDS_Production.dbo.stu_award_year.student_token
JOIN PowerFAIDS_Production.dbo.stu_award on PowerFAIDS_Production.dbo.stu_award_year.stu_award_year_token = PowerFAIDS_Production.dbo.stu_award.stu_award_year_token
JOIN YEAR_TERM_TABLE on (YEAR_TERM_TABLE.YR_CDE = EX_SCHOLARSHIP_RECIPIENTS.YR_CDE) and (YEAR_TERM_TABLE.TRM_CDE = EX_SCHOLARSHIP_RECIPIENTS.TRM_CDE)
Where EX_SCHOLARSHIP_RECIPIENTS.YR_CDE = '2021'
and EX_SCHOLARSHIP_RECIPIENTS.TRM_CDE = 'FA'
and YEAR_TERM_TABLE.TRM_BEGIN_DTE = PowerFAIDS_Production.dbo.stu_award.award_period_begin_dt
and EX_SCHOLARSHIP_RECIPIENTS.AWARD_AMT = PowerFAIDS_Production.dbo.stu_award.actual_amt
and stu_award.status = 'A'
),
AWARDED_SCHOLARSHIPS as
(Select distinct NAME_MASTER.ID_NUM, (NAME_MASTER.FIRST_NAME + ' ' + NAME_MASTER.LAST_NAME) as STUDENT_NAME,
SCHOLARSHIP.DESCRIPTION,
Format (EX_SCHOLARSHIP_RECIPIENTS.AWARD_AMT, 'C','en-us') as AWARD_AMT,
EX_SCHOLARSHIP_RECIPIENTS.COMMENTS,
YR_DESC, TRM_DESC, EX_SCHOLARSHIP_RECIPIENTS.AID_ELEMENT,
(CAST (NAME_MASTER.ID_NUM as VARCHAR) + CAST (EX_SCHOLARSHIP_RECIPIENTS.AID_ELEMENT as VARCHAR) ) as CHECK_ID,
NAME_MASTER.LAST_NAME, NAME_MASTER.FIRST_NAME
From NAME_MASTER
JOIN EX_SCHOLARSHIP_RECIPIENTS on NAME_MASTER.ID_NUM = EX_SCHOLARSHIP_RECIPIENTS.ID_NUM
JOIN SCHOLARSHIP on EX_SCHOLARSHIP_RECIPIENTS.AID_ELEMENT = SCHOLARSHIP.AID_ELEMENT
JOIN YEAR_DEF on EX_SCHOLARSHIP_RECIPIENTS.YR_CDE = YEAR_DEF.YR_CDE
JOIN TERM_DEF on EX_SCHOLARSHIP_RECIPIENTS.TRM_CDE = TERM_DEF.TRM_CDE
Where EX_SCHOLARSHIP_RECIPIENTS.TRM_CDE = 'FA'
and EX_SCHOLARSHIP_RECIPIENTS.YR_CDE = '2021'
and EX_SCHOLARSHIP_RECIPIENTS.AID_ELEMENT not between '5000' and '5999'
)
Select distinct AWARDED_SCHOLARSHIPS.ID_NUM, STUDENT_NAME,
AWARDED_SCHOLARSHIPS.DESCRIPTION, AWARDED_SCHOLARSHIPS.AWARD_AMT,
--CASE
-- WHEN AWARDED_SCHOLARSHIPS.CHECK_ID not in (Select CHECK_ID from POWERFAIDS_CHECK)
-- THEN 'No'
-- ELSE 'Yes'
--END as Processed_FA_Award,
AWARDED_SCHOLARSHIPS.COMMENTS,
AWARDED_SCHOLARSHIPS.YR_DESC, AWARDED_SCHOLARSHIPS.TRM_DESC, AWARDED_SCHOLARSHIPS.LAST_NAME, AWARDED_SCHOLARSHIPS.FIRST_NAME
From AWARDED_SCHOLARSHIPS
LEFT OUTER JOIN POWERFAIDS_CHECK on AWARDED_SCHOLARSHIPS.ID_NUM = POWERFAIDS_CHECK.ID_NUM
Where AWARDED_SCHOLARSHIPS.ID_NUM in (Select ID_NUM from AWARDED_SCHOLARSHIPS)
Order by AWARDED_SCHOLARSHIPS.DESCRIPTION, LAST_NAME, FIRST_NAME
Any insights much appreciated, thanks!
It's hard to give a definitive answer here without knowing what your data and indexes look like. If you can share your the execution plan for both versions of your query it would be way easier to give you a clear answer.
You can share you execution plans here: https://www.brentozar.com/pastetheplan/
Without the execution plan here are a couple of ideas to try:
EXISTS often performs better than IN/NOT IN
CASE WHEN EXISTS (SELECT * FROM POWERFAIDS_CHECK WHERE CHECK_ID = AWARDED_SCHOLARSHIPS.CHECK_ID) THEN [...]
Adding a new CTE that contains the subset of data you need might help:
), VALID_CHECK_IDS AS ( SELECT DISTINCT CHECK_ID FROM POWER_FAIDS_CHECK )
Then use this CTE in your case statement.
Add a second join to POWERFAIDS_CHECK
LEFT JOIN POWERFAIDS_CHECK AS VALIDCHECKID ON AWARDED_SCHOLARSHIPS.CHECK_ID = POWERFAIDS_CHECK.CHECK_ID
and update your case to
CASE WHEN VALIDCHECKID.CHECK_ID IS NOT NULL THEN 'No' ELSE 'Yes' [...]

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

Duplicate fields in a table, distinct doesn't work

I have the following query:
select distinct
ROW_ID = row_number() over (
order by wms_us.wms_us.rrno.rrdate
, wms_us.wms_us.rrno.pono
, wms_us.wms_us.transferboxdet.meidhex
, att.Date_cleared
)
, ATT_PO = wms_us.wms_us.rrno.pono
, Received_Date = wms_us.wms_us.rrno.rrdate
, IMEI = case
when len(wms_us.wms_us.transferboxdet.meidhex) >= 15
then left(wms_us.wms_us.transferboxdet.meidhex, 14)
else wms_us.wms_us.transferboxdet.meidhex
end
, Model = case
when (wms_us.wms_us.model.modeldesc = 'MIXED')
then wms_us.wms_us.transferboxdet.basemodel
else wms_us.wms_us.model.modelbase
end
, Date_cleared = case
when (Future.[Error Code] = '1')
then Future.LocalTime
else att.Date_cleared
end
, Result = case
when (Future.[Error Code] = '1')
then 'PASS'
else att.Result
end
from wms_us.wms_us.transferboxdoc
inner join wms_us.wms_us.transferboxdet
on wms_us.wms_us.transferboxdoc.transferboxdocid
= wms_us.wms_us.transferboxdet.transferboxdocid
inner join wms_us.wms_us.rrno
on wms_us.wms_us.transferboxdet.rrnoid = wms_us.wms_us.rrno.rrnoid
inner join wms_us.wms_us.model
on wms_us.wms_us.transferboxdoc.modelid = wms_us.wms_us.model.modelid
left join DRSCSQLQADB01.att_view2.dbo.attview2 as att
on att.IMEI = LEFT(wms_us.wms_us.transferboxdet.meidhex, 14)
inner join Futerdial.dbo.Futuredial_Validation as Future
on Future.IMEI = wms_us.wms_us.transferboxdet.meidhex
where (wms_us.wms_us.rrno.rrdate > '2016-12-01')
and Future.IMEI = '352130070643357'
I have the IMEI in the table Futuredial_Validation duplicate, I have been trying to use the Distinct just to show me one IMEI but it's not working, there is any alternative that I can use?? Or I am using it wrong?
Attach a picture of what is showing me, I just one be able to see one the first one.
Screenshot
Thanks
For rows to be filtered out by distinct, all values must be the same. In this query it looks like you can just wrap the query in a CTE and filter on ROW_ID = 1.

MS SQL Join based on One conditional if NULL, two if value passed

We have an SMS Text Message sender for various merchants that sends text messages based on the merchant ID. They can also send SMS Messages to limiting them to the Location ID.
When the SMS Campaign is set, the Merchant ID (MID) will be set, but the Location ID (LID) will be NULL unless the user wants to limit the SMS campaign to only those that have visited a specific location.
Here's my attempt:
SELECT * FROM tblOrders_SMS
INNER JOIN tblMerchants ON sms_order_mid = merchant_mid
(
CASE
WHEN ISNULL(sms_order_lid,1)
INNER JOIN tblLookup_Locations_Members ON lm_mid = sms_order_mid
ELSE
INNER JOIN tblLookup_Locations_Members ON lm_mid = sms_order_mid AND lm_lid = sms_order_lid
END
)
INNER JOIN tlbMembers ON member_id = lm_member_id
WHERE sms_order_sent = 0
So the idea is do an inner join on just the MID fields if the sms_order_lid is NULL, but if the SMS Campaign order has a LID set in sms_order_lid, then make it join on both fields.
First, ISNULL is a function and replaces a null value if the value in the column is null.
Almost exactly like COALESCE in ANSI-Standard-SQL
It's not an if clause.
Second, if you want to catch NULL in a "case when" clause in T-SQL, your syntax
CASE
WHEN ISNULL(sms_order_lid,1)
...
is wrong, and this syntax is right:
CASE
WHEN sms_order_lid IS NULL THEN [...]
ELSE [...]
END
Third, unless I interpreted your ISNULL wrong, this is what you actually want:
SELECT *
FROM tblOrders_SMS
INNER JOIN tblMerchants
ON sms_order_mid = merchant_mid
INNER JOIN tblLookup_Locations_Members
ON lm_mid = sms_order_mid
AND
(
lm_lid = sms_order_lid
OR
sms_order_lid IS NULL
)
INNER JOIN tlbMembers
ON member_id = lm_member_id
WHERE sms_order_sent = 0
Try this:
SELECT *
FROM tblOrders_SMS
INNER JOIN
tblMerchants ON sms_order_mid = merchant_mid
INNER JOIN
tblLookup_Locations_Members ON
(sms_order_lid IS NULL AND lm_mid = sms_order_mid) OR
(lm_mid = sms_order_mid AND lm_lid = sms_order_lid)
INNER JOIN
tlbMembers ON member_id = lm_member_id
WHERE sms_order_sent = 0

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