Convert returned char from substring to binary - sql

I have written the following query:
substring(SELECT DB_NAME()), 1, 1)
I wish to convert the char which this query returns in to a binary string like "11001101".
What is the correct way to do it?
Thanks

You could use ASCII() to convert the character to a decimal integer and then use the script given on this answer to convert that to a "binary" string
You will possibly end up with something like this:
DECLARE #i INT = ASCII(SUBSTRING((DB_NAME()),1,1))
SELECT
CASE WHEN CONVERT(VARCHAR(8), #i & 128 ) > 0 THEN '1' ELSE '0' END +
CASE WHEN CONVERT(VARCHAR(8), #i & 64 ) > 0 THEN '1' ELSE '0' END +
CASE WHEN CONVERT(VARCHAR(8), #i & 32 ) > 0 THEN '1' ELSE '0' END +
CASE WHEN CONVERT(VARCHAR(8), #i & 16 ) > 0 THEN '1' ELSE '0' END +
CASE WHEN CONVERT(VARCHAR(8), #i & 8 ) > 0 THEN '1' ELSE '0' END +
CASE WHEN CONVERT(VARCHAR(8), #i & 4 ) > 0 THEN '1' ELSE '0' END +
CASE WHEN CONVERT(VARCHAR(8), #i & 2 ) > 0 THEN '1' ELSE '0' END +
CASE WHEN CONVERT(VARCHAR(8), #i & 1 ) > 0 THEN '1' ELSE '0' END

Related

SQL Server : find members from a number

Problem : How to find out from the given number from which numbers this number consists?
"Sunday = 1", "Monday = 2", "Tuesday = 4", Wednesday = 8", "Thursday =
16", "Friday = 32", "Saturday = 64"
For example : Given the number 109 this would signify Sunday, Tuesday, Wednesday, Friday, Saturday
You can do something like this.
CREATE FUNCTION dbo.Int2BinaryToWeekDay (#i INT) RETURNS NVARCHAR(2048) AS BEGIN
RETURN
CASE WHEN CONVERT(VARCHAR(16), #i & 64 ) > 0 THEN 'Saturday,' ELSE '' END +
CASE WHEN CONVERT(VARCHAR(16), #i & 32 ) > 0 THEN 'Friday,' ELSE '' END +
CASE WHEN CONVERT(VARCHAR(16), #i & 16 ) > 0 THEN 'Thurday,' ELSE '' END +
CASE WHEN CONVERT(VARCHAR(16), #i & 8 ) > 0 THEN 'Wed,' ELSE '' END +
CASE WHEN CONVERT(VARCHAR(16), #i & 4 ) > 0 THEN 'Tuesday,' ELSE '' END +
CASE WHEN CONVERT(VARCHAR(16), #i & 2 ) > 0 THEN 'Monday,' ELSE '' END +
CASE WHEN CONVERT(VARCHAR(16), #i & 1 ) > 0 THEN 'Sunday,' ELSE '' END
END;
GO
Now do following thing.
SELECT dbo.Int2BinaryToWeekDay(109)
Looks like a binary design. You need to use bitwise & operator to get the desired output.
Decimal = Binary
109 = 1101101
001 = 0000001
------&------
0000001 = 1
109 = 1101101
002 = 0000010
------&------
0000000 = 0
109 = 1101101
004 = 0000100
------&------
0000100 = 4
SQL Server has bitwise operators in built. you can utilize bitwise & for this like:
DECLARE #InputNum INT = 109
SELECT ISNULL(STUFF(CASE WHEN #InputNum & 1 > 0 THEN ', SUN' ELSE '' END +
CASE WHEN #InputNum & 2 > 0 THEN ', MON' ELSE '' END +
CASE WHEN #InputNum & 4 > 0 THEN ', TUE' ELSE '' END +
CASE WHEN #InputNum & 8 > 0 THEN ', WED' ELSE '' END +
CASE WHEN #InputNum & 16 > 0 THEN ', THU' ELSE '' END +
CASE WHEN #InputNum & 32 > 0 THEN ', FRI' ELSE '' END +
CASE WHEN #InputNum & 64 > 0 THEN ', SAT' ELSE '' END,1,2,''),'')
check the MS documentation for more detailed explaination of bitwise operators.

Getting error using "GROUP BY WITH ROLLUP" and "ORDER BY"

I could use your help on this. I am running a stored procedure in SQL Server 2008 R2 where I import data into an Excel worksheet.
I am able to import the information I need just fine except for the order of the output.
This is what I get:
1 - OUTCO
10 - OUT
11 - MATCH
12 - UNRSL
2 - INCO
3 - UNDEL
4 - MAIL
5 - NOTSU
6 - NOMSI
7 - RSRCH
9 - IN
9 - INCOM
I would like to display it with the proper numeric order.
1,2,3,4,5,6,7,9,9,10,11,12.
Here is the code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [Temp].[dmv_import]
#date DATE = NULL,
#import_type VARCHAR(5) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #date_work DATE
IF #date IS NULL
SET #date_work = GETDATE()
ELSE
SET #date_work = #date
SELECT
CASE
WHEN CONVERT(VARCHAR(8), import_code) + ' - ' + vi.import_reason IS NULL
THEN 'TOTAL'
ELSE CONVERT(VARCHAR(8), import_code) + ' - ' + vi.import_reason
END AS 'Category',
SUM(CASE WHEN CONVERT(DATE, vi.createdate, 101) = #date_work THEN 1 ELSE 0 END) AS 'received',
SUM(CASE WHEN CONVERT(DATE, vi.processed_date, 101) = #date_work THEN 1 ELSE 0 END) AS 'processed'
FROM
DIMSNet.dbo.voter_import vi
WHERE
vi.import_type IN ('DMV', 'DUP','INET')
AND import_code < 13
GROUP BY
CONVERT(VARCHAR(8), import_code) + ' - ' +vi.import_reason WITH ROLLUP
END
I have tried a few different ORDER BY clauses, but I keep getting conversion errors.
1) ORDER BY CONVERT(INT, LEFT((vi.import_code + ' - ' + vi.import_reason), 2))
2) ORDER BY LEFT((vi.import_code + ' - ' + vi.import_reason),PATINDEX('%[-]%',(vi.import_code + ' - ' + vi.import_reason)-1), CAST(RIGHT((vi.import_code + ' - ' + vi.import_reason), LEN((vi.import_code + ' - ' + vi.import_reason)) - 2) AS INT)
3) ORDER BY (CONVERT(VARCHAR(8), import_code) + ' - ' + vi.import_reason) ASC
4) order by
case
WHEN ISNUMERIC(vi.import_code + ' - ' + vi.import_reason) = 1
THEN CAST(vi.import_code + ' - ' + vi.import_reason AS FLOAT)
WHEN ISNUMERIC(LEFT((vi.import_code + ' - ' + vi.import_reason),1)) = 0 THEN ASCII(LEFT(LOWER((vi.import_code + ' - ' + vi.import_reason)),1))
ELSE 2147483647 End
None of these has returned a properly formatted output.
Any help would be appreciated.
Assuming your codes are all numeric, try this:
order by cast(max(import_code) as int)
If not, you can use a case expression:
order by (case when isnumeric(max(import_code)) = 1
then max(import_code)
end)
The key here is using the aggregation function to just order by the import_code.

Pervasive sql to Oracle

I am having trouble converting this Pervasive sql query to Oracle. The errors that oracle is giving me does not help. It is giving me an error at SQL_Date.
This is what I have in Pervasive:
SELECT
(CASE
WHEN joefdt = 0
THEN NULL
WHEN joefdt > 0
THEN CONVERT(LEFT(CONVERT(joefdt, SQL_CHAR),4) + '-' + RIGHT(LEFT(CONVERT(joefdt, SQL_CHAR),6),2) + '-' + RIGHT(CONVERT(joefdt, SQL_CHAR),2),SQL_DATE) END) AS EFFECTIVEDATE,
(CASE
WHEN jopost = 0
THEN NULL
WHEN jopost > 0
THEN CONVERT(LEFT(CONVERT(jopost, SQL_CHAR),4) + '-' + RIGHT(LEFT(CONVERT(jopost, SQL_CHAR),6),2) + '-' + RIGHT(CONVERT(jopost, SQL_CHAR),2),SQL_DATE) END) AS POSTDATE,
(SELECT ltrim(rtrim(cdname)) from money.code WHERE cdtabl = 3 AND cdnumb = joetyp) AS TYPE,
(SELECT ltrim(rtrim(cdname)) from money.code WHERE cdtabl = 5 AND cdnumb = jodelm) AS DELIVERYMETHOD,
joissd AS SHARESISSUED, jocand AS SHARESCANCELLED , joprsn AS BROKERID, joprsn AS TRANSACID
FROM money.jour
WHERE joiss = 1 AND joetyp in (2,3,4) AND (JOISSD > 0 OR JOCAND > 0)
AND joefdt >= '19920127' AND joefdt <= '20040726'
ORDER BY joefdt;
This is what I have tried, but it doesn't work:
SELECT
(CASE
WHEN joefdt = 0
THEN NULL
WHEN joefdt > 0
THEN CONVERT(substr(CONVERT(joefdt, SQL_CHAR),4) + '-' + RIGHT(LEFT(CONVERT(joefdt, SQL_CHAR),6),2) + '-' + RIGHT(CONVERT(joefdt, SQL_CHAR),2),SQL_DATE) END) AS EFFECTIVEDATE,
(CASE
WHEN jopost = 0
THEN NULL
WHEN jopost > 0
THEN CONVERT(substr(CONVERT(jopost, SQL_CHAR),4) + '-' + RIGHT(LEFT(CONVERT(jopost, SQL_CHAR),6),2) + '-' + RIGHT(CONVERT(jopost, SQL_CHAR),2),SQL_DATE) END) AS POSTDATE, ----Error at SQL_DATE
(SELECT ltrim(rtrim(cdname)) from money.code WHERE cdtabl = 3 AND cdnumb = joetyp) AS TYPE,
(SELECT ltrim(rtrim(cdname)) from money.code WHERE cdtabl = 5 AND cdnumb = jodelm) AS DELIVERYMETHOD,
joissd AS SHARESISSUED, jocand AS SHARESCANCELLED , joprsn AS BROKERID, joprsn AS TRANSACID
FROM money.jour
WHERE joiss = 1 AND joetyp in (2,3,4) AND (JOISSD > 0 OR JOCAND > 0)
AND joefdt >= '20000302' AND joefdt <= '20000302'
ORDER BY joefdt;
In Oracle CONVERT function translates character string from one character set to another. It cannot be used to convert something to date (does Pervasive means this?) or something. Oracle does not know identifiers SQL_DATE and SQL_CHAR, so you cannot use them in this manner. And last, conditions like joefdt >= '20000302' are doubtful. Maybe it means something like joefdt >= DATE '2000-03-02'

CASE statement plus modulo (%)

AIM: simple program; when my variable is divided into 3 it returns the word'hip', when it is divided into 5 it returns 'hop' and when it is divided into 3 & 5 at the same time it returns both words.
DECLARE #Zmienna AS INT
SET #Zmienna = 0
WHILE #Zmienna < 999
BEGIN
PRINT #Zmienna +
CASE
WHEN #Zmienna/3=% THEN ' hip'
WHEN #Zmienna/5=% THEN ' hop'
END
SET #Zmienna = #Zmienna + 1
END
Error
ERROR: Msg 156, Level 15, State 1, Line 8
Incorrect syntax near the keyword 'THEN'.
Msg 102, Level 15, State 1, Line 12
Incorrect syntax near 'END'.
Any idea?
I would use the remainder of the modulo (like you tried) and concatenate the two case statements (else you will never get hiphop if both conditions are true). Also you need the else '' since otherwise you can get null values:
CASE
WHEN #Zmienna % 3 = 0
THEN ' hip'
ELSE ''
END
+
CASE
WHEN #Zmienna % 5 = 0
THEN ' hop'
ELSE ''
END
Hint: if you want a space or some other text if both conditions are true, you have to use an and in the case statement:
CASE
WHEN #Zmienna % 3 = 0 and #Zmienna % 5 = 0
THEN ' hip hop'
WHEN #Zmienna % 3 = 0
THEN ' hip'
WHEN #Zmienna % 5 = 0
THEN ' hop'
END
try this:
DECLARE #Zmienna AS INT
SET #Zmienna = 0
WHILE #Zmienna < 999
BEGIN
PRINT CAST(#Zmienna as varchar) +
CASE
when (#Zmienna%3=0 AND #Zmienna%5=0) THEN ' hip hop'
WHEN #Zmienna%3=0 THEN ' hip'
WHEN #Zmienna%5=0 THEN ' hop'
END
SET #Zmienna = #Zmienna + 1
END
Try this, it will give you only 1 dataset instead of 999 for better performance and readability.
Print can only handle 1 value, instead you can SELECT all the rows in 1 go and display the values in different columns instead of concatinating them:
;WITH CTE as
(
SELECT 0 Zmienna
UNION ALL
SELECT Zmienna + 1
FROM CTE
WHERE Zmienna < 998 -- i wonder why you don't want to include 999
)
SELECT
Zmienna,
CASE
WHEN Zmienna % 15 = 0 THEN 'hiphop'
WHEN Zmienna % 3 = 0 THEN 'hip'
WHEN Zmienna % 5 = 0 THEN 'hop'
END as Hippityhop
FROM CTE
OPTION (maxrecursion 0)
you can do it with IF statement
DECLARE #Zmienna AS INT
SET #Zmienna = 0
WHILE #Zmienna < 999
BEGIN
if (#Zmienna % 3) = 0 and (#Zmienna % 5) = 0
BEGIN
PRINT convert(varchar(10),#Zmienna)+ ' hip'+' '+'hop'
END
ELSE
BEGIN
if (#Zmienna % 3) = 0
BEGIN
PRINT convert(varchar(10),#Zmienna)+' hip'
END
if (#Zmienna % 5) = 0
BEGIN
select convert(varchar(10),#Zmienna)+' hop'
END
END
SET #Zmienna = #Zmienna + 1
END
It seems like the easiest answer:
DECLARE #Zmienna AS INT
SET #Zmienna = 0
WHILE #Zmienna < 999
BEGIN
PRINT CAST(#Zmienna as varchar) +
CASE
when (#Zmienna%3=0 AND #Zmienna%5=0) THEN ' hip hop'
WHEN #Zmienna%3=0 THEN ' hip'
WHEN #Zmienna%5=0 THEN ' hop'
ELSE ''
END
SET #Zmienna = #Zmienna + 1
END

Calculate Count of true bits in binary type with t-sql

I need to find how many true bit exists in my binary value.
example:
input: 0001101 output:3
input: 1111001 output:5
While both answers work, both have issues. A loop is not optimal and destructs the value. Both solutions can not be used in a select statement.
Possible better solution is by masking together as follows
select #counter = 0
+ case when #BinaryVariable2 & 1 = 1 then 1 else 0 end
+ case when #BinaryVariable2 & 2 = 2 then 1 else 0 end
+ case when #BinaryVariable2 & 4 = 4 then 1 else 0 end
+ case when #BinaryVariable2 & 8 = 8 then 1 else 0 end
+ case when #BinaryVariable2 & 16 = 16 then 1 else 0 end
+ case when #BinaryVariable2 & 32 = 32 then 1 else 0 end
+ case when #BinaryVariable2 & 64 = 64 then 1 else 0 end
+ case when #BinaryVariable2 & 128 = 128 then 1 else 0 end
+ case when #BinaryVariable2 & 256 = 256 then 1 else 0 end
+ case when #BinaryVariable2 & 512 = 512 then 1 else 0 end
This can be used in a select and update statement. It is also an order of magnitude faster. (on my server about 50 times)
To help you might want to use the following generator code
declare #x int = 1, #c int = 0
print ' #counter = 0 ' /*CHANGE field/parameter name */
while #c < 10 /* change to how many bits you want to see */
begin
print ' + case when #BinaryVariable2 & ' + cast(#x as varchar) + ' = ' + cast(#x as varchar) + ' then 1 else 0 end ' /* CHANGE the variable/field name */
select #x *=2, #c +=1
end
Also as further note: if you use a bigint or go beyond 32 bits it is necessary to cast like follows
print ' + case when #Missing & cast(' + cast(#x as varchar) + ' as bigint) = ' + cast(#x as varchar) + ' then 1 else 0 end '
Enjoy
DECLARE #BinaryVariable2 VARBINARY(10);
SET #BinaryVariable2 = 60; -- binary value is 111100
DECLARE #counter int = 0
WHILE #BinaryVariable2 > 0
SELECT #counter +=#BinaryVariable2 % 2, #BinaryVariable2 /= 2
SELECT #counter
Result:
4
I've left various debug selects in.
begin
declare #bin as varbinary(20);
declare #bitsSet as int;
set #bitsSet = 0;
set #bin = convert(varbinary(20), 876876876876);
declare #i as int;
set #i = 0
select LEN(#bin), 'Len';
while #i < LEN(#bin)
begin
declare #bit as varbinary(1);
set #bit = SUBSTRING(#bin, #i, 1);
select #bit, 'Bit';
declare #power as int
set #power = 0;
while #power < 8
begin
declare #powerOf2 as int;
set #powerOf2 = POWER(2, #power);
if #powerOf2 <> 0
set #bitsSet = #bitsSet + (#bit & #powerOf2) / #powerOf2; -- edited to add the divisor
select #power, #powerOf2;
set #power = #power + 1;
end;
select #bitsSet;
set #i = #i + 1;
end;
select #bitsSet, 'End'
end;
Cheers -
You can handle an arbitrary length binary value by using a recursive CTE to split the data into a table of 1-byte values and counting all of the bits that are true in each byte of that table...
DECLARE #data Varbinary(MAX) = Convert(Varbinary(MAX), N'We can count bits of very large varbinary values without a loop or number table if you like...');
WITH each ( byte, pos ) AS (
SELECT Substring(#data, Len(#data), 1), Len(#data)-1 WHERE Len(#data) > 0
UNION ALL
SELECT Substring(#data, pos, 1), pos-1 FROM each WHERE pos > 0
)
SELECT Count(*) AS [True Bits]
FROM each
CROSS JOIN (VALUES (1),(2),(4),(8), (16),(32),(64),(128)) [bit](flag)
WHERE each.byte & [bit].flag = [bit].flag
OPTION (MAXRECURSION 0);
From SQL Server 2022 you can just use SELECT BIT_COUNT(input)
expression_value can be
Any integer or binary expression that isn't a large object (LOB).
For integer expressions the result can depend on the datatype. e.g. -1 as smallint has a binary representation of 1111111111111111 (two's complement) and will have more bits set for int datatype.