using CASE in T-SQL in the where clause? - tsql

Im trying to use case to vary the value im checking in a where clause but I'm getting the error:
incorrect syntax near the keyword 'CASE'
SQL Server 2005
select *
from table
where ((CASE when adsl_order_id like '95037%'
then select '000000'+substring(adsl_order_id,6,6)
ELSE select adsl_order_id
END)
not in (select mwebID from tmp_csv_dawis_bruger0105)

Here is one way to include a case statement in a Where clause:
SELECT * FROM sometable
WHERE 1 = CASE WHEN somecondition THEN 1
WHEN someothercondition THEN 2
ELSE ... END

You could try
SELECT *
FROM table
WHERE (SELECT CASE WHEN adsl_order_id LIKE '95037%'
THEN '000000' + SUBSTRING(adsl_order_id, 6, 6)
ELSE adsl_order_id
END)
NOT IN (select mwebID from tmp_csv_dawis_bruger0105)

A correlated subquery is one possibility:
select *
from mytable
where not exists (
select *
from
tmp_csv_dawis_bruger0105
where
mwebID =
CASE when mytable.adsl_order_id like '95037%' then '000000' + substring(mytable.adsl_order_id,6,6)
ELSE mytable.adsl_order_id END
)

I came to this question looking for an answer thinking WHERE CASE ... would be the solution. I could not adapt the answers to my problem, but this technique to use a parameter that could be null, partial, or specific, works:
CREATE PROC myproc #vJobID VARCHAR (11)
AS
SELECT * FROM Jobs
WHERE Jobs.JobID like coalesce(#vJobID+'%','%')
HTH

You have one too many opening parentheses before the CASE expression.

Put it in the SELECT clause...
select *, (CASE when adsl_order_id like '95037%'
then '000000'+substring(adsl_order_id,6,6)
ELSE adsl_order_id
END) AS Id
from table
where not in (select mwebID from tmp_csv_dawis_bruger0105)
Also, you don't need to "SELECT" the result of the CASE.

Related

How to optimize CASE statement in SELECT query which has same check condition for three different columns

I have below select statement to fetch the data having CASE statement.
SELECT PK_ID
,MGR_ID
,EMP_ID
,CASE
WHEN msts.MGR_ID is null AND msts.EMP_ID is not null THEN
(SELECT 'A' from dual)
ELSE
(SELECT 'B' from dual)
END FIRST_COL
,CASE
WHEN msts.MGR_ID is null AND msts.EMP_ID is not null THEN
(SELECT 'P' from dual)
ELSE
(SELECT 'Q' from dual)
END SECOND_COL
,CASE
WHEN msts.MGR_ID is null AND msts.EMP_ID is not null THEN
(SELECT 'X' from dual)
ELIE
(SELECT 'Y' from dual)
END THIRID_COL
from m_sel_tabs msts
here, As i know that we can check condition with mulitiple columns but the result will be only one for CASE statement.
so my question is here that as my check CASE statement is the same for all three columns (FIRST_COL, SECOND_COL, THIRID_COL), hence is there any other way to write this query in an optimized way.
Thanks in advance.
Maybe I'm wrong, but - when saying that you have "the same 3 CASE statements" - well, you don't. Those are 3 different CASE statements. An expression is the same, yes, but you're selecting 3 different columns, with different results (A, B, P, Q, X, Y - in your example).
You could create a function which would "hide" code you currently use and make the SELECT prettier, such as
select
pk_id, ...,
f_col(1, MGR_ID, EMP_ID) first_col,
f_col(2, MGR_ID, EMP_ID) second_col,
f_col(3, MGR_ID, EMP_ID) third_col
from m_sel_tabs
but - at the end - it would be just the same (or, possibly somewhat worse because of context switching) as you'd have to put all that code somewhere (into the function, right?).

Using EXISTS as a column in TSQL

Is it possible to use the value of EXISTS as part of a query?
(Please note: unfortunately due to client constraints, I need SQLServer 2005 compatible answers!)
So when returning a set of results, one of the columns is a boolean value which states whether the subquery would return any rows.
For example, I want to return a list of usernames and whether a different table contains any rows for each user. The following is not syntactically correct, but hopefully gives you an idea of what I mean...
SELECT T1.[UserName],
(EXISTS (SELECT *
FROM [AnotherTable] T2
WHERE T1.[UserName] = T2.[UserName])
) AS [RowsExist]
FROM [UserTable] T1
Where the resultant set contains a column called [UserName] and boolean column called [RowsExist].
The obvious solution is to use a CASE, such as below, but I wondered if there was a better way of doing it...
SELECT T1.[UserName],
(CASE (SELECT COUNT(*)
FROM [AnotherTable] T2
WHERE T1.[UserName] = T2.[UserName]
)
WHEN 0 THEN CAST(0 AS BIT)
ELSE CAST(1 AS BIT) END
) AS [RowsExist]
FROM [UserTable] T1
Your second query isn't valid syntax.
SELECT T1.[UserName],
CASE
WHEN EXISTS (SELECT *
FROM [AnotherTable] T2
WHERE T1.[UserName] = T2.[UserName]) THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT)
END AS [RowsExist]
FROM [UserTable] T1
Is generally fine and will be implemented as a semi join.
The article Subqueries in CASE Expressions discusses this further.
In some cases a COUNT query can actually perform better though as discussed here
I like the other guys sql better but i just wrote this:
with bla as (
select t2.username, isPresent=CAST(1 AS BIT)
from t2
group by t2.username
)
select t1.*, isPresent = isnull(bla.isPresent, CAST(0 AS BIT))
from t1
left join blah on t1.username=blah.username
From what you wrote here I would alter your first query into something like this
SELECT
T1.[UserName], ISNULL(
(
SELECT
TOP 1 1
FROM [AnotherTable]
WHERE EXISTS
(
SELECT
1
FROM [AnotherTable] AS T2
WHERE T1.[UserName] = T2.[UserName]
)
), 0)
FROM [UserTable] T1
But actually if you use TOP 1 1 you would not need EXISTS, you could also write
SELECT
T1.[UserName], ISNULL(
(
SELECT
TOP 1 1
FROM [AnotherTable] AS T2
WHERE T1.[UserName] = T2.[UserName]
), 0)
FROM [UserTable] T1

IS IN (Select statement, 'value', 'value')

I am trying to run the following SQL
DELETE FROM T_ATH_POSHLD WHERE T_ATH_POSHLD.A_INSID IN (SELECT T_ATH_POSHLD.A_INSID FROM T_ATH_POSHLD LEFT JOIN T_ATH_INS ON T_ATH_POSHLD.A_INSID = T_ATH_INS.A_INSID WHERE T_ATH_INS.A_INSCLSCDE1 = 'CASH' AND T_ATH_POSHLD.A_INSID NOT IN (SELECT A_INSID FROM T_ATH_CCY) AND A_ACCID IN (SELECT A_ACCID FROM T_ATH_EXTACC, '1212OEIC', '5667033ZS'))
and in particular, am trying to check whether an ACCID is in a set of values, some coming from a table and two hardcoded. How would I achieve this?
IN (SELECT A_ACCID FROM T_ATH_EXTACC, '1212OEIC', '5667033ZS')
Doesn't work, I get an 'Incorrect Syntax error'.
Thanks
You need to use UNION to add the 2 hardcoded values to the resultset that you are passing to the in clause.
IN (SELECT A_ACCID FROM T_ATH_EXTACC UNION ALL SELECT '1212OEIC' UNION ALL SELECT '5667033ZS')
IN (SELECT '1212OEIC', '5667033ZS', A_ACCID FROM T_ATH_EXTACC )

Having "___ in (select distinct ___ from #temp)" in Case statement

I'm trying to achieve this
select
case
when Org_CD = '1111' or Org_CD in (select distinct New_Org_CD from #temp) then 'International'
end as 'Organisation',
count(*)
from #AnotherTempTable
group by
case
when Org_CD = '1111' or Org_CD in (select distinct New_Org_CD from #temp) then 'International'
end
I received this error:
Column '#AnotherTempTable.Org_Cd' is
invalid in the select list because it
is not contained in either an
aggregate function or the GROUP BY
clause.
Is it because I cannot use "in" keyword inside the case statements? If yes, any known workarounds would be more than helpful!
I'd try this...
select
Org_CD, count(*)
from
#AnotherTempTable A
JOIN
(select distinct New_Org_CD from #temp UNION SELECT '1111') T ON A.Org_CD = T.New_Org_CD
group by
Org_CD
You can't have an inline IN like this (CASE + aggregate)
If this is not OK, please give sample data and output
I solved it with a variation of gbn's solution using 'Union'. Thanks all.

T-SQL - how to get around the order by restriction in CTEs

I have the following CTE. Its purpose is to provide unique Month/Year pairs. Later code will use the CTE to produce a concatenated string list of the Month/Year pairs.
;WITH tblStoredWillsInPeriod AS
(
SELECT DISTINCT Kctc.GetMonthAndYearString(DateWillReceived) Month
FROM Kctc.StoredWills
WHERE DateWillReceived BETWEEN '2010/01/01' AND '2010/03/31'
ORDER BY DateWillReceived
)
I have omitted the implmementation of the GetMonthAndYearString function as it is trivial.
Edit: As requested by Martin, here is the surrounding code:
DECLARE #PivotColumnHeaders nvarchar(MAX)
--CTE declaration as above---
SELECT #PivotColumnHeaders =
COALESCE(
#PivotColumnHeaders + ',[' + Month + ']',
'[' + Month + ']'
)
FROM tblStoredWillsInPeriod
SELECT #PivotColumnHeaders
Sadly, it seems T-SQL is always one step ahead. When I run this code, it tells me I'm not allowed to use ORDER BY in a CTE unless I also use TOP (or FOR XML, whatever that is.) If I use TOP, it tells me I can't use it with DISTINCT. Yup, T-SQL has all the answers.
Can anyone think of a solution to this problem which is quicker than simply slashing my wrists? I understand that death from blood loss can be surprisingly lingering, and I have deadlines to meet.
Thanks for your help.
David
Will this work?
DECLARE #PivotColumnHeaders VARCHAR(MAX)
;WITH StoredWills AS
(
SELECT GETDATE() AS DateWillReceived
UNION ALL
SELECT '2010-03-14 11:48:07.580'
UNION ALL
SELECT '2010-03-12 11:48:07.580'
UNION ALL
SELECT '2010-02-12 11:48:07.580'
),
tblStoredWillsInPeriod AS
(
SELECT DISTINCT STUFF(RIGHT(convert(VARCHAR, DateWillReceived, 106),8), 4, 1, '-') AS MMMYYYY,
DatePart(Year,DateWillReceived) AS Year,
DatePart(Month,DateWillReceived) AS Month
FROM StoredWills
WHERE DateWillReceived BETWEEN '2010-01-01' AND '2010-03-31'
)
SELECT #PivotColumnHeaders =
COALESCE(
#PivotColumnHeaders + ',[' + MMMYYYY + ']',
'[' + MMMYYYY + ']'
)
FROM tblStoredWillsInPeriod
ORDER BY Year, Month
Could you clarify why you need the data in the the CTE to be ordered? And why you are not able to order the data in the query using the CTE. Remember data in an ordinary subquery can't be ordered either.
What about?
;WITH tblStoredWillsInPeriod AS
(
SELECT DISTINCT Kctc.GetMonthAndYearString(DateWillReceived) Month
FROM Kctc.StoredWills
WHERE DateWillReceived BETWEEN '2010/01/01' AND '2010/03/31'
ORDER BY DateWillReceived
),
tblStoredWillsInPeriodOrdered AS
(
SELECT TOP 100 PERCENT Month
FROM tblStoredWillsInPeriod
ORDER BY Month
)
And you think you know T-SQL syntax!
Turns out I was wrong about not being able to use TOP and DISTINCT together.
This yields a syntax error...
SELECT TOP 100 PERCENT DISTINCT...
whereas this is absolutely fine...
SELECT DISTINCT TOP 100 PERCENT...
Work that one out.
One drawback is that you have to include the ORDER BY field in the SELECT list, which in all likelihood will interfere with your expected DISTINCT results. Sometimes T-SQL has you running around in circles.
But for now, my wrists are left unmarked.
SELECT DISTINCT TOP 100 PERCENT ...
ORDER BY ...