How to flip bit fields in T-SQL? - sql

I'm trying to flip a bit field in SQL Server using an update query, that is, I want to make all the 0's into 1's and vice versa. What's the most elegant solution?
There doesn't seem to be a bitwise NOT operator in T-SQL (unless I'm missing something obvious) and I haven't been able to find any other way of performing the update.

You don't need a bitwise-not for this -- just XOR it with 1 / true.
To check it:
select idColumn, bitFieldY, bitFieldY ^ 1 as Toggled
from tableX
To update:
update tableX
set bitFieldY = bitFieldY ^ 1
where ...
MSDN T-SQL Exclusive-OR (^)

Why not a simple bitfield = 1 - bitfield?

Another way is
DECLARE #thebit bit = 1, #theflipbit bit
SET #theflipbit = ~ #thebit
SELECT #theflipbit
where "~" means "NOT" operator. It's clean and you get a good code to read.
"negate the bit" is even cleaner and it does exactly what the "NOT" operator was designed for.

I was pretty sure that most SQL flavors had a bitwise NOT, so I checked and there does appear to be one in TSQL.
From the documentation, it's the character ~.

UPDATE tblTest SET MyBitField = CASE WHEN MyBitField = 1 THEN 0 ELSE 1 END
It's bland but everyone will understand what it's doing.
EDIT:
You might also need to account for nulls as suggested in the comments. Depends on your req's of course.
UPDATE tblTest SET
MyBitField = CASE
WHEN MyBitField = 1 THEN 0
WHEN MyBitField = 0 THEN 1
ELSE NULL -- or 1 or 0 depending on requirements
END

A simple bitwise NOT operator (~) worked for me in SQL Server 2014 - 12.0.2269.0
In the update clause inside your T-SQL -
Update TableName
SET [bitColumnName] = ~[bitColumnName],
....
WHERE ....
Hope this helps
Ref - https://learn.microsoft.com/en-us/sql/t-sql/language-elements/bitwise-not-transact-sql

Did you try this?
UPDATE mytable SET somecolumn =
CASE WHEN somecolumn = 0 THEN 1
WHEN somecolumn IS NULL THEN NULL
WHEN somecolumn = 1 THEN 0
END

query (vb)
x = "select x from table"
update (vb)
"update table set x=" Not(x*(1))

Related

Problem with field not equal to null in case statement

So I have EXISTS in huge query which looks like this:
EXISTS(
SELECT
*
FROM
ExistTable
WHERE
ExTableFieldA = #SomeGuid AND
ExTableFieldB = MainTableFieldB AND
ExTableFieldA <> (
CASE
WHEN MainTableFieldZ = 10 THEN MainTableFieldYYY
ELSE NULL
END
)
)
The problem comes from ELSE part of CASE statement, this ExTableFieldA <> NULL will be always false. I could easily write another parameter #EmptyGuid and make it equal to '00000000-0000-0000-0000-000000000000' and everything will work but is this the best approach ?
Pretty much I want to execute another check into the exist for the small size of the records which return the "main" query.
How about removing the case and just using boolean logic?
WHERE ExTableFieldA = #SomeGuid AND
ExTableFieldB = MainTableFieldB AND
(MainTableFieldZ <> 10 OR ExTableFieldA <> MainTableFieldYYY)
I would also recommend that you qualify the column names by including the table alias.
Note: This does assume that MainTableFieldZ is not NULL. If that is a possibility than that logic can easily be incorporated.
ELSE NULL is implied even if you don't list it, but you could use ISNULL here.
ISNULL(ExTableFieldA,'') <> (
CASE
WHEN MainTableFieldZ = 10 THEN MainTableFieldYYY
ELSE ''
END
)
You may need to use some other value like 9999 instead of ''

SQL Server: interpreting 'y' as BIT value

In C, when you compared true/false value to 1/0, it worked very well.
I would want the similar possibility with SQL Server - when I have a bit column, I would like to compare myBitField = 'y' / myBitField = 'n'
Is there anything I can do about that? Maybe change some SQL interpreter settings or something?
Example of what I would like to do:
select * from
(
select CAST(1 AS BIT) as result
) as main
where main.result = 'y'
Currently, it throws an error, and I would like it to return 1/true/'y', whatever, but I would like it to be able to make that comparison.
I suppose you want to do it for some yes/no thing. But this is generally a wrong concept, your application which is accessing the SQL Server should interpret y as a 1 and n as a 0 and afterwards set the correct parameters for the query. You should not (actually I'm temped to write "must not") do this in SQL Server, that's what you have a business logic for.
As others have said, BIT and CHAR / VARCHAR are entirely different datatypes. But if you want to cast them during the select, you can use CASE expression like so:
-- Reading string as BIT
SELECT CAST(CASE RESULT WHEN 'Y' THEN 1 WHEN 'N' THEN 0 ELSE NULL END AS BIT) RESULT
-- Reading BIT as string
SELECT CAST(CASE RESULT WHEN 1 THEN 'Y' WHEN 0 THEN 'N' ELSE NULL END AS CHAR(1)) RESULT
And that's about as far as your options go here, far as I can understand. :)

An expression of non-boolean type specified in a context where a condition is expected, near 'END'

So maybe someone can point me in the right direction of what is causing this error? I've been fighting with this for a couple of hours and searching the web, and I can't figure out what I'm doing wrong here. It's included as part of a stored procedure, I don't know if that matters, if it does I can include that as well. Tables and field names have been changed to protect the innocent... meaning my job. Thanks.
SELECT
/* The fields are here*/
FROM
/* my joins are here */
WHERE
(Table.Field = stuff)
AND
(Table.Field2 = otherstuff)
AND
(Table2.Field3 = someotherstuff)
AND
CASE #param1
WHEN 0 THEN 'Table.Field IS NULL'
WHEN 1 THEN 'Table.Field2 IS NOT NULL'
ELSE ''
END
Thanks for the responses. Technically egrunin was the correct answer for this question, but OMG Ponies and Mark Byers were pretty much the same thing just missing that last piece. Thanks again.
I'm pretty sure the other answers leave out a case:
WHERE
(Table.Field = stuff)
AND
(Table.Field2 = otherstuff)
AND
(Table2.Field3 = someotherstuff)
AND
(
(#param1 = 0 and Table.Field IS NULL)
OR
(#param1 = 1 and NOT Table.Field2 IS NULL)
OR
(#param1 <> 0 AND #param1 <> 1) -- isn't this needed?
)
You are returning a string from your case expression, but only a boolean can be used. The string is not evaluated. You could do what you want using dynamic SQL, or you could write it like this instead:
AND (
(#param1 = 0 AND Table.Field IS NULL) OR
(#param1 = 1 AND Table.Field IS NOT NULL)
)
You can't use CASE in the WHERE clause like you are attempting
The text you provided in the CASE would only run if you were using dynamic SQL
Use:
WHERE Table.Field = stuff
AND Table.Field2 = otherstuff
AND Table2.Field3 = someotherstuff
AND ( (#param1 = 0 AND table.field IS NULL)
OR (#param1 = 1 AND table.field2 IS NOT NULL))
...which doesn't make sense if you already have Table.Field = stuff, etc...
Options that would perform better would be to either make the entire query dynamic SQL, or if there's only one parameter - use an IF/ELSE statement with separate queries & the correct WHERE clauses.

Equivalent to VB AndAlso in SQL?

Is there an equivalent to VB's AndAlso/OrElse and C#'s &&/|| in SQL (SQL Server 2005). I am running a select query similar to the following:
SELECT a,b,c,d
FROM table1
WHERE
(#a IS NULL OR a = #a)
AND (#b IS NULL OR b = #b)
AND (#c IS NULL OR c = #c)
AND (#d IS NULL OR d = #d)
For example, if the "#a" parameter passed in as NULL there is no point in evaluating the 2nd part of the WHERE clause (a = #a). Is there a way to avoid this either by using special syntax or rewriting the query?
Thanks,
James.
The only way to guarantee the order of evaluation is to use CASE
WHERE
CASE
WHEN #a IS NULL THEN 1
WHEN a = #a THEN 1
ELSE 0
END = 1
AND /*repeat*/
In my experience this is usually slower then just letting the DB engine sort it out.
TerrorAustralis's answer is usually the best option for non-nullable columns
Try this:
AND a = ISNULL(#a,a)
This function looks at #a. If it is not null it equates the expression
AND a = #a
If it is null it equates the expression
AND a = a
(Since this is always true, it replaces the #b is null statement)
The query engine will take care of this for you. Your query, as written, is fine. All operators will "short circuit" if they can.
Another way is to do:
IF (#a > 0) IF (#a = 5)
BEGIN
END
Another if after the condition will do an "AndAlso" logic.
I want to emphesise that this is just a short way to write:
IF (#a > 0)
IF (#a = 5)
BEGIN
END
Take this example:
SELECT * FROM Orders
WHERE orderId LIKE '%[0-9]%'
AND dbo.JobIsPending(OrderId) = 1
Orders.OrderId is varchar(25)
dbo.JobIsPending(OrderId) UDF with int parameter
No short circuit is made as the conversion fails in dbo.JobIsPending(OrderId) when
Orders.OrderId NOT LIKE '%[0-9]%'
tested on SQL Server 2008 R2

sql query - true => true, false => true or false

Simple query, possibly impossible but I know there are some clever people out there :)
Given a boolean parameter, I wish to define my where clause to either limit a certain column's output - or do nothing.
So, given parameter #bit = 1 this would be the result:
where column = 1
given parameter #bit = 0 this would be the result:
where column = 1 or 0
i.e. have no effect/show all results (column is a bit field)
I'm not wanting dynamic sql - I can settle for fixing this in code but I just wondered if there's some clever magic that would make the above neat and simple.
Is there? I'm using sql server.
cheers :D
The answer column = 1 or #bit = 0 works if column may only be 0 or 1. If column may be any value you want: column = 1 or #bit = 0 and column = 0.
SELECT *
FROM mytable
WHERE column = 1 OR #bit = 0
If you have an index on column1, this one will be more efficient:
SELECT *
FROM mytable
WHERE column = 1 AND #bit = 1
UNION ALL
SELECT *
FROM mytable
WHERE #bit = 0
See this article in my blog for performance comparison of a single WHERE condition vs. UNION ALL:
IN with a comma separated list: SQL Server
where column BETWEEN #bit AND 1
select *
from MyTable
where (#bit = 0 OR MyColumn = 1)
select ...
from [table]
where #bit = 0 or (column = #bit)
I had come up with a different answer and felt dumb when seeing the consensus answer.
So, just for yucks, compared the two using my own database. I don't really know if they are really comparable, but my execution plans give a slight advantage to my goofy answer:
select *
from MyTable
where column <> case #bit when 1 then 0 else -1 end
I realize indices, table size, etc. can affect this.
Also, realized you probably can't compare a bit to a -1...
Just thought I'd share.
try this
select ...
from table
where column = case when #bit = 0 then 0 else column end
this works no matter what the datatype of column is (could even be a string, for example). If it were, of course, it would be a different default value (not 0)
WHERE column >= #bit
However, this only works for > 0 values in a numeric column. #bit will be implicitly cast to int, smallint etc because of data type precedence.