SQL Server : find members from a number - sql-server-2012

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.

Related

Replace Bit Values (1) with Day names SQL

with following query i select days (bit values) from my database into a string separated with blank space:
SELECT CONVERT(VARCHAR(20),BPL_MONDAY) + ' ' +
CONVERT(VARCHAR(20),BPL_TUESDAY) + ' ' +
CONVERT(VARCHAR(20),BPL_WEDNESDAY) + ' ' +
CONVERT(VARCHAR(20),BPL_THURSDAY) + ' ' +
CONVERT(VARCHAR(20),BPL_FRIDAY) + ' ' +
CONVERT(VARCHAR(20),BPL_SATURDAY) + ' ' +
CONVERT(VARCHAR(20),BPL_SUNDAY)
FROM BOS_PRICE_LIST
Result of the query looks something like this:
Now i want to replace 1 with current day name. Example of one row:
Current query result: 1 1 1 1 1 0 0
What i want: Monday Tuesday Wednesday Thursday Friday
Thanks for help
Greetings
Use CASE statement
SELECT case when BPL_MONDAY = 1 then 'Monday' else '' end +
case when BPL_TUESDAY = 1 then 'Tuesday' else '' end +
case when BPL_WEDNESDAY = 1 then 'Wednesday' else '' end +
case when BPL_THURSDAY = 1 then 'Thursday' else '' end +
case when BPL_FRIDAY = 1 then 'Friday' else '' end +
case when BPL_SATURDAY = 1 then 'Saturday' else '' end +
case when BPL_SUNDAY = 1 then 'Sunday' else '' end
FROM BOS_PRICE_LIST

SQL add conversion of date to existing query

I'm would like to convert the date using this function. I'm using SQL server 2014
CONVERT(varchar, sc.StartDate,103) + '" + " " + "' + '" + " - " + "' + CONVERT(varchar, sc.EndDate,103) SIPDate
so it will display in dd/mm/yyyy - dd/mm/yyyy. How do i add it into the query? Thanks.
The query is:
SELECT CONCAT(sc.StartDate, sc.ENDDate) SIPDate,
COUNT (sj.LOComment) WeekReviewed,
COUNT(sjd.WeekNo) TotalWeek,
SUM(sjj.TotalDaysRecord) TotalDaysRecord,
COUNT(CASE sjd.JournalStatusCode WHEN 'D' THEN 1 ELSE NULL END) PENDingComplete
FROM StudentJournalDate sjd
LEFT JOIN StudentJournal sj
ON sjd.WeekNo = sj.WeekNo
LEFT OUTER JOIN
(
SELECT sj.WeekNo,
CASE WHEN RTRIM(sj.Day1Journal) = '' OR sj.Day1Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day2Journal) = '' OR sj.Day2Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day3Journal) = '' OR sj.Day3Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day4Journal) = '' OR sj.Day4Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day5Journal) = '' OR sj.Day5Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day6Journal) = '' OR sj.Day6Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day7Journal) = '' OR sj.Day7Journal IS NULL THEN 0 ELSE 1 END AS TotalDaysRecord
FROM StudentJournal sj
) AS sjj
ON sjj.WeekNo = sj.WeekNo
LEFT OUTER JOIN StudentSIP sc
ON sc.AdminNo = sjd.AdminNo
GROUP BY CONCAT(sc.StartDate, sc.ENDDate)
You can just SELECT and GROUP BY this formatted date expression, i.e.:
SELECT CONVERT(varchar, sc.StartDate, 103) + " - " + CONVERT(varchar, sc.EndDate, 103) AS SIPDate,
COUNT (sj.LOComment) WeekReviewed,
COUNT(sjd.WeekNo) TotalWeek,
SUM(sjj.TotalDaysRecord) TotalDaysRecord,
COUNT(CASE sjd.JournalStatusCode WHEN 'D' THEN 1 ELSE NULL END) PENDingComplete
FROM StudentJournalDate sjd
LEFT JOIN StudentJournal sj
ON sjd.WeekNo = sj.WeekNo
LEFT OUTER JOIN
(
SELECT sj.WeekNo,
CASE WHEN RTRIM(sj.Day1Journal) = '' OR sj.Day1Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day2Journal) = '' OR sj.Day2Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day3Journal) = '' OR sj.Day3Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day4Journal) = '' OR sj.Day4Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day5Journal) = '' OR sj.Day5Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day6Journal) = '' OR sj.Day6Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day7Journal) = '' OR sj.Day7Journal IS NULL THEN 0 ELSE 1 END AS TotalDaysRecord
FROM StudentJournal sj
) AS sjj
ON sjj.WeekNo = sj.WeekNo
LEFT OUTER JOIN StudentSIP sc
ON sc.AdminNo = sjd.AdminNo
GROUP BY CONVERT(varchar, sc.StartDate, 103) + " - " + CONVERT(varchar, sc.EndDate, 103)
Try this. since your SQL SERVER is 2014 you can use format to format the date
SELECT CONCAT(FORMAT(sc.StartDate,'dd/MM/yyy'),+ ' - ' +FORMAT(sc.ENDDate,'dd/MM/yyy')) SIPDate,
COUNT (sj.LOComment) WeekReviewed,
COUNT(sjd.WeekNo) TotalWeek,
SUM(sjj.TotalDaysRecord) TotalDaysRecord,
COUNT(CASE sjd.JournalStatusCode WHEN 'D' THEN 1 ELSE NULL END) PENDingComplete
FROM StudentJournalDate sjd
LEFT JOIN StudentJournal sj
ON sjd.WeekNo = sj.WeekNo
LEFT OUTER JOIN
(
SELECT sj.WeekNo,
CASE WHEN RTRIM(sj.Day1Journal) = '' OR sj.Day1Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day2Journal) = '' OR sj.Day2Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day3Journal) = '' OR sj.Day3Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day4Journal) = '' OR sj.Day4Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day5Journal) = '' OR sj.Day5Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day6Journal) = '' OR sj.Day6Journal IS NULL THEN 0 ELSE 1 END +
CASE WHEN RTRIM(sj.Day7Journal) = '' OR sj.Day7Journal IS NULL THEN 0 ELSE 1 END AS TotalDaysRecord
FROM StudentJournal sj
) AS sjj
ON sjj.WeekNo = sj.WeekNo
LEFT OUTER JOIN StudentSIP sc
ON sc.AdminNo = sjd.AdminNo
GROUP BY CONCAT(FORMAT(sc.StartDate,'dd/MM/yyy'),+ ' - ' +FORMAT(sc.ENDDate,'dd/MM/yyy'))

How to count up a single character in multiple fields in SQL

HI i have a table 'TableCustomers' and within this table are many fields titled 'Name1' 'Name2''Name3'.... 'Name40' some of these fields just have the letter 'x' i want to know how many 'x' are there in all 40 fields
One possible solution is something like;
SELECT
CASE WHEN [Name] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name1] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name2] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name3] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name4] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name5] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name6] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name7] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name8] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name9] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name10] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name11] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name12] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name13] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name14] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name15] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name16] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name17] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name18] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name19] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name20] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name21] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name22] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name23] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name24] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name25] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name26] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name27] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name28] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name29] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name30] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name31] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name32] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name33] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name34] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name35] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name36] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name37] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name38] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name39] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name40] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name41] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name42] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name43] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name44] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name45] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name46] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name47] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name48] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name49] = 'x' THEN 1 ELSE 0 END +
CASE WHEN [Name50] = 'x' THEN 1 ELSE 0 END
FROM [TableCustomers]
I generated this using an application called Nimble Text (http://nimbletext.com/) though you could use dynamic SQL along with the sys.columns view to generate this statement within SQL server, if the columns of the table change. Let me know if you would like an example of this...
You may try something like this:
select len(name00 + name01 + .. + name40) - len(replace(name00 + name01 + .. + name40, 'x', ''))
from yourTable;

Convert returned char from substring to binary

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

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.