SQL Server embedded CASE statement - sql-server

How do I go about writing a query where I want to get the last value?
For example I have a table with with tasks, 1-4 for each parent workflow.
I then have a completed column with a 1 or 0.
I would like to return 1 value, Task 1 or 2 or 3 or 4 depending if the task is complete.
I tried an embedded CASE statement, but it would always returns value 4.
There has to be a better way.
SELECT
Estimate.EstimateID, Estimate.EstimateNo,
CASE
WHEN TransWorkFlow.OwnerID = Estimate.EstimateID
THEN
CASE
WHEN TransWorkFlowDetails.TaskNo = 1 AND TransWorkFlowDetails.Completed = 0
THEN 1
ELSE
CASE
WHEN TransWorkFlowDetails.TaskNo = 2 AND TransWorkFlowDetails.Completed = 0
THEN 2
ELSE
CASE
WHEN TransWorkFlowDetails.TaskNo = 3 AND TransWorkFlowDetails.Completed = 0
THEN 3
ELSE
CASE
WHEN TransWorkFlowDetails.TaskNo = 4 AND TransWorkFlowDetails.Completed = 0
THEN 4
ELSE 4
END
END
END
END
END AS TaskCompleted
FROM
TransWorkFlow
INNER JOIN
TransWorkFlowDetails ON TransWorkFlow.TransWorkFlowID = TransWorkFlowDetails.TransWorkFlowID
INNER JOIN
Estimate ON TransWorkFlow.OwnerID = Estimate.EstimateID

It seems like this can be simplified into one simple CASE statement
SELECT
e.EstimateID,
e.EstimateNo,
CASE WHEN td.Completed = 0 AND td.TaskNo IN (1,2,3,4) THEN td.TaskNo ELSE 4 END AS TaskCompleted
FROM TransWorkFlow t
INNER JOIN TransWorkFlowDetails td ON t.TransWorkFlowID = td.TransWorkFlowID
INNER JOIN Estimate e ON t.OwnerID = e.EstimateID;
Note:
we're using aliases like t, td and e to shorten the code
we got rid of your initial CASE check, because it's covered by the INNER JOIN
TaskNo seems to be your check condition and also output, let's can reference that in THEN part

Not really clear what you are trying to do here but I think that wall of case expressions could be simplified to this.
case when TransWorkFlowDetails.Completed = 0
AND TransWorkFlowDetails.TaskNo in (1, 2, 3, 4)
THEN TransWorkFlowDetails.TaskNo
ELSE
--whatever you want here
END

Related

Using between clause on nvarchar column to find range is not working

I have 3 nvarchar columns user_3, user_4 and description. I am setting yes and no flag. If the value in description column is equal or in between user_3 and User4 then set the flag to 'N' else
set the flag to 'Y'.
Here is the SQL script I wrote so far. it works in some instances but not always. See the image with results. it worked on line #1 but didn't work on line # 6 for example. What am I doing wrong?
SELECT [B].USER_3,[B].USER_4,A.DESCRIPTION,
(case when Isnumeric(A.DESCRIPTION) <> 1 then 'Y'
else case when (CASE WHEN Isnumeric(A.DESCRIPTION) = 1 then
cast(A.DESCRIPTION AS decimal(10,5)) else 0 end)
between ( CASE WHEN Isnumeric([B].USER_4) = 1 then
cast([B].USER_4 AS decimal(10,5)) else 0 end) and
(CASE WHEN Isnumeric([B].USER_3) = 1 then cast([B].USER_3 AS decimal(10,5)) else 0 end)
then 'N' else 'Y' end end) as Flagset
from A , B
Here is the screenshot of the results
enter image description here
The issue is with your use of BETWEEN as per the docs:
BETWEEN returns TRUE if the value of test_expression is greater than or equal to the value of begin_expression and less than or equal to the value of end_expression.
Because you don't know whether USER_3 or USER_4 is the higher limit or the lower limit, you need to test both ways.
Note: For this sort of query I prefer to pre-calculate all the values (using CROSS APPLY in this case) I need. It makes it much easier to follow and debug.
SELECT USER_3, USER_4, [DESCRIPTION]
, CASE WHEN ISNUMERIC([DESCRIPTION]) <> 1 THEN 'Y' ELSE
CASE WHEN CASE WHEN ISNUMERIC([DESCRIPTION]) = 1 THEN CAST([DESCRIPTION] AS decimal(10,5)) ELSE 0 END BETWEEN CASE WHEN ISNUMERIC(USER_4) = 1 THEN CAST(USER_4 AS decimal(10,5)) ELSE 0 END AND
CASE WHEN ISNUMERIC(USER_3) = 1 THEN CAST(USER_3 AS decimal(10,5)) ELSE 0 END
THEN 'N' ELSE 'Y' END END AS Flagset
, CASE WHEN DNUMERIC <> 1 THEN 'Y' ELSE CASE WHEN DESCRIPTIOND BETWEEN USER_4D AND USER_3D OR DESCRIPTIOND BETWEEN USER_3D AND USER_4D THEN 'N' ELSE 'Y' END END CorrectedFlagSet
FROM (VALUES
('1.395','1.385','1.390')
, ('22.025','41.425','22')
, ('22.025','41.425','23.025')
) AS X (USER_3, USER_4, [DESCRIPTION])
CROSS APPLY (VALUES (
CASE WHEN ISNUMERIC(USER_3) = 1 THEN CAST(USER_3 AS decimal(10,5)) ELSE 0 END
, CASE WHEN ISNUMERIC(USER_4) = 1 THEN CAST(USER_4 AS decimal(10,5)) ELSE 0 END
, CASE WHEN ISNUMERIC([DESCRIPTION]) = 1 THEN CAST([DESCRIPTION] AS decimal(10,5)) ELSE 0 END
, CASE WHEN ISNUMERIC([DESCRIPTION]) = 1 THEN 1 ELSE 0 END
)) AS Y (USER_3D, USER_4D, DESCRIPTIOND, DNUMERIC);
Returns:
USER_3
USER_4
DESCRIPTION
Flagset
CorrectedFlagSet
1.395
1.385
1.390
N
N
22.025
41.425
22
Y
Y
22.025
41.425
23.025
Y
N
I'm sure I don't have to mention that you should really be storing this data in numeric form in the first place as it will perform better and save you lots of future issues.
And well laid out queries with consistent casing also helping understand and debug them.
Finally providing a minimal reproducible example with sample data, your query and your desired result as shown here makes it much easier for people to assist.

where case when in clause statement

I need a SQL query having WHERE CASE WHEN statement with a in list. I am not sure what part of my query is wrong,
First I need to make a KEY out of coldelist and IDD,IDP and then since my codelists' lenght are 5 or 6 so need to use CASE WHEN to check if their length are 5 or 6 then search in separate lists (each almost 200 or more) because my aim is to compare some tables' data using EXCEPT
My SQL statement is like:
SELECT
codelist = CASE
WHEN LEN(codelist) = 5
THEN CONCAT(CONCAT(SUBSTRING(codelist, 1, 5), IDD), IDP)
WHEN LEN(codelist) = 6
THEN CONCAT(CONCAT(SUBSTRING(codelist, 1, 6), IDD), IDP)
ELSE codelist
END,
codelist
FROM
[table1]
WHERE
(codelist = CASE
WHEN LEN(codelist) = 5
THEN (SELECT 'FEV00', 'FEV64', 'FEV97', 'FEV90')
WHEN LEN(codelist) = 6
THEN (SELECT 'FEV208', 'FEV227', 'FEV308', 'FEV326')
END)
EXCEPT
SELECT
....

Will these two MS queries give me the same output?

I'm updating some queries as an assignment for work. The bottom query is the updated version with different syntax, and the top is the old query. I just want to double check that the two queries will end with the same results:
SELECT a.breed
FROM dogs a, cats b, fish c
WHERE a.breed = b.breed AND a.tail = 0 AND b.size = c.size AND c.gills = 0 AND c.fin = #fin
----
SELECT a.breed
FROM dogs a
INNER JOIN cats b ON a.breed = b.breed
INNER JOIN fish c ON b.size = c.size
WHERE c.gills = 0 AND a.tail = 0 AND c.fin = #fin
Edit 1: fixed the format of the question to better represent what I meant. I changed the names of the tables and columns just in case.
Yes, these queries will return the same results.

SQL Server CASE 1 WHEN 1, WHERE 1=1 AND 1=1

I inherited the following query from a previous application. I'm having a hard time understanding the "Case" in the "Select" and "Where" clause also.
SELECT J1.AC_CODE, J1.PERIOD, J1.JRNAL_NO, J1.DESCRIPTN, - J1.AMOUNT ,
J1.ANAL_T3,
CASE 1
WHEN 1 THEN 'A'
ELSE J1.ACCNT_CODE
END ,
J1.JRNAL_LINE
FROM dbo.JSource J1
WHERE 1=1
AND 1=1
AND NOT ('A' LIKE '%Z%'
AND J1.JRNAL_SRCE IN ('B/F',
'CLRDN')
AND J1.JRNAL_NO = 0)
AND CASE 1
WHEN 1 THEN 'A'
ELSE J1.AC_CODE
END ='A'
AND J1.AC_CODE='156320'
AND J1.PERIOD BETWEEN 2014001 AND 2014012
AND J1.ANAL_T3='ANAL001'
ORDER BY 1,2,3,4,5,6,7,8
I'm not sure If I understand the following clauses correctly:
1st Clause:
CASE 1
WHEN 1 THEN 'A'
ELSE J1.AC_CODE
END
I understood as: If column 1 is true, then choose literal A ortherwise choose J1.AC_CODE.
2nd clause:
WHERE 1=1
AND 1=1
AND NOT ('A' LIKE '%Z%'
AND J1.JRNAL_SRCE IN ('B/F',
'CLRDN')
AND J1.JRNAL_NO = 0)
AND CASE 1
WHEN 1 THEN 'A'
ELSE J1.AC_CODE
END ='A'
AND J1.AC_CODE='156320'
AND J1.PERIOD BETWEEN 2014001 AND 2014012
AND J1.ANAL_T3='ANAL001'
I'm totally lost with this "Where" clause.
Can you help explain this query and write a better version for this whole query?
I'm running this query on SQL Server 2008 (R2)
I understood as: If column 1 is true, then choose literal A ortherwise
choose J1.AC_CODE.
No, it is comparing the value 1 with the value 1 and if that is true the case returns an A and that is of course always true so the case statement will always return A.
Your where clause does not do anything at all.
1=1
AND 1=1
will always be true and the case will always be true and 'A' LIKE '%Z%' will always be false and that makes the entire AND NOT 'A' LIKE '%Z%' .... expression to always be true.
A simpler version of your query would look like this.
SELECT J1.AC_CODE,
J1.PERIOD,
J1.JRNAL_NO,
J1.DESCRIPTN,
- J1.AMOUNT,
J1.ANAL_T3,
'A',
J1.JRNAL_LINE
FROM dbo.JSource J1
WHERE J1.AC_CODE='156320' AND
J1.PERIOD BETWEEN 2014001 AND 2014012 AND
J1.ANAL_T3='ANAL001'
ORDER BY 1,2,3,4,5,6,7,8
Without knowing the history of this query, I am guessing that this was written with testing/debugging in mind and some of that code has been left in place. The case statement in the select line could (and I repeat could as this is my guess from looking at the query) have had other with clauses during creation of the query used for testing and these would have been switched between by changing the value after the CASE (example SELECT ..... CASE 1 WHEN 1 THEN 'A' WHEN 2 THEN 'some value' WHEN 3 'some other value' ELSE J1.ACCNT_CODE).
As for the where 1 = 1, I have seen this used during query creation/testing - mainly because it means each of the true conditions can easily be commented/uncommented or cut & pasted as the first where condition is always true. I've not seen AND 1 = 1 before. Not sure what that line was intended for, but I'd still think came about from testing/debugging and was not taken out the query.

checking rows of row_number result on condition of another column

I have a query that outputs some rows that I need to "filter".
The data I want to filter is like this:
rownum value
1 0
2 0
3 1
4 1
I need the first 2 rows, but only when they have "0" in the value-column.
The structure of the query is like this:
select count(x)
from
(
select row_number() over (partition by X order by y) as rownum, bla, bla
from [bla bla]
group by [bla bla]
) as temp
where
/* now this is where i want the magic to happen */
temp.rownum = 1 AND temp.value = 0
AND
temp.rownum = 2 AND temp.value = 0
So I want x only when row 1 and 2 have "0" in the value-column.
If either rownumber 1 or 2 have a "1" in the value-column, I dont want them.
I basically wrote the where-clause the way I wrote it here, but it's returning data sets that have "1" as value in either row 1 or 2.
How to fix this?
A value in a single row for a given column can never be both 1 and 2 at the same time.
So, first of all, either use OR (which is what I believe you intended):
WHERE (temp.rownum = 1 AND temp.value = 0)
OR (temp.rownum = 2 AND temp.value = 0)
Or simplify the query altogether:
WHERE temp.rownum <= 2 AND temp.value = 0
From here, you will get just the first two rows, and only if value = 0. If you only want rows when both rows are returned (i.e. both rows have value = 0), add
HAVING COUNT(1) = 2
to the query.

Resources