{"id":95170,"date":"2022-12-04T21:00:14","date_gmt":"2022-12-04T21:00:14","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=95170"},"modified":"2022-12-05T09:47:35","modified_gmt":"2022-12-05T09:47:35","slug":"dealing-with-the-bits-of-a-binary-value-in-sql-server","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/dealing-with-the-bits-of-a-binary-value-in-sql-server\/","title":{"rendered":"Dealing with the Bits of a Binary Value in SQL Server"},"content":{"rendered":"<h2>How you used to do it<\/h2>\n<p>For example, say you want to find all the read-write database using SQL Server 2022 system objects (I think this started back in 2005, in fact). You can write:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT name\r\nFROM sys.databases\r\nWHERE is_read_only = 0\r\n  AND name IN ('master','msdb','tempdb');<\/pre>\n<p>This will return those three system databases (because they still will always be read-write.) Using the old <code>sysdatabases<\/code> object, there was just a status column.<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT name, status\r\nFROM   sys.sysdatabases\r\nWHERE  name IN ('master','msdb','tempdb');<\/pre>\n<p>On my computer, and most likely yours, the output from this query is:<\/p>\n<p><code>name\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0status<br \/>\n-------------- -----------<br \/>\nmaster\u00a0 \u00a0 \u00a0 \u00a0 \u00a065544<br \/>\nmsdb\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a065544<br \/>\ntempdb\u00a0 \u00a0 \u00a0 \u00a0 \u00a065544<\/code><\/p>\n<p>I expect that 99% of the people reading this probably would expect there to be a status table that contained the values of status. Seeing that this is a base 2 number, you may be in that 1% that thinks this might be a bitmask. but unless you have and eidetic memory, you probably don&#8217;t know what all of the bits mean.<\/p>\n<p>A bitmask is a type of denormalization of values where instead of having a set of columns that have on or off values (no Null values), you encode it like:<\/p>\n<p><code>00000101<\/code><\/p>\n<p>Now the user has to figure out what bit each of the 8 bits are in the integer\/binary value to determine a value. For status, you can determine if a database is read-only using the 10th place. In versions of SQL Server before 2022, this was achieved by doing something like this:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT name, status &amp; 1024 AS is_readonly\r\nFROM   sys.sysdatabases\r\nWHERE  name IN ('master','msdb','tempdb');<\/pre>\n<p>The idea is that if the 10th bit in the number is set to 1, that it <code>AND<\/code> (<code>&amp;<\/code>) the value will return <code>1024<\/code> (since it will return <code>1024<\/code> (which is <code>POWER(2,10))<\/code>, and if it is value, it will return 0. (For the full list of bit values, check here: <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/system-compatibility-views\/sys-sysdatabases-transact-sql?view=sql-server-ver16\">https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/system-compatibility-views\/sys-sysdatabases-transact-sql?view=sql-server-ver16<\/a>)<\/p>\n<p>To see one that does return a match, check out the following 2 queries:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT name\r\nFROM   sys.databases\r\nWHERE  page_verify_option_desc = 'CHECKSUM'\r\n  AND  name IN ('master','msdb','tempdb');\r\n\r\nSELECT name\r\nFROM   sys.sysdatabases\r\nWHERE  status &amp; 65536 = 65536 \r\n AND name IN ('master','msdb','tempdb');<\/pre>\n<p>Both return three rows. Ok, so that is the basics, now lets look at some new syntax that makes this easier. For example, let&#8217;s take that <code>65536<\/code> value. It is 2 to the 16th power:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT POWER(2,16); --returns 65536<\/pre>\n<p>In SQL Server 2022, there are 5 new bitwise functions that have some value. For example, finding that a bit is set is a lot easier. The functions are:<\/p>\n<ul>\n<li>GET_BIT &#8211; See if a bit is set in a binary value<\/li>\n<li>SET_BIT &#8211; Set a bit in a binary value and return the new value<\/li>\n<li>LEFT_SHIFT, RIGHT_SHIFT &#8211; Shift all the bits left or right in a binary value<\/li>\n<li>BIT_COUNT &#8211; count the number of bits set in a value<\/li>\n<\/ul>\n<p>In our previous query of status and checksum, you could rewrite as:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT name, GET_BIT(status,10) AS is_readonly,\r\n\t\t\t GET_BIT(status,16) AS is_checksum\r\nFROM   sys.sysdatabases\r\nWHERE  name IN ('master','msdb','tempdb');<\/pre>\n<p>This returns:<\/p>\n<p><code>name\u00a0 \u00a0 \u00a0 \u00a0 \u00a0is_readonly is_checksum<br \/>\n------------ -----------\u00a0 -----------<br \/>\nmaster\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a00\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 1<br \/>\nmsdb\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a00\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 1<br \/>\ntempdb\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a00\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 1<\/code><\/p>\n<p>While I am STILL never in my life going to bless a bitwise solution in the year 2022 (much less the year 2000), this does make it far less unpleasant to work with.<\/p>\n<p>The rest of the bit functions are less useful in any solution I have ever seen, but they are interesting. For example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">DECLARE @value VARBINARY(64) = 0;\r\n\r\nSET @value = SET_BIT(@value,10);\r\n\r\nSELECT @value <\/pre>\n<p>This returns:<\/p>\n<p><code>-------------<\/code><br \/>\n<code>0x00000400<\/code><\/p>\n<p>Which is binary for <code>1024<\/code> (cast that value to <code>int<\/code> and you will see it). Note that while bits may be technically implemented in SQL Server internally as bits from the left, the bit operators treat values as if they were from the right (since that maps to our typical numbering system). Now let\u2019s set bits 1, 2, 3, and 4, then shift those bits right:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT SET_BIT(SET_BIT(SET_BIT(SET_BIT(0,1),2),3),4);<\/pre>\n<p>This outputs 30.. which may confuse you (it did me!), there is a bit 0 also. So it is 2 + 4 + 8 + 16 = 30<\/p>\n<p>Shifting 30 right 1 position:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT RIGHT_SHIFT(30,1);<\/pre>\n<p>This outputs 15, which is now 1 + 2 + 4 + 8. Let&#8217;s shift it again:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT RIGHT_SHIFT(30,2);<\/pre>\n<p>This is analogous to <code>RIGHT_SHIFT(RIGHT_SHIFT(30,1),1)<\/code> and returns 7. Bits fall off to the side, so, for example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT LEFT_SHIFT(RIGHT_SHIFT(30,100),100);<\/pre>\n<p>Returns 0, because the first set of <code>RIGHT_SHIFT<\/code> statements pushed the bits al the way off of the map. Swap the calls:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT RIGHT_SHIFT(LEFT_SHIFT(30,100),100);<\/pre>\n<p>And wait&#8230; it still falls off and returns 0. Why? Because this is technically a 31-bit integer (the sign takes off a bit), so you lose the bits anyhow. So be careful bit shifting!<\/p>\n<p>Finally, let&#8217;s look at the <code>BIT_COUNT<\/code> function. Using the 30 value, which we know is 2 + 4 + 8 + 16. Next, execute the following:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT BIT_COUNT(30);<\/pre>\n<p>And you will see that it returns 4, telling us there are 4 bits that are 1.<\/p>\n<p>Might be the bit of information you absolutely never have a valid use for, but the more you know, you may some day actually need it!<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this article, I want to talk about a topic that you may never need. The only time I have really had need to look at the bits in a byte pattern. In (what is now) ancient versions of SQL Server didn&#8217;t have such self-describing columns like in its metadata objects like it does now.&hellip;<\/p>\n","protected":false},"author":56085,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2,143531],"tags":[],"coauthors":[19684],"class_list":["post-95170","post","type-post","status-publish","format-standard","hentry","category-blogs","category-t-sql-programming-sql-server"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/95170","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/56085"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=95170"}],"version-history":[{"count":6,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/95170\/revisions"}],"predecessor-version":[{"id":95176,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/95170\/revisions\/95176"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=95170"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=95170"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=95170"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=95170"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}