create/rank 50 digit number and cast it to varchar - sql

I cant create such a long numeric value(numeric value out of range), so i have to cast it, but it doesnt work.
ID DesiredID
1 100000..1(50 digit long)
2 100000..2(50 digit long)
3 100000..3(50 digit long)
...
999 435345...(50 digit long)
The numbers can have any values, but they need to be 50 digit long and the ID starts from 1 and goes up to a three digit number(999).
I have tryed something like
select (100000.....000 + dense_rank() over (order by ID))::varchar(50)
but i am getting the numeric value out of range error. With:
select (1000 + dense_rank() over (order by ID))::varchar(4)
the sql works.

Postgres supports unlimited length numerics, so both these work:
select '10000000000000000000000000000000000000000000000000000000000001'::numeric
select 10000000000000000000000000000000000000000000000000000000000001

Your code will work fine if the number you start with really has 50 digits.
I will bet two pizzas and a bottle of beer that you have a 1 followed by 50 zeros, totalling 51 digits.
Here's an example of it working:
https://dbfiddle.uk/?rdbms=postgres_13&fiddle=c197e05132fa454b1187201ee28ca39e

Related

Counting the number of digits in column

Here is my code
select len(cast(code as float)),code
from tbl1
where code is not null
and this is the output:
I want a count of digits in the code column.
I don't understand why the last one is counted as 12 and not 8?
Cast it as an int instead:
select len(cast(code as int)), code
from tbl1
where code is not null;
Presumably, some sort of decimal values are getting counted.
Get the number's power of 10 and add 1. This works either if ints or reals to count the number of digits of the whole number part (note using LOG10 only works on positive numbers so I have applied ABS to get around this issue, may not be required for your data):
SELECT code, CASE WHEN Number = 0 THEN 1
ELSE FLOOR(LOG10(ABS(code))) + 1 AS NDigits
FROM tbl1

Replace the digits of a number with subsequent higher digits

Given a number I want to replace each digit with the next digit that is larger. If there is no next larger digit leave the digit as it was.
Eg : Input : 1234, Output - 2344
Since in Oracle we can process everything row by row, I tried first to separate the digits of number into rows by using the below query.
SELECT REGEXP_SUBSTR ('1234','[[:digit:]]',1,LEVEL) txt
FROM dual
CONNECT BY LEVEL <= length('1234');
The query will give me this result.
TXT
----------------
1
2
3
4
But I am stuck in here, how to compare the two rows and replace them with the largest.
Attempted expansion and clarification based on comments:
Treat the number as a string of digits. For each digit, find the first digit among the remaining digits to the right of the current one, that has a higher value than the current digit. That may not be the highest-value digit in the string, or even the highest among all the digits to the right, it is just the first higher value encountered. If there is no higher value then keep the current digit intact. Only consider following digits, preceding ones are ignored.
Some examples:
1234 -> 2344
1357 -> 3577
1157 -> 5577
1245638 -> 2456888
Breaking down the last one:
Digit 1 is 1; the first digit in the remaining string 245638 that is higher than 1 is 2.
Digit 2 is 2; the first digit in the remaining string 45638 that is higher than 2 is 4.
Digit 3 is 4; the first digit in the remaining string 5638 that is higher than 4 is 5.
Digit 4 is 5; the first digit in the remaining string 638 that is higher than 5 is 6.
Digit 5 is 6; the first digit in the remaining string 38 that is higher than 6 is 8.
Digit 6 is 3; the first digit in the remaining string 8 that is higher than 3 is 8.
Digit 7 is 8; no subsequent digit is higher then 8 so keep existing digit 8.
After some clarification in comments:
WITH t AS (
SELECT LEVEL AS pos,
ROWNUM AS txt_order,
REGEXP_SUBSTR ('1245638','[[:digit:]]',1,LEVEL) AS txt
FROM dual
CONNECT BY LEVEL <= LENGTH('1245638')
),
v AS (
SELECT t1.pos, t1.txt,
MIN(t2.txt) KEEP (DENSE_RANK FIRST ORDER BY t2.pos) as new_txt
FROM t t1
LEFT JOIN t t2 ON t2.pos > t1.pos AND t2.txt > t1.txt
GROUP BY t1.pos, t1.txt
)
SELECT LISTAGG(NVL(new_txt, txt), NULL) WITHIN GROUP (ORDER BY pos) AS OUTPUT
FROM v;
OUTPUT
--------
2456888
The t CTE is just your original query. Now the v CTE is finding the first digit later in the list which is larger than the current one; the nvl uses the current digit if there isn't one larger. The listagg just sticks the digits back together in the right order.
SQL Fiddle of the same logic, but using a recursive CTE instead of the connect-by to generate the digits, just so multiple values can be 'converted' in one go from a table. Which gives:
ORIGINAL OUTPUT
---------------------------------------- --------
1234 2344
1157 5577
1357 3577
1245638 2456888

order sql server string like numbers

I need to order string containing this format
number .(dot) number .(dot) number .(dot) number and so on multiple levels so the string can be
1.1.1.1.1.1.5
or
1.1.1.1.1.1.1.1.1.1.1.1.1.1......9
or
5
or
5.5.6.7.8.1.2.3454.2.11213
I have tried doing cast, but i need a solution other than common table expresions, because it is pretty slow.
is there a way to order this like numbers so 10 be next to 9 and not to 1, thank you
This works, with a few assumptions, one being that the first digit always is an int.
insert into #t values ('1.0'),
('10.2.44.2'),
('5.2.523.242'),
('4.23.5511'),
('0.9.4343.1.6.2'),
('99.245.52371.0.1'),
('1.1.1.1.1.1.5'),
('1.1.1.1.1.1.1.1.1.1.1.1.1.1......9'),
('5.5'),
('5.5.6.7.8.1.2.3454.2.11213')
SELECT CAST(SUBSTRING(c, 0, COALESCE(CHARINDEX('.',c, 0), c)) AS INT) AS FirstDigit, c
from #t
order by FirstDigit
Results:
FirstDigit c
0 0.9.4343.1.6.2
1 1.0
1 1.1.1.1.1.1.5
1 1.1.1.1.1.1.1.1.1.1.1.1.1.1......9
4 4.23.5511
5 5.2.523.242
5 5.5
5 5.5.6.7.8.1.2.3454.2.11213
10 10.2.44.2
99 99.245.52371.0.1

BigQuery: Mod operator returning negative result when dividing by positive integer

I have a table with a couple of fields. The first field is the userId. I am using the hash function to shard the data by userId.
I am running the following query:
SELECT userId, HASH(userId) as hashedId, HASH(userId) % 3 as hashedIdMod3
FROM mydataset.mytable LIMIT 1000
So for example:
-5655326518438853587 % 3 ==> -1 when it should be 2
HASH(27315207816077732041734307321022553299) is -3139846784539570547 and the remainder is -2 when divided by 3 when it should be 1
So, how can the remainder be negative when dividing by a positive integer?
mod of a negative number is negative in SQL (and c++, java, etc). So you'll want to use ABS() -- as in:
SELECT userId,
HASH(userId) as hashedId,
ABS(HASH(userId) % 3) as hashedIdMod3
FROM mydataset.mytable LIMIT 1000

Finding even or odd ID values

I was working on a query today which required me to use the following to find all odd number ID values
(ID % 2) <> 0
Can anyone tell me what this is doing? It worked, which is great, but I'd like to know why.
ID % 2 is checking what the remainder is if you divide ID by 2. If you divide an even number by 2 it will always have a remainder of 0. Any other number (odd) will result in a non-zero value. Which is what is checking for.
For finding the even number we should use
select num from table where ( num % 2 ) = 0
As Below Doc specify
dividend % divisor
Returns the remainder of one number divided by another.
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/modulo-transact-sql#syntax
For Example
13 % 2 return 1
Next part is <> which denotes Not equals.
Therefor what your statement mean is
Remainder of ID when it divided by 2 not equals to 0
Be careful because this is not going to work in Oracle database. Same Expression will be like below.
MOD(ID, 2) <> 0
ID % 2 reduces all integer (monetary and numeric are allowed, too) numbers to 0 and 1 effectively.
Read about the modulo operator in the manual.
In oracle,
select num from table where MOD (num, 2) = 0;
dividend % divisor
Dividend is the numeric expression to divide. Dividend must be any expression of integer data type in sql server.
Divisor is the numeric expression to divide the dividend. Divisor must be expression of integer data type except in sql server.
SELECT 15 % 2
Output
1
Dividend = 15
Divisor = 2
Let's say you wanted to query
Query a list of CITY names from STATION with even ID numbers only.
Schema structure for STATION:
ID Number
CITY varchar
STATE varchar
select CITY from STATION as st where st.id % 2 = 0
Will fetch the even set of records
In order to fetch the odd records with Id as odd number.
select CITY from STATION as st where st.id % 2 <> 0
% function reduces the value to either 0 or 1
It's taking the ID , dividing it by 2 and checking if the remainder is not zero; meaning, it's an odd ID.
<> means not equal. however, in some versions of SQL, you can write !=