Issue regarding Nested CASE statement in sql server 2005 - sql-server

here is my sql when i am trying to execute it then i am getting error msg An expression of non-boolean type specified in a context where a condition is expected, near 'then'.
i am not being able to understand it where i am making mistake. so please have a look at my full sql specially where i use nested case and tell me what to rectify.
SELECT
[bbajobs].[jid],
[Add Dates],
CASE WHEN 1 then 'Yes'
CASE WHEN 0 then
CASE WHEN job_flow_state.no_fault_found = 1 THEN 'No fault found'
CASE WHEN job_flow_state.unable_to_repaired = 1 THEN 'Unable to repair'
CASE WHEN job_flow_state.Repair_Not_Requested = 1 THEN 'Repair Not Requested'
ELSE 'N/A'
END
END AS [Repaired]
FROM bbajobs
LEFT JOIN ourfeedback
ON bbajobs.jid = ourfeedback.jid
INNER JOIN job_flow_state
ON bbajobs.jid = job_flow_state.jid
WHERE CONVERT(VARCHAR(8), bbajobs.jobshippeddate, 112) >='20140117'
AND CONVERT(VARCHAR(8), bbajobs.jobshippeddate, 112) <='20140117' AND bbajobs.jobstate IN ('DONE')
AND bbajobs.jobtype NOT LIKE '%warranty%'
AND job_flow_state.repaired = 1
AND (ltrim(rtrim(ourfeedback.Rating))='' OR ltrim(rtrim(ourfeedback.Rating))='N/A') AND [bbajobs].[accountreference] IN
(SELECT accountref FROM ourfeedback where
CONVERT(VARCHAR(8), ourfeedback.adddates, 112) >='20140117' AND CONVERT(VARCHAR(8), ourfeedback.adddates,112) <= '20140117'
)
nested case used
CASE WHEN 1 then 'Yes'
CASE WHEN 0 then
CASE WHEN job_flow_state.no_fault_found = 1 THEN 'No fault found'
CASE WHEN job_flow_state.unable_to_repaired = 1 THEN 'Unable to repair'
CASE WHEN job_flow_state.Repair_Not_Requested = 1 THEN 'Repair Not Requested'
ELSE 'N/A'
END
END AS [Repaired]

I'd rewrite the nested case statement like so:
CASE WHEN 1 then 'Yes'
ELSE
CASE WHEN job_flow_state.no_fault_found = 1 THEN 'No fault found'
WHEN job_flow_state.unable_to_repaired = 1 THEN 'Unable to repair'
WHEN job_flow_state.Repair_Not_Requested = 1 THEN 'Repair Not Requested'
ELSE 'N/A'
END
END AS [Repaired]

You've got too many CASEs - you just need WHENs in the inner nesting. You also need to switch on a predicate - i.e. when 'what' is 1 or 0. And lastly, you should consider what happens if the inner case doesn't match.
i.e.:
CASE SomeColumn
WHEN 1 then 'Yes'
WHEN 0 then
CASE WHEN job_flow_state.no_fault_found = 1 THEN 'No fault found'
WHEN job_flow_state.unable_to_repaired = 1 THEN 'Unable to repair'
WHEN job_flow_state.Repair_Not_Requested = 1 THEN 'Repair Not Requested'
ELSE 'Oops'
END
ELSE 'N/A'
END AS [Repaired];
SqlFiddle here

Related

SQL: Reusing Query with EXIST

Ok so I have a query that looks something like
SELECT
CASE WHEN EXISTS(SELECT NULL
FROM B
WHERE B.LENGTH = A.LENGTH + 10)
THEN 'Yes'
ELSE 'No'
END AS Result1,
CASE WHEN EXISTS(SELECT NULL
FROM B
WHERE B.LENGTH = A.LENGTH - 10)
THEN 'Yes'
ELSE 'No'
END AS Result2,
CASE WHEN EXISTS(SELECT NULL
FROM B
WHERE B.LENGTH = A.LENGTH)
THEN 'Yes'
ELSE 'No'
END AS Result3
FROM A
As you can see the 3 EXIST Queries are almost the same with little differentce that (I hope) can be passed as an argument.
I tried to create a TVF but it fails when I Return SELECT NULL... but works if I use SELECT *. The thing I am afraid of is that I don't need the values I want to check if only exists and that's it.
My question is what would be the best way to refactor this code so it's not that repetitive?
You can use conditional aggregation to generate one query per row having three columns:
SELECT CASE WHEN CA.C1 > 0 THEN 'Yes' ELSE 'No' END
, CASE WHEN CA.C2 > 0 THEN 'Yes' ELSE 'No' END
, CASE WHEN CA.C3 > 0 THEN 'Yes' ELSE 'No' END
FROM A
CROSS APPLY (
SELECT COUNT(CASE WHEN B.LENGTH = A.LENGTH + 10 THEN 1 END)
, COUNT(CASE WHEN B.LENGTH = A.LENGTH - 10 THEN 1 END)
, COUNT(CASE WHEN B.LENGTH = A.LENGTH THEN 1 END)
FROM B
WHERE B.LENGTH IN (A.LENGTH + 10, A.LENGTH - 10, A.LENGTH)
) AS CA(C1, C2, C3)
You could do something like this:
SELECT A.Length,
CASE COUNT(CASE A.[LENGTH] WHEN B.[LENGTH] - 10 THEN 1 END)WHEN 0 THEN 'No' ELSE 'Yes' END AS result1,
CASE COUNT(CASE A.[LENGTH] WHEN B.[LENGTH] + 10 THEN 1 END)WHEN 0 THEN 'No' ELSE 'Yes' END AS result2,
CASE COUNT(CASE A.[LENGTH] WHEN B.[LENGTH] THEN 1 END)WHEN 0 THEN 'No' ELSE 'Yes' END AS result3
FROM A
CROSS JOIN B
GROUP BY A.Length;
This saves on 3 scans of the table B, but you will still need repetitive logic of some kind.

SQL Server complicated CASE Statement (check value of a field first then choose CASE stmt used)

How would I write a CASE statement where I need to check the value of a field first before I know which way I need the CASE statement prepared? I wrote it as an IF below:
select *,
IF schedule_at is not NULL THEN CASE
when actual_start < schedule_at THEN 'Early'
else 'Late'
END as Delivery,
ELSE
case
when actual_start between schedule_from and schedule_to THEN 'On Time'
when datediff(minute,actual_start,schedule_from) < 0 THEN 'Late'
else 'Early'
END as Delivery,
END
from some_dates_table
Hi if i understand what you want this query should be work :
select *,
Case when schedule_at is not NULL THEN (CASE
when actual_start < schedule_at THEN 'Early'
else 'Late'
END)
ELSE
(case
when actual_start between schedule_from and schedule_to THEN 'On Time'
when datediff(minute,actual_start,schedule_from) < 0 THEN 'Late'
else 'Early'
END) END as Delivery
from some_dates_table

SQL Server - What's the right query for this purpose?

I have a TABLE that contains, for example:
ID CVG
4 A
4 C
5 B
Each row contains a coverage for a given ID. If the ID does not have a coverage, there will be no row in the table (ex. ID 4 has no coverage B).
From this table I want to write a query like
SELECT ID, A = case (when ??? then 'TRUE' when ??? then 'FALSE'), B = case (...), C = case (...) FROM TABLE
that will give the output
ID A B C
4 TRUE FALSE TRUE
5 FALSE TRUE FALSE
where there is only one row for each ID, and one column for each coverage.
What's a workable query for this? I'm not allowed to change any permanent tables on the server so I'm trying to reach a solution with what I have.
You can use conditional aggregation to get the required result:
SELECT ID,
CASE
WHEN COUNT(CASE WHEN CVG = 'A' THEN 1 END)>=1 THEN 'TRUE'
ELSE 'FALSE'
END AS A,
CASE
WHEN COUNT(CASE WHEN CVG = 'B' THEN 1 END)>=1 THEN 'TRUE'
ELSE 'FALSE'
END AS B,
CASE
WHEN COUNT(CASE WHEN CVG = 'C' THEN 1 END)>=1 THEN 'TRUE'
ELSE 'FALSE'
END AS C,
.... etc
FROM mytable
GROUP BY ID
SQL Fiddle Demo
You could do something like this:
select
ID,
max(case when CVG = 'A' then 'TRUE' else 'FALSE' end),
max(case when CVG = 'B' then 'TRUE' else 'FALSE' end),
max(case when CVG = 'C' then 'TRUE' else 'FALSE' end),
from
table
group by
ID
The case + max will select the true if even one row is found for that ID, otherwise false.
If you want to have it select where
A = case (when ??? then 'TRUE' when ??? then 'FALSE'), B = case (...), C = case (...)
which is what I got from your explenation, what you need to do is
SELECT id, A, B, C FROM TABLE WHERE A = case (when ??? then 'TRUE' when ??? then 'FALSE'), B = case (...), C = case (...)

MS SQL - is there a quick way to refer to the result of a case statement without re-doing the case statement?

...In other words...
If I have a case statement that does this...
Case
when Type = 'payment' then net *-1
else net
end as 'pos_neg'
How can I use the result of that in another case statement that split payments and receipts by > or < that 0.
What I want to do is this....
Case
when 'pos_neg' >0 then 'pos_neg'
else 0 end as 'Receipts'
....and the opposite for payments.
the only way I know to acheive this is to nest the first case in the second....which is a lot of repetition.
You could select from a nested select statement.
select case when 'pos_neg' > 0 then 'pos_neg' else 0 end as 'Receipts'
from
(Select case when Type = 'payment' then net*-1 else net end as 'pos_neg'
From Table) T
or use a Common Table Expression
with T(pos_neg) as (
Select case when Type = 'payment' then net*-1 else net end as pos_neg
From Table)
select case when pos_neg > 0 then pos_neg else 0 end as Receipts
from T
select
case
when Type = 'payment' and net * -1 > 0
then 'pos_neg'
when Type = 'payment' and net * -1 <= 0
then ...
...
else 0 end as [Receipts]

How to use conditional columns values in the same select statement?

I have something like
(COMPLEX_EXPRESSION_N stands for a long subquery)
select
ID_Operation,
FirstCheck = CASE WHEN (COMPLEX_EXPRESSION_1)= 0 then 0 else 1 end,
SecondCheck = CASE WHEN (COMPLEX_EXPRESSION_2)= 0 then 0 else 1 end,
ThirdCheck = CASE WHEN (COMPLEX_EXPRESSION_3)= 0 then 0 else 1 end,
AllChecksOk = Case WHEN
(FirstCheck + SecondCheck + Third CHeck = 3)
Then 'OK' Else 'No' End
from
AllOperationsTable
Is it possible to use FirstCheck, SecondCheck, ThirdCheck as I did in the AllChecksOk line?
I am not concerned about performance, this is something that is manually run once a day on a very small number of records, I just want to avoid to create views, tables or temporary tables and keep all in a single select statement.
As an altenrative I can do this, but it makes the query less readable (as I need to write twice every complex expression):
select
ID_Operation,
FirstCheck = CASE WHEN (COMPLEX_EXPRESSION_1)= 0 then 0 else 1 end,
SecondCheck = CASE WHEN (COMPLEX_EXPRESSION_2)= 0 then 0 else 1 end,
ThirdCheck = CASE WHEN (COMPLEX_EXPRESSION_3)= 0 then 0 else 1 end,
AllChecksOk = Case WHEN
(COMPLEX_EXPRESSION_1+ COMPLEX_EXPRESSION_2+
COMPLEX_EXPRESSION_3CHeck = 3) Then 'OK' Else 'No' End
from
AllOperationsTable
You can't reference a column alias in the select but you can use a CTE as below.
;WITH CTE AS
(
select
ID_Operation,
FirstCheck = CASE WHEN (COMPLEX_EXPRESSION_1)= 0 then 0 else 1 end,
SecondCheck = CASE WHEN (COMPLEX_EXPRESSION_2)= 0 then 0 else 1 end,
ThirdCheck = CASE WHEN (COMPLEX_EXPRESSION_3)= 0 then 0 else 1 end
from
AllOperationsTable
)
SELECT *,
AllChecksOk = Case WHEN
(COMPLEX_EXPRESSION_1+ COMPLEX_EXPRESSION_2+
COMPLEX_EXPRESSION_3CHeck = 3) Then 'OK' Else 'No' End
FROM CTE
You can also use CROSS APPLY to define the 3 column aliases then reference them in the main SELECT list as in this example.
Below is a derived table solution
SELECT
T.ID_Operation,
FirstCheck = CASE WHEN T.Expr1 = 0 THEN 0 ELSE 1 END,
SecondCheck = CASE WHEN T.Expr2 = 0 THEN 0 ELSE 1 END,
ThirdCheck = CASE WHEN T.Expr3 = 0 THEN 0 ELSE 1 END,
AllChecksOk = CASE WHEN T.Expr1 + T.Expr2 + T.Expr3 = 3 THEN 'OK' ELSE 'No' END
FROM
(
SELECT
ID_Operation,
Expr1 = (COMPLEX_EXPRESSION_1),
Expr2 = (COMPLEX_EXPRESSION_2),
Expr3 = (COMPLEX_EXPRESSION_3)
FROM
AllOperationsTable
) T
Personally, I find using CTE or derived tables a bit confusing for this purpose, as you have to nest things one level and think about the nesting impliciations. A much simpler approach (at least in my opinion) is to use APPLY (or standard SQL LATERAL in other RDBMS) to generate column expression aliases:
SELECT
ID_Operation,
FirstCheck,
SecondCheck,
ThirdCheck,
AllChecksOk = CASE
WHEN FirstCheck + SecondCheck + ThirdCheck = 3 THEN 'OK' ELSE 'NO'
END
FROM
AllOperationsTable
CROSS APPLY (
SELECT
FirstCheck = CASE WHEN COMPLEX_EXPRESSION_1 = 0 THEN 0 ELSE 1 END,
SecondCheck = CASE WHEN COMPLEX_EXPRESSION_1 = 0 THEN 0 ELSE 1 END,
ThirdCheck = CASE WHEN COMPLEX_EXPRESSION_1 = 0 THEN 0 ELSE 1 END
) t

Resources