Custom number sequence formatting - sql-server-2008

The system I am working with has a numbering system where the numbers 0-999 are represented by the usual 0-999, but 1000 is represented by A00, followed by A01, A02, A03, etc, 1100 being B00 etc.
I can't think of a way to handle this in T-SQL without resorting to inspecting individual digits with huge case statements, and there must be a better way than that. I had thought about using Hexadecimal but that's not right.
DECLARE #startint int = 1,
#endint int = 9999;
;WITH numbers(num)
AS
(
SELECT #startint AS num
UNION ALL SELECT num+1 FROM numbers
WHERE num+1 <= #endint
)
SELECT num, convert(varbinary(8), num) FROM [numbers] N
OPTION(MAXRECURSION 0)
With this 999 is now 3E7, where it should just be 999.
This currently produces this:
Number Sequence
0 0x00000000
1 0x00000001
...
10 0x0000000A
...
100 0x00000064
...
999 0x000003E7
1000 0x000003E8
What I'm looking for:
Number Sequence
0 000
1 001
...
10 010
11 011
12 012
...
999 999
1000 A00
1001 A01
...
1099 A99
1100 B00
1101 B01
1200 C00
I need this to work in SQL Server 2008.

You can use integer division and modulo to separate the hundreds part from the tens.
After that, you can add 64 to the quotient to get an ASCII value starting from A.
create function function dbo.fn_NumToThreeLetters(#num integer)
RETURNS nchar(3)
AS
begin
RETURN (SELECT (case
when #num/1000 >0 then
CHAR(( (#num-900)/100) +64)
+ replace(cast( #num %100 as nchar(2)),' ','0')
else cast(#num as nvarchar(3))
end)
)
END
select dbo.fn_NumToThreeLetters(1100)
-------
B00
select dbo.fn_NumToThreeLetters(999)
-------
999
The first when clause ensures that the conversion is applied only if a number is above 1000. If it is, subtract 900 then divide by 100, so we get a number that starts from 1 for 1000, 2 for 1100, etc.
Add 64 to it to get an ASCII starting from A and convert it back to a character with CHAR.
The remainder just needs to be converted to a 2-digit nchar, where spaces are replaced with 0.
This will work only up to 3500. The question doesn't specify what should be done with larger numbers

Related

How many unique conditions can be defined using only two on and off mode switches? [duplicate]

For example, if n=9, then how many different values can be represented in 9 binary digits (bits)?
My thinking is that if I set each of those 9 bits to 1, I will make the highest number possible that those 9 digits are able to represent. Therefore, the highest value is 1 1111 1111 which equals 511 in decimal. I conclude that, therefore, 9 digits of binary can represent 511 different values.
Is my thought process correct? If not, could someone kindly explain what I'm missing? How can I generalize it to n bits?
29 = 512 values, because that's how many combinations of zeroes and ones you can have.
What those values represent however will depend on the system you are using. If it's an unsigned integer, you will have:
000000000 = 0 (min)
000000001 = 1
...
111111110 = 510
111111111 = 511 (max)
In two's complement, which is commonly used to represent integers in binary, you'll have:
000000000 = 0
000000001 = 1
...
011111110 = 254
011111111 = 255 (max)
100000000 = -256 (min) <- yay integer overflow
100000001 = -255
...
111111110 = -2
111111111 = -1
In general, with k bits you can represent 2k values. Their range will depend on the system you are using:
Unsigned: 0 to 2k-1
Signed: -2k-1 to 2k-1-1
What you're missing: Zero is a value
A better way to solve it is to start small.
Let's start with 1 bit. Which can either be 1 or 0. That's 2 values, or 10 in binary.
Now 2 bits, which can either be 00, 01, 10 or 11 That's 4 values, or 100 in binary... See the pattern?
Okay, since it already "leaked": You're missing zero, so the correct answer is 512 (511 is the greatest one, but it's 0 to 511, not 1 to 511).
By the way, an good followup exercise would be to generalize this:
How many different values can be represented in n binary digits (bits)?
Without wanting to give you the answer here is the logic.
You have 2 possible values in each digit. you have 9 of them.
like in base 10 where you have 10 different values by digit say you have 2 of them (which makes from 0 to 99) : 0 to 99 makes 100 numbers. if you do the calcul you have an exponential function
base^numberOfDigits:
10^2 = 100 ;
2^9 = 512
There's an easier way to think about this. Start with 1 bit. This can obviously represent 2 values (0 or 1). What happens when we add a bit? We can now represent twice as many values: the values we could represent before with a 0 appended and the values we could represent before with a 1 appended.
So the the number of values we can represent with n bits is just 2^n (2 to the power n)
The thing you are missing is which encoding scheme is being used. There are different ways to encode binary numbers. Look into signed number representations. For 9 bits, the ranges and the amount of numbers that can be represented will differ depending on the system used.

SQL Bit operation, change second last bit to 0

i have a lot of rows with an bigint(length 20) and i have to change every second last bit to 0.
For example i have: 0101 1011 and the result i need is: 0101 1001
The Problem is, the numbers are "random" and i can't calcuate -2(10).
You can use the bitwise AND operator (&), ANDing with NOT 2 (created using the bitwise inversion operator (~)) to get your results e.g.
CREATE TABLE test (num BIGINT(20));
INSERT INTO test VALUES
(4),
(91),
(9223372036854775807);
SELECT num, num & ~2 FROM test;
Output:
num num & ~2
4 4
91 89
9223372036854775807 9223372036854775805
Demo on dbfiddle
You can use "Bitwise And" operator to change the bit.
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/bitwise-operators-transact-sql?view=sql-server-2017

SQL Order By but invert for one element

I've got an SQL query which results upto the following
Code int1 int2 int3 S
C12 21 22 14 1
C33 43 56 2 3
C34 23 2 1 3
C55 33 92 12 5
CB56 45 66 10 5
MA10 10 11 12 1
This is the result of using OrderBy on Code
However I do not want it to order according to alphabets
But by the number after it for ex 1 in M1 and 33 in C33
In some cases the number after the alphabet may be 3 digits like E344
What I want it to look like
Code int1 int2 int3 S
MA10 10 11 12 1
C12 21 22 14 1
C323 43 56 2 3
C325 43 56 2 3
C34 23 2 1 3
C525 33 92 12 5
CB56 45 66 10 5
What I need is
M Should always show on top if Present
Then Sort According to Number on first place
Then Sort it according to the number on the Second place
Then sort it according to the number on the third place
The field 's' will always consist of the first digit from the Code
step 1 split up the column into 2 columns, 1 containing the letters, the other containing the numbers:
SELECT
substring(code,0,PATINDEX('%[0-9]%', Code)) as letters,
substring(code,PATINDEX('%[0-9]%', Code)) as numbers,
fields
FROM table
step 2 Convert the numbers to integer and sort
CONVERT(substring(code,PATINDEX('%[0-9]%', Code)),UNSIGNED INTEGER) as numbers
step 3 sort
Order by field1 asc, field2 desc... etc
It might be easier to use a subquery:
select * from
(SELECT
substring(code,0,PATINDEX('%[0-9]%', Code)) as letters,
CONVERT(substring(code,PATINDEX('%[0-9]%', Code)),UNSIGNED INTEGER) as numbers,
fields
FROM table) T
order by numbers asc, letters desc
This is conceptually simple: you want to order first by whether the code starts or not with the letter 'M', and then by the numeric portion of the code. You say in a comment:
extracting the first digit then order and then extracting the second
digit and then order and then extracting the third digit and then
order
This is exactly how alphabetical order has always worked. You order by first character; when it is the same you order by the second character, etc. so you need no special treatment for that case. Just get the numeric part of the code as a string, then order by it.
At this point, the only problem left to resolve is how to extract the numeric part of the code. That would be easy with PATINDEX() (as Alfons pointed out) but unfortunately MySQL does not support PATINDEX() as far as I know.
Now, what follows is extremely ugly, but it does work. Basically we get the non-numeric part of the string by removing all the numeric characters from it, then use the length of the non-numeric part to extract the numeric part.
SELECT mytable.* FROM mytable
INNER JOIN (
SELECT
code,
RIGHT(code, LENGTH(letters)) numbers
FROM (
SELECT
code,
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
code, 0, ''), 1, ''), 2, ''), 3, ''), 4, '')
, 5, ''), 6, ''), 7, ''), 8, ''), 9, '') letters
FROM mytable
) letters_table
) numbers_table
ON numbers_table.code = mytable.code
ORDER BY (numbers_table.code like 'M%') DESC,
numbers_table.numbers ASC
This solution is probably inefficient. However, I don't think you can get any acceptable efficiency anyway unless you store the numeric part on a separate column that you can index.
As you are guaranteeing that s is the value of the first digit in the code, this can be used to find the start of the code and from there, get the numeric part of the code. As you want to have all the codes starting with 'M' first, this results in the following ORDER BY clause:
... ORDER BY IF(SUBSTR(code, 1, 1) = 'M', 0, 1), SUBSTR(code, LOCATE(s, code))

How many values can be represented with n bits?

For example, if n=9, then how many different values can be represented in 9 binary digits (bits)?
My thinking is that if I set each of those 9 bits to 1, I will make the highest number possible that those 9 digits are able to represent. Therefore, the highest value is 1 1111 1111 which equals 511 in decimal. I conclude that, therefore, 9 digits of binary can represent 511 different values.
Is my thought process correct? If not, could someone kindly explain what I'm missing? How can I generalize it to n bits?
29 = 512 values, because that's how many combinations of zeroes and ones you can have.
What those values represent however will depend on the system you are using. If it's an unsigned integer, you will have:
000000000 = 0 (min)
000000001 = 1
...
111111110 = 510
111111111 = 511 (max)
In two's complement, which is commonly used to represent integers in binary, you'll have:
000000000 = 0
000000001 = 1
...
011111110 = 254
011111111 = 255 (max)
100000000 = -256 (min) <- yay integer overflow
100000001 = -255
...
111111110 = -2
111111111 = -1
In general, with k bits you can represent 2k values. Their range will depend on the system you are using:
Unsigned: 0 to 2k-1
Signed: -2k-1 to 2k-1-1
What you're missing: Zero is a value
A better way to solve it is to start small.
Let's start with 1 bit. Which can either be 1 or 0. That's 2 values, or 10 in binary.
Now 2 bits, which can either be 00, 01, 10 or 11 That's 4 values, or 100 in binary... See the pattern?
Okay, since it already "leaked": You're missing zero, so the correct answer is 512 (511 is the greatest one, but it's 0 to 511, not 1 to 511).
By the way, an good followup exercise would be to generalize this:
How many different values can be represented in n binary digits (bits)?
Without wanting to give you the answer here is the logic.
You have 2 possible values in each digit. you have 9 of them.
like in base 10 where you have 10 different values by digit say you have 2 of them (which makes from 0 to 99) : 0 to 99 makes 100 numbers. if you do the calcul you have an exponential function
base^numberOfDigits:
10^2 = 100 ;
2^9 = 512
There's an easier way to think about this. Start with 1 bit. This can obviously represent 2 values (0 or 1). What happens when we add a bit? We can now represent twice as many values: the values we could represent before with a 0 appended and the values we could represent before with a 1 appended.
So the the number of values we can represent with n bits is just 2^n (2 to the power n)
The thing you are missing is which encoding scheme is being used. There are different ways to encode binary numbers. Look into signed number representations. For 9 bits, the ranges and the amount of numbers that can be represented will differ depending on the system used.

MySQL append , prefix a range of numbers with 0

I have around a few thousand rows with which contain 3 digit numbers starting with 100 and ranging to 199 which i need to prefix with 0. There are also thousands of other numbers 4 digit numbers as well which i don't want to change.
I need find all the 3 digit numbers in the range and prefix only those ranging from 100 -199 with a 0 so as they are 4 digits eg 100 > 0100 , 104 > 0104 and so on.
Also these numbers may step eg 110 next is 124.
Is there a way I can do this using SQL? as i don't fancy changing these manually!
Many Thanks
This is best done with a programming language. That said, here's a SQL query that will update all the existing numbers:
UPDATE tableName SET fieldName = right(concat('0000',fieldName), 4) WHERE length(fieldName) < 4
The LPAD function is what you are looking for. You can use this in your query to pad the numbers on the fly.
SELECT LPAD(CONVERT(num AS CHAR), 4, '0') FROM tbl WHERE num > 99 AND num < 200
If you prefer to do this on the script side, str_pad will do the same in php.