Ampersand (&) operator in a SQL Server WHERE Clause - sql-server

Sorry for the very basic question. What does the & operator do in this SQL
WHERE (sc.Attributes & 1) = 0
sc is an alias for a table which contains a column attributes.
I'm trying to understand some SQL in a report and that line is making it return 0 entries. If I comment it out it works. I have limited SQL knowledge and I'm not sure what the & 1 is doing.

& is the bitwise logical and operator - It performs the operation on 2 integer values.
WHERE (sc.Attributes & 1) = 0
The above code checks to see if sc.Attributes is an even number. Which is the same as saying that the first bit is not set.
Because of the name of the column though: "Attributes", then the "1" value is probably just some flag that has some external meaning.
It is common to use 1 binary digit for each flag stored in a number for attributes. So to test for the first bit you use sc.Attributes&1, to test for the second you use sc.Attributes&2, to test for the third you use sc.Attributes&4, to test for the fourth you use sc.Attributes&8, ...
The = 0 part is testing to see if the first bit is NOT set.
Some binary examples: (== to show the result of the operation)
//Check if the first bit is set, same as sc.Attributes&1
11111111 & 00000001 == 1
11111110 & 00000001 == 0
00000001 & 00000001 == 1
//Check if the third bit is set, same as sc.Attributes&4
11111111 & 00000100 == 1
11111011 & 00000100 == 0
00000100 & 00000100 == 1

It is a bitwise logical AND operator.

It's a bitwise and.

Seeing as you tagged this as sql server, I thought I'd add something from a different angle as also ran into one of these this week.
These can hurt the performance of your queries if used in the predicate. Very easy to manufacture an example of your own. Here is the snippet from my query
WHERE
advertiserid = #advertiserid
AND (is_deleted & #dirty > 0)
WHERE
advertiserid = #advertiserid
AND (is_deleted > 0 AND #dirty > 0)
by simply defining each column with a proper value this allowed the optimizer to remove a bookmark lookup and performance stats showed a X10 performance increase.

Related

Error during SqlBulkCopy WriteToServer - Message (Incorrect syntax near 'ALLOW_ENCRYPTED_VALUE_MODIFICATIONS'.))

I was trying to upload the data from my datatable using SqlBulkCopy. But after the line goes to WriteToServer(dt) the system returns an exception
Incorrect syntax near 'ALLOW_ENCRYPTED_VALUE_MODIFICATIONS'
I've already tried adding sqlBulkCopyOptions but the error is still the same.
Dim mapSessionNo As New SqlBulkCopyColumnMapping, mapBatchID As New SqlBulkCopyColumnMapping, mapPolicyID As New SqlBulkCopyColumnMapping, mapUpdateDts As New SqlBulkCopyColumnMapping, mapID As New SqlBulkCopyColumnMapping
Dim bulkcopy As SqlBulkCopy = New SqlBulkCopy(ConnectionString, SqlBulkCopyOptions.FireTriggers & SqlBulkCopyOptions.CheckConstraints & SqlBulkCopyOptions.KeepIdentity & SqlBulkCopyOptions.UseInternalTransaction)
bulkcopy.DestinationTableName = "BatchUpdateLog"
mapSessionNo = New SqlBulkCopyColumnMapping("SessionNo", "SessionNo")
mapBatchID = New SqlBulkCopyColumnMapping("BatchID", "BatchID")
mapPolicyID = New SqlBulkCopyColumnMapping("PolicyID", "PolicyID")
mapUpdateDts = New SqlBulkCopyColumnMapping("UpdateDts", "UpdateDts")
mapID = New SqlBulkCopyColumnMapping("ID", "ID")
bulkcopy.NotifyAfter = 10000
bulkcopy.ColumnMappings.Add(mapID)
bulkcopy.ColumnMappings.Add(mapSessionNo)
bulkcopy.ColumnMappings.Add(mapBatchID)
bulkcopy.ColumnMappings.Add(mapPolicyID)
bulkcopy.ColumnMappings.Add(mapUpdateDts)
bulkcopy.WriteToServer(dt)
bulkcopy.Close()
I expect the whole data table will be uploaded to the database. But the system returns an error when it comes to the WriteToServer line of code
I suspect that the issue is that here:
Dim bulkcopy As SqlBulkCopy = New SqlBulkCopy(ConnectionString, SqlBulkCopyOptions.FireTriggers & SqlBulkCopyOptions.CheckConstraints & SqlBulkCopyOptions.KeepIdentity & SqlBulkCopyOptions.UseInternalTransaction)
you are performing string concatenation on the SqlBulkCopyOptions values instead of combination. You combine Enum values with a bitwise Or. I suspect that you were going for a bitwise And, which would still be wrong. In C#, the & operator is a bitwise And but it's string concatenation in VB. That should be:
Dim bulkcopy As SqlBulkCopy = New SqlBulkCopy(ConnectionString, SqlBulkCopyOptions.FireTriggers Or SqlBulkCopyOptions.CheckConstraints Or SqlBulkCopyOptions.KeepIdentity Or SqlBulkCopyOptions.UseInternalTransaction)
EDIT: It's a bit counter-intuitive that you need to use Or when, logically, you want one value AND another value. It's perfectly logical if you understand bitwise logic though. Bitwise logic is basically Boolean logic on the individual bits of a numeric value. Let's say that you have two Enum values where one has the numeric value 4 and the other has the value 32. In binary, those two values would look like this:
0000 0100
0010 0000
Bitwise operations work on corresponding pairs of bits and treat 1 as TRUE and 0 as FALSE. In Boolean logic, the result of an OR operation is TRUE if either operand is TRUE, otherwise it is FALSE. That means that, in bitwise operations, a bit in the result will be 1 if either of the corresponding bits in the operands is 1, otherwise it will be 0. That means that the result of a bitwise OR on those two values will have a 1 anywhere either operand has a 1 and a 0 everywhere else:
0010 0100
If you did a bitwise AND then the result would only have a 1 where both operands had a 1 and 0 everywhere else. Those two operands don't both have a 1 anywhere so the result would be all 0:
0000 0000
When it comes to Enums, you use bitwise OR to combine, bitwise AND to mask, bitwise AND NOT to test and bitwise XOR to toggle. By "mask" I mean remove all but certain values. For instance, let's say that you have an unknown combination of the same Enum as before and you want to mask out all but the 4 and 32 values. You would first combine 4 and 32 with a bitwise OR and then AND that with your current value. The result of a bitwise AND will have a 1 where both operands have a 1, so it can only have a 1 in the 4 or 32 position but it will only have a 1 in those positions if the original value does, e.g. if the original value was:
1010 1010
and we AND it with:
0010 0100
then we get:
0010 0000
Hopefully this helps a bit with bitwise logic.
have you tried SqlBulkCopyOptions.Default?
or what about the ALLOW_ENCRYPTED_VALUE_MODIFICATIONS user property? https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-user-transact-sql?view=sql-server-2017
Cheers

what does | 0x01 do in C language?

I have seen something like this in some of my coworkers code today :
I2C1ADB1= (slave_read_address | 0x01);
What does this | 0x01 part do? Does it end 1 at the end of the bits?
Let's say I2C1ADB1=0b00000000. If I use above line, will the new I2C1ADB1 be 0b000000001? Will it also increase the bit count from 8 to 9?
'|' is bit-wise OR operator in C. It does bit-wise OR between two values and return the final value.
I2C1ADB1= (slave_read_address | 0x01);
Assume slave_read_address in binary is 0bxxxxxxxx where each x is bit value 1 or 0. Similarly, 0x01 in binary is 0x00000001.
As you know OR will return true (1) if at least one of the value is true (1). Otherwise returns false (0).
So After the above C line, I2C1ADB1 will have 0bxxxxxxx1.
The operator will not ADD bits. Usually '|' (OR) operator is used to set a particular set of bits without altering other bits.
The statement I2C1ADB1 = (slave_read_address | 0x01); stores the value of slave_read_address into I2C1ADB1, forcing the low order bit to 1.
Your interpretation is incorrect, the value is not shifted, no extra bit is appended. The lowest bit is set to 1:
0 becomes 1,
1 is unchanged,
2 becomes 3,
3 does not change,
4 becomes 5,
etc.
Because on the left you have a variable and on the right a constant the result is to set all the corresponding 1 bits from the constant in the variable. In this case you’re right: it sets the last bit. No bit count increase occur!

Switching the bits

How can I switch the certain bits of a number? For example, given bit representation (just an example, the syntax is surely wrong!):
someNumber = 00110111
changeNumber = 11100110
Then how can I change the far right bit of someNumber with the far right bit of the changeNumber without changing the rest bits of the someNumber? So the result would be:
00110111 //someNumber
11100110 //changeNumber
________
00110110
Extract the far right bit of changeNumber:
changeNumber & 1
Remove the far right bit of someNumber:
someNumber & ~1
And OR them together:
(changeNumber & 1) | (someNumber & ~1)
To set bit n, change 1 to 2n.
One a similar line as Martin,
Test the last bit of someNumber, and use the result to select the operation to change some number ('bitwise and' or 'bitwise or')
#DEFINE SWITCH_MASK_OR 0b00000001
#DEFINE SWITCH_MASK_AND (~SWITCH_MASK_OR)
...
result = changeNumber & SWITCH_MASK_OR ? \
someNumber | SWITCH_MASK_OR : someNumber & SWITCH_MASK_AND;
I suggest the following steps:
Clear the last bit of someNumber.
someNumber &= ~1
Extract the last bit of changeNumber
int lastBit = changeNumber & 1;
Set the last bit of someNumber:
someNumber |= lastBit;
AND the changenumber with a mask of 00000001, so extracting the state of the lowest bit, all others set to 0: 00000000
AND the somenumber with a mask of 11111110, so setting the lowest bit to 0 while leaving the rest unchanged: 00110110
OR the two results together, so : 00110110

Serial data parsing

I have a probably simple question, which I just cant seem to understand.
I am creating a serial parser for a datalogger which sends a serial stream. Under the documentation for the product a calculation is stated, which I don't understand.
Lateral = Data1 And 0x7F + Data2 / 0x100
If (Data1 And 0x80)=0 Then Lateral = -Lateral
What does Data1 And 0x7f means? I know that 7F is 127, but besides that I don't understand the combination with the And statement.
What would the real formula look like?
Bitwise AND -- a bit in the output is set if and only if the corresponding bit is set in both inputs.
Since your tags indicate that you're working in C, you can perform bitwise AND with the & operator.
(Note that 0x7F is 01111111 and 0x80 is 10000000 in binary, so ANDing with these correspond respectively to extracting the lower seven bits and extracting the upper bit of a byte.)
1st sentence
Lateral = Data1 And(&) 0x7f + Data2/ 0x100
means take the magnitude of Data1(Data and 0x7f) and add to it the value of Data2/256
2nd sentence
check the sign od Data1 and assign the same to Lateral.

rewrite T-SQL bitwise logic

How do I rewrite this T-SQL code to produce the same results
SELECT ACC.Title,
ACC.AdvertiserHierarchyId,
1 AS Counter
FROM admanAdvertiserHierarchy_tbl ACC
JOIN dbo.admanAdvertiserObjectType_tbl AOT ON AOT.AdvertiserObjectTypeId = ACC.AdvertiserObjectTypeId
WHERE (EXISTS
(SELECT 1
FROM dbo.admanAdvertiserHierarchy_tbl CAMP
JOIN dbo.admanAdvertiserAdGroup_tbl AG ON CAMP.AdvertiserHierarchyId = AG.AdvertiserHierarchyId
JOIN dbo.admanAdvertiserCreative_tbl AC ON AC.AdvertiserAdGroupId = AG.AdvertiserAdGroupId
AND CAMP.ParentAdvertiserHierarchyId = ACC.AdvertiserHierarchyId
WHERE CAMP.ERROR = 0
AND AC.Dirty & 7 > 0
AND AC.ERROR = 0
AND AG.ERROR = 0 ))
its preventing the optimizer from using indexes efficiently .
trying to achieve the following results
Title AdvertiserHierarchyId Counter
trcom65#travelrepublic.co.uk 15908 1
paul570#travelrepublic.co.uk 37887 1
es88#travelrepublic.co.uk 37383 1
it004#travelrepublic.co.uk 27006 1
011 10526 1
013 10528 1
033 12013 1
062 17380 1
076 20505 1
this is a count of the dirty tinyint column
Dirty total
0 36340607
1 117569
2 873553
3 59
that links to a static reason table
DirtyReasonId Title
0 Nothing
1 Overnight Engine
2 End To End
3 Overnight And End To End
4 Pause Resume
5 Overnight Engine and Paused
6 Overnight Engine E2E and Paused
7 All Three
If you are asking specifically about the use of the BITWISE AND operator, I believe you are correct, and it's unlikely that SQL Server sees that as sargable, at least, not with an index with Dirty as a leading column.
You are showing only the lowest two bits in use (maximum value of Dirty is 3), yet you are testing the lowest three bits.
So, AC.Dirty > 0 would return an equivalent result, given that 3 is largest value of Dirty. But there is a possibility that other (higher-order) bits are set, for example Dirty could be set to 8. So, if the intent is to check ONLY the lowest three bits, then we need to ensure that we test only the three lowest-order bits. This expression would do that, and one of the predicates is sargable:
( AC.Dirty > 0 AND AC.Dirty % 8 > 0 )
This basically tests first whether ANY bits in AC.Dirty are set, and then checks if any of the last three bits are set. (We're using the MODULO division operator to return the remainder of AC.Dirty divided by 8, which will of course return an integer value between 0 and 7. If we get a zero, then we know that none of the lower three bits are set, else we know at least one of the bits is set.
Just to be clear: the predicate on AC.Dirty > 0 is redundant. It's included here in case you are wanting to make sure that database can at least consider using an existing index with Dirty as a leading column.
I will mention that another option to consider would be adding a persisted COMPUTED COLUMN on the expression, and create an index on it. But that seems a bit overkill for what you need here.
If you are asking specifically about getting an index used on table admanAdvertiserCreative_tbl (AC), then likely your best candidate would be covering index on (AdvertiserAdGroupId, Error, Dirty).
The SQL rewrite below should return equivalent results, perhaps with better performance (depending on your data distribution, indexes, et al.)
Basically, replace the EXISTS (correlated subquery) with a JOIN to a subquery. The subquery returns distinct values of CAMP.ParentAdvertiserHierarchyId, which is the column you referenced to correlate the subquery.
This may or may not make use of any indexes, depending on what indexes are available. (It's likely have clustered unique indexes on the primary keys, and have non-clustered indexes on the foreign keys, which should help join performance.)
Untested:
SELECT ACC.Title,
ACC.AdvertiserHierarchyId,
1 AS Counter
FROM admanAdvertiserHierarchy_tbl ACC
JOIN dbo.admanAdvertiserObjectType_tbl AOT
ON AOT.AdvertiserObjectTypeId = ACC.AdvertiserObjectTypeId
JOIN (SELECT CAMP.ParentAdvertiserHierarchyId
FROM dbo.admanAdvertiserHierarchy_tbl CAMP
JOIN dbo.admanAdvertiserAdGroup_tbl AG
ON CAMP.AdvertiserHierarchyId = AG.AdvertiserHierarchyId
JOIN dbo.admanAdvertiserCreative_tbl AC
ON AC.AdvertiserAdGroupId = AG.AdvertiserAdGroupId
WHERE CAMP.ERROR = 0
AND ( AC.Dirty > 0 AND AC.Dirty % 8 > 0 )
AND AC.ERROR = 0
AND AG.ERROR = 0 )
GROUP BY CAMP.ParentAdvertiserHierarchyId
) c
ON c.ParentAdvertiserHierarchyId = ACC.AdvertiserHierarchyId

Resources