Bit field in where clause - sql

I have a situation where I want to search for a field in the where clause only if the bit variable is 1 else ignore it.
#Active bit = 0
select * from Foo where firstname = 'xyz' and
if(#active=1)
then search on the Active column else ignore the filtering on the Active column. How can I have that in a simple condition instead of checking each parameter seperately and then building the where clause

Just simple logic will usually suffice:
select * from Foo where firstname = 'xyz' and
(#Active = 0 or Active = <filter condition>)
For general advice about writing code for arbitrary search conditions, you could do worse than read Erland Sommarskog's Dynamic Search Conditions in T-SQL

it seems like Active is the Actual Column as well in your table.
using Case stmt you can make the search efficient as it will use appropriate indexes you may have on this table.
DECLARE #Active BIT=0
SELECT *
FROM Foo
WHERE firstname = 'a'
AND active = CASE WHEN #Active=1 THEN #Active ELSE Active END

How about:
DECLARE #Active bit
if #Active = 1
BEGIN
(select * from Foo where firstname = 'bar' and Active = --condition)
END
else
BEGIN
(select * from Foo where firstname = 'bar')
END
of course, something will have to set the value for #Active somewhere between the declaration and the if...else statement.

you can write this as below
select * from Foo where firstname = 'xyz' and (#isactive=0 or (some conditions))

Related

Is there a way to use in or = with a case statement in the where clause in sql?

I have a stored procedure that may or may not get a string list of int ids. When it doesn't get it the value is: ' '. Other wise its something like this: '500,507,908'
I'm trying to use it like this:
select ID as projectTeamId, Employee_ID, Supervisor_ID
from ProjectTeam
where Project_ID = #projectId and IsDeleted = 0 and
ID in (CASE #stringList WHEN '' THEN ID ELSE (SELECT * from TurnListStringIntoTable(#stringList)) END)
to get a result set but it errors out with this code when the string list comes in blank:
An error has occurred while processing Report 'MassReleaseHoursReport':
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I know its an issue where id needs to = id instead of being in id. Any ideas on how I can have the case statement work with #stringList = '' then id = id else id in (SELECT * from TurnListStringIntoTable(#stringList))?
TurnListStringIntoTable returns a table from a string list which in my case is just the project Team ID
I would recommend boolean logic rather than a case expression:
where
Project_ID = #projectId
and IsDeleted = 0
and (
#stringList = ''
or id in (select * from TurnListStringIntoTable(#stringList))
)
Unrelated side note: if you are running SQL Server, as I suspect, and your version is 2016 or higher, you can use built-in function string_split() instead of your customer splitter.
Sure!
All you have to do is use the parameterless flavor of case:
select *
from my_table t
where t.col_1 = case
when #var in (1,2,3) then "foo"
when #var = 4 then "bar"
when #var in (5,6,7) then "baz"
else "bat"
end
One might note that the when expressions are not limited to looking at the same variable in any way. The only requirement is that they have to be a boolean expression. They're evaluated in order top to bottom. The first when clause that evaluates to true wins and it's then value is returned.
If there's no else and evaluation fails to find a match, the result value is null.
Your problem though, is that case expressions
return a single value, and
that value must be of the same type. Can have it returning a string in some cases and a table variable in another.
So... your where clause should look something like this:
where ...
and 'true' = case
when #stringList = '' then 'true'
when ID in ( select *
from TurnListStringIntoTable(#stringList)
) then 'true'
else 'false'
end
You'll probably find, too, that invoking a user-defined function to convert a comma-delimited string into a table variable within the where clause is probably a Bad Idea™ due to the performance impact that that will have.
You'd be better off to move your TurnListStringIntoTable call outside of the select statement, thus:
declare #list = TurnListStringIntoTable(#stringlist)
select ...
from ProjectTeam pt
where . . .
and #stringlist = ''
OR exists ( select * from #list x where x.ID = pt.ID )

How to translate nested CASE statement in WHERE clause

I have a stored procedure that was not written by me.
Could you please help me translate CASE statement in WHERE clause?
--Declaring the parameter for SP
DECLARE
#CompanyGuids varchar(8000) = '29634AF7-D0A2-473D-9574-405C23E10F02'
--Declaring table variable that will contain only CompanyGuid
DECLARE #CompanyGuidsTbl TABLE(Guid uniqueidentifier)
IF #CompanyGuids IS NULL
BEGIN
INSERT INTO #CompanyGuidsTbl
SELECT DISTINCT CompanyGuid FROM tblCompanies
END
ELSE
BEGIN
INSERT INTO #CompanyGuidsTbl
SELECT * FROM dbo.StringOfGuidsToTable(#CompanyGuids,',')
END
--Select statement
SELECT Col1,
Col2,
Col3
FROM MyTable1 INNER JOIN MyTable2
/* this is where I am confused */
WHERE
CASE WHEN #CompanyGuids IS NOT NULL
THEN
CASE WHEN tblCompanies.CompanyGuid in (SELECT Guid FROM #CompanyGuidsTbl)
THEN 1 ELSE 0 END
ELSE 1
END = 1
Correct me if I'm wrong:
"So if the parameter #CompanyGuids is NOT NULL, then we are checking if table #CompanyGuidsTbl has assigned parameter and if it does - then we gonna use it, but if it does not - ??? "
Maybe there is a way to rewrite it?
Thanks
A poorly constructed statement for sure, but yes it is ultimately checking a truth statement where 1 = 1. First checks for an empty variable, then if the variable is not empty it checks if the CompanyGUID in tblCompanies is in the list supplied in the variable, returning 1 if it is found (thus 1 = 1 is true so the record is matched), or if it is not found (in which case 0 = 1, which is false so the record is not matched). Awful stuff!

Add condition only if data exists

I want to add a condition to the WHERE clause ONLY if a variable has data.
I tried with the following case statement, but it has a syntax error.
Declare #last_name varchar(10) = null;
Select * from TABLE1
Where FirstName = 'John'
AND CASE WHEN #last_name IS NOT NULL THEN LastName = #last_name
Select * from TABLE1
where FirstName = 'John'
AND (#last_name IS NULL OR LastName = #last_name)
Others have already posted better ways to write the logic you are trying to express, but just in case you need to use the CASE syntax in the future, remember that the syntax requires you to include the word END. This tells SQL where the expression finishes.
This is what a basic CASE expression would look like:
CASE
WHEN MyField = 'MyValue' THEN 'MyResult'
WHEN MyField = 'MyOtherValue' THEN 'MyOtherResult'
ELSE 'NoResult'
END
Any CASE expression must have at least the CASE, WHEN, THEN, and END. The ELSE isn't strictly necessary - just be aware that if you don't include it, then the expression will return a NULL if none of the WHEN conditions are met.
You can try the following:
Declare #last_name varchar(10) = null;
Select * from TABLE1
Where FirstName = 'John'
AND LastName = ISNULL(#last_name, LastName)
You can also replace ISNULL with COALESCE too.

SQL Statement Match Anything

I use a regex in my SQL statements for an app that look like this
SELECT * FROM table WHERE id = {{REPLACEME}}
However, sometimes I'm not giving a parameter to replace that string with. Is there a way to replace it with something that matches anything. I tried *, but that does not work.
SELECT * FROM table WHERE id = id will match all rows that have non-null id
SELECT * FROM table WHERE id = id OR id IS NULL will match all rows.
id is probably a primary key, so you can probably use the former.
Replace {{REPLACEME}} with
[someValidValueForYouIdType] OR 1=1
I can only describe my solution with an example. The #AllRec is a parameter:
Declare #AllRec bit
set #AllRec = {0|1} --as appropriate
SELECT *
FROM table
WHERE
(
id = {{REPLACEME}}
and #AllRec = 0
) OR (
#AllRec = 1
)
In this solution, if #AllRec is 1 then everything is returned, ignoring the id filter. If #AllRec is zero, then the id filter is applied and you get one row. You should be able to quickly adapt this to your current regex solution.
Using the Regex-Replace option opens you up to SQL Injection attacks.
Assuming your language has support for parameterized queries, try this modified version of Jacob's answer:
SELECT * FROM table WHERE (id = #id OR #id IS NULL)
The catch is that you'll always have to provide the #id value.
SELECT field1, field2
FROM dbo.yourTable
WHERE id = isnull(#var, id)
Not sure what language your using, and this code kind of scares me but...
var statement = "SELECT * FROM table";
If REPLACEME is not empty Then
statement += " WHERE id = {{REPLACEME}}"
End If

creating SQL command to return match or else everything else

i have three checkboxs in my application. If the user ticks a combination of the boxes i want to return matches for the boxes ticked and in the case where a box is not checked i just want to return everything . Can i do this with single SQL command?
I recommend doing the following in the WHERE clause;
...
AND (#OnlyNotApproved = 0 OR ApprovedDate IS NULL)
It is not one SQL command, but works very well for me. Basically the first part checks if the switch is set (checkbox selected). The second is the filter given the checkbox is selected. Here you can do whatever you would normally do.
You can build a SQL statement with a dynamic where clause:
string query = "SELECT * FROM TheTable WHERE 1=1 ";
if (checkBlackOnly.Checked)
query += "AND Color = 'Black' ";
if (checkWhiteOnly.Checked)
query += "AND Color = 'White' ";
Or you can create a stored procedure with variables to do this:
CREATE PROCEDURE dbo.GetList
#CheckBlackOnly bit
, #CheckWhiteOnly bit
AS
SELECT *
FROM TheTable
WHERE
(#CheckBlackOnly = 0 or (#CheckBlackOnly = 1 AND Color = 'Black'))
AND (#CheckWhiteOnly = 0 or (#CheckWhiteOnly = 1 AND Color = 'White'))
....
sure. example below assumes SQL Server but you get the gist.
You could do it pretty easily using some Dynamic SQL
Lets say you were passing your checkboxes to a sproc as bit values.
DECLARE bit #cb1
DECLARE bit #cb2
DECLARE bit #cb3
DECLARE nvarchar(max) #whereClause
IF(#cb1 = 1)
SET #whereClause = #whereClause + ' AND col1 = ' + #cb1
IF(#cb2 = 1)
SET #whereClause = #whereClause + ' AND col2 = ' + #cb2
IF(#cb3 = 1)
SET #whereClause = #whereClause + ' AND col3 = ' + #cb3
DECLARE nvarchar(max) #sql
SET #sql = 'SELECT * FROM Table WHERE 1 = 1' + #whereClause
exec (#sql)
Sure you can.
If you compose your SQL SELECT statement in the code, then you just have to generate:
in case nothing or all is selected (check it using your language), you just issue non-filter version:
SELECT ... FROM ...
in case some checkboxes are checked, you create add a WHERE clause to it:
SELECT ... FROM ... WHERE MyTypeID IN (3, 5, 7)
This is single SQL command, but it is different depending on the selection, of course.
Now, if you would like to use one stored procedure to do the job, then the implementation would depend on the database engine since what you need is to be able to pass multiple parameters. I would discourage using a procedure with just plain 3 parameters, because when you add another check-box, you will have to change the SQL procedure as well.
SELECT *
FROM table
WHERE value IN
(
SELECT option
FROM checked_options
UNION ALL
SELECT option
FROM all_options
WHERE NOT EXISTS (
SELECT 1
FROM checked_options
)
)
The inner subquery will return either the list of the checked options, or all possible options if the list is empty.
For MySQL, it will be better to use this:
SELECT *
FROM t_data
WHERE EXISTS (
SELECT 1
FROM t_checked
WHERE session = 2
)
AND opt IN
(
SELECT opt
FROM t_checked
WHERE session = 2
)
UNION ALL
SELECT *
FROM t_data
WHERE NOT EXISTS (
SELECT 1
FROM t_checked
WHERE session = 2
)
MySQL will notice IMPOSSIBLE WHERE on either of the SELECT's, and will execute only the appropriate one.
See this entry in my blog for performance detail:
Selecting options
If you pass a null into the appropriate values, then it will compare that specific column against itself. If you pass a value, it will compare the column against the value
CREATE PROCEDURE MyCommand
(
#Check1 BIT = NULL,
#Check2 BIT = NULL,
#Check3 BIT = NULL
)
AS
SELECT *
FROM Table
WHERE Column1 = ISNULL(#Check1, Column1)
AND Column2 = ISNULL(#Check2, Column2)
AND Column3 = ISNULL(#Check3, Column3)
The question did not specify a DB product or programming language. However it can be done with ANSI SQL in a cross-product manner.
Assuming a programming language that uses $var$ for variable insertion on strings.
On the server you get all selected values in a list, so if the first two boxes are selected you would have a GET/POST variable like
http://url?colors=black,white
so you build a query like this (pseudocode)
colors = POST['colors'];
colors_list = replace(colors, ',', "','"); // separate colors with single-quotes
sql = "WHERE ('$colors$' == '') OR (color IN ('$colors_list$'));";
and your DB will see:
WHERE ('black,white' == '') OR (color IN ('black','white')); -- some selections
WHERE ('' == '') OR (color IN ('')); -- nothing selected (matches all rows)
Which is a valid SQL query. The first condition matches any row when nothing is selected, otherwise the right side of the OR statement will match any row that is one of the colors. This query scales to an unlimited number of options without modification. The brackets around each clause are optional as well but I use them for clarity.
Naturally you will need to protect the string from SQL injection using parameters or escaping as you see fit. Otherwise a malicious value for colors will allow your DB to be attacked.