CASE statement inside a WHERE clause in SQL Server - sql-server

I am trying to add a CASE statement, but I need an OR within it and I am having a little trouble.
I'm not sure how I can do this, but I was hoping someone could help. Here is what I am trying to do:
SELECT *
FROM Table1
WHERE IsUpdate = CASE WHEN #Type = 'Yes' THEN 1 ELSE (0 OR 1) END
So basically, I want to select only the rows that have IsUpdate set to 1 when #Type = 'Yes', otherwise I want to select the rows where IsUpdate = 0 OR IsUpdate = 1. Any ideas?

You don't need a CASE, i assume that the value can only be 0 or 1:
SELECT * FROM Table1
WHERE #Type <> 'Yes' OR IsUpdate = 1
If this is sitting in a stored-procedure it's probably better to use a If-Else instead of the parameter-check since above query is non-sargable so it might be inefficient on a large table.

The full where clause that matches your logic is:
where (#Type = 'Yes' and IsUpdate = 1) or
(#Type <> 'Yes' and IsUpdate in (0, 1))
You can simplify this, if you know something about the values in the columns. For instance, if IsUpdate only takes on the values 0 and 1 (and not NULL):
where #Type <> 'Yes' or IsUpdate = 1

Related

Update where exists, referencing the table being updated?

I need to update a table where one of the conditions is an EXISTS that needs to reference the table being updated.
I couldn't find a neat way to do this, so I resorted to this verbose SQL that gets the job done:
update TABLE_R set
_deleted = 1
where id in (
select id from TABLE_R r
where (r.connectId = #theID)
and (isnull(r._deleted, 0) = 0)
and (r.type = 'Person')
and exists(
select id from TABLE_P p
where (isnull(p.deleted, 0) = 1)
and (isnull(p.social_security, '') <> '')
and (p.social_security = r.social_security)
and (p.trans_id = r.trans_id)
)
)
Is there any way to simplify this? It seems like there should be a way to remove the outer nested select - but I couldn't find a way to reference TABLE_R in the EXISTS clause unless I wrap it in SELECT id FROM TABLE_R r.
Any ideas? Or is this as good as it gets?
I don't want to use JOIN, and I want to keep it as readable and simple as possible.
Whould this work? Since this is an UPDATE, PLEASE make sure you run this on test data, and also run it as a select first to verify the results.
UPDATE r SET _deleted = 1
--SELECT *
FROM TABLE_R r
WHERE r.connectId = #theID
AND ISNULL(r._deleted, 0) = 0
AND r.[type] = 'Person'
AND EXISTS (
SELECT *
FROM TABLE_P p
WHERE p.deleted = 1
AND p.social_security <> ''
AND p.social_security = r.social_security
AND s.trans_id = r.trans_id
)
I removed a couple things.
(isnull(p.deleted, 0) = 1)
The ISNULL() is not needed here since you want p.deleted = 1, that will filter out NULL's anyway.
and (isnull(p.social_security, '') <> '')
I also removed this ISNULL() since p.social_security = r.social_security will eliminate the NULL's as well, but you still want to avoid joining on blank social_security's.
In Sql Server, you can take your logic out of the in clause. Outside of that, you can make it a bit more readable by avoiding parentheses when not necessary. The exists clause may seem verbose, but it's actually going to be the most performant way you can do it. But for readability I like to select 0 to make it clear we don't care about the results.
update r
set _deleted = 1
from TABLE_R r
where r.connectId = #theID
and isnull(r._deleted, 0) = 0
and r.type = 'Person'
and exists(
select 0
from TABLE_P p
where isnull(p.deleted, 0) = 1
and isnull(p.social_security, '') <> ''
and p.social_security = r.social_security
and s.trans_id = r.trans_id
)

Check condition in WHERE clause

I have below dynamic WHERE condition in XML mapping which is working fine:
WHERE
IncomingFlightId=#{flightId}
<if test="screenFunction == 'MAIL'.toString()">
and ContentCode = 'M'
</if>
<if test="screenFunction == 'CARGO'.toString()">
and ContentCode Not IN('M')
</if>
order by ContentCode ASC
I'm trying to run below query in a IDE but unfortunately its not working.
Can anybody please explain what i'm doing wrong?
WHERE
IncomingFlightId = 2568648
AND (IF 'MAIL' = 'MAIL'
BEGIN
SELECT 'and ContentCode = "M"'
END ELSE BEGIN
SELECT 'and ContentCode Not IN("M")'
END)
order by ContentCode ASC
You can't use IF in straight up SQL statement, use CASE WHEN test THEN returniftrue ELSE valueiffalse END instead (if you have to use conditional logic)
That said, it's probably avoidable if you do something like this:
WHERE
(somecolumn = 'MAIL' AND ContentCode = 'M') OR
(somecolumn <> 'MAIL' and ContentCode <> 'M')
Example of conditional logic in a straight SQL:
SELECT * FROM table
WHERE
CASE WHEN col > 0 THEN 1 ELSE 0 END = 1
Case when runs a test and returns a value. You always have to compare the return value to something else. You can't do something that doesn't return a value.
It's kinda dumb here though, because anything you can express in the truth of a case when, can be more simply and readably expressed in the truth of a where clause directly..
SELECT * FROM table
WHERE
CASE WHEN type = 'x'
THEN (SELECT count(*) FROM x)
ELSE (SELECT count(*) FROM y)
END = 1
Versus
SELECT * FROM table
WHERE
(type = 'x' AND (SELECT count(*) FROM x) = 1) OR
type <> 'x' AND (SELECT count(*) FROM y) = 1)
It's useful for things like this though:
SELECT
bustourname,
SUM(CASE WHEN age > 60 THEN 1 ELSE 0 END) as count_of_old_people
FROM table
GROUP BY bustourname
If you're looking to write a stored procedure that conditionally builds an SQL, then sure, you can do that...
DECLARE #sql VARCAHR(max) = 'SELECT * FROM TABLE WHERE';
IF blah SET #sql = CONCAT(#sql, 'somecolumn = 1')
IF otherblah SET #sql = CONCAT(#sql, 'othercolumn = 1')
EXEC #sql...
But this is only in a stored procedure or procedure-like sql script where it builds a string that looks like an SQL, and then executes it dynamically. You cannot use IF in a plain SELECT statement
You are running the query which (beside it is syntactically incorrect SQL) has nothing to do with query generated and used by mybatis.
You need to understand how if in mybatis mapper works.
if element evaluates before the query is executed at the stage of generation of the SQL query text. If the value of the test is true the content of if element is included into the resulting query. In your case depending on the screenFunction parameter passed to mybatis mapper method one of three conditions are generated.
If value of screenFunction is MAIL then:
WHERE
IncomingFlightId=#{flightId}
and ContentCode = 'M'
order by ContentCode ASC
If value of screenFunction is CARGO then:
WHERE
IncomingFlightId=#{flightId}
and ContentCode Not IN('M')
order by ContentCode ASC
Otherwise (if value of screenFunction is not MAIL and is not CARGO):
WHERE
IncomingFlightId=#{flightId}
order by ContentCode ASC
Only after the query text is generated it is executed via JDBC against the database.
So if you want to run the query manually you need to try one of these queries.
One thing that you may want to do to make it easier is to enable logging of SQL queries and parameters passed to them so you can more easily rerun them.

TSQL IF THEN WHERE something ELSE WHERE something else

I need to transform this c# line into a SQL query:
from t in table where type == 0 ? t.colA=1 : t.ColB=1
I've tried something like
select * from table t where
BEGIN IF #type=0 THEN t.colA=1 END
BEGIN IF #type=1 THEN t.colB=1 END
but I get
Incorrect syntax near the keyword 'BEGIN'.
and
Incorrect syntax near the keyword 'THEN'.
What am I doing wrong? It is even possible to do this as a SQL command?
Just use boolean expressions:
select *
from table t
where (#type = 0 and t.colA = 1) or
(#type = 1 and t.colB = 1)
If you want everything when #type is not 0 or 1, then include:
select *
from table t
where (#type = 0 and t.colA = 1) or
(#type = 1 and t.colB = 1) or
(#type not in (0, 1)) -- adjust if #type could be NULL
You could use CASE:
select * from table t
where (CASE #type WHEN 0 THEN colA
WHEN 1 THEN colB
END) = 1
CASE is the "if" function in TSQL
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/case-transact-sql?view=sql-server-2017

How to check if bit variable is true or false in sql server?

I have a simple query and all I want to do is check if this variable is true or false, and for some reason it always returns false.
DECLARE #CappedIFCheck BIT
SET #CappedIFCheck = (SELECT distinct 1
FROM mytable
WHERE 1=1);
select #CappedIFCheck
IF (#CappedIFCheck = 'True')
BEGIN
SELECT 'true';
END
ELSE
BEGIN
SELECT 'false';
END
When comparing BIT values in Sql Server, use literal values 1 and 0 instead of 'True' and 'False'.
IF (#CappedIFCheck = 1) ...
A bit variable in SQL Server can have three values. 0, 1 and NULL.
The strings 'true' and 'false' map to 1 and 0 respectively.
Your code does not take account of the third possible value. If mytable is empty then the variable will not be initialised and have the value NULL.
SELECT CASE #CappedIFCheck
WHEN 'True' THEN 'true'
WHEN 'False' THEN 'false'
ELSE 'unknown'
END
I'm not sure exactly what your code is trying to do but that is a very inefficient way of going about things. You should use EXISTS instead.
Try the set clause like this:
SET #CappedIFCheck = ISNULL((select 1 where exists (select 1 from MyTable where 1=0)),0)

Check if a SQL Select statement returns no rows

I have a select statement
SELECT QBalance
FROM dbo.CustomerBalance
WHERE (CustomerID = 1) AND (MarchentID = #MerchantId)
I want to check if that statement returns 0 rows. I tried to use the ISNULL and IFNULL but it seems that I'm missing something.
To find out whether no matching rows exist you can use NOT EXISTS. Which can be more efficient than counting all matching rows
IF NOT EXISTS(SELECT * FROM ...)
BEGIN
PRINT 'No matching row exists'
END
If this is SQL Server, try ##ROWCOUNT.
SELECT COUNT(*)
FROM dbo.CustomerBalance
WHERE (CustomerID = 1) AND (MarchentID = #MerchantId)
If you get 0, you got 0. :)
You can use ##ROWCOUNT. For e.g.
SELECT QBalance
FROM dbo.CustomerBalance
WHERE (CustomerID = 1) AND (MarchentID = #MerchantId)
--This will return no of rows returned by above statement.
SELECT ##ROWCOUNT
You will get 0 if first statement will not return any rows. You can also use if statement to check that just after first statement. e.g.
IF ##ROWCOUNT <> 0
PRINT 'Select statement is returning some rows'
ELSE
PRINT 'No rows returned'
try this:
SELECT ISNULL(QBalance, 'ReplaceValue')
FROM dbo.CustomerBalance
WHERE (CustomerID = 1) AND (MarchentID = #MerchantId)
Could also use an outer ISNULL check?
SELECT ISNULL((
SELECT QBalance
FROM dbo.CustomerBalance
WHERE (CustomerID = 1) AND (MarchentID = #MerchantId)), 0)

Resources