How to format a numeric value in Postgresql - sql

I have a set of code that generates a number which can be seen below
SELECT MAX(RIGHT ("node_id",3)::numeric) + 1 as newnum from sewers.structures
WHERE(
ST_WITHIN(
ST_CENTROID((ST_SetSRID(structures.geom, 4326))),
ST_SetSRID((SELECT geom FROM sewers."Qrtr_Qrtr_Sections" WHERE "plat_page" = '510A'),4326)) ) and "node_id" != 'PRIVATE' and "node_id" !='PRIV_SAN' and "node_id" !='PRIV_STORM'
When I run this it generates a number based on the previously placed values. The out put will be a number that can be up to 3 digits. I want to take an output of less than three digits, and force it into a 3 digit format.
For example, if I generate the number 93 I would like to format it as 093. Same for single digit numbers like 2, I want it to be formated at 002 and so on. However, if it generates a 3 digit number, I want it to keep the same format, so 121 stays as 121.

If I got your question right, you're looking for lpad():
WITH j (x) AS (
VALUES (2),(121),(93)
)
SELECT lpad(x::text,3,'0') FROM j;
lpad
------
002
121
093
(3 rows)

Since the output will be a string, you can use to_char with a format of three 0
select to_char(1,'000');
to_char
---------
001
(1 row)

Related

split(regexp_replace ) Like Function In Presto : 331

Is there any way to split values based on consecutive 0's in presto.Minimum 6 digits should be there in first split, if digit count is less than 6 than need to consider some 0's as digit then split if digit count is >= 6 then just need to split in 2 groups.
below query is working as expected in Hive.But I am not able to do the same using presto.
select low as orginal_Value,
split(regexp_replace(low,'(\\d{6,}?)(0+)$','$1|$2'),'\\|') Output_Value from test;
Presto Query:
presto> SELECT regexp_split('1234567890000', '(\d{6,}?)(0+)$') as output;
output
[1234567890000]
(1 row)
It worked Now.
select split(regexp_replace('1234567890000','(\d{6,}?)(0+)$','$1|$2'), '|') as output;
enter code here
output
-------------------
[123456789, 0000]

Print limited number of elements in collect_set array using printf function

I want to printf() just the first 3 patients in collect_set() of patient numbers.
A. I have created "patient_list" using collect_set
collect_set(distinct patient_seq) AS patient_list
which yields arrays of patients numbers of varying length (4, 5 or 6 digits)
Example:
["16189","26599","406622","419117","5551"]
["223587","224663","232072","326504","433430","436673","54540","58188","74118"]
B. I then stripped out the commas and quotes and separated by '*' (in order to grab just the first 3 patients, in the next step):
concat_ws('*', patient_list) AS pat_list
This produces:
16189*26599*406622*419117*5551
223587*224663*232072*326504*433430*436673*54540*58188*74118
C. I tried to use SUBSTRING_INDEX() to create a new variable (pat_list_short) containing just the first 3 patients, but this function is not supported in hive 1.1.0 (not supported until 1.3.0).
substring_index(pat_list, '*', 3) AS pat_list_short
What other option do I have?
I want to feed the pat_list_short into the PRINTF using %s in order to print out just the first three patient numbers for review team. Since the patient num varies in length I can't just limit the print to a certain length
Thanks
Using the data you provided
--------------
key | pat_id
--------------
1 16189
1 26599
1 406622
1 419117
1 5551
2 223587
2 224663
2 232072
2 326504
2 433430
2 436673
2 54540
2 58188
2 74118
you can use this UDF here to truncate an array to a desired length. There are instructions on the main page how to build and use the jar.
Query:
add jar /path/to/jar/brickhouse-0.7.1.jar;
create temporary function trunc_array as 'brickhouse.udf.collect.TruncateArrayUDF';
select key
, concat(' ', trunc_array(collect_set( pat_id ), 3)) pat_list_short
from db.tbl
group by key
Output:
----------------------
key | pat_list_short
----------------------
1 5551 26599 16189
2 232072 58188 223587
I must admit I'm a bit unclear has to how printf() plays a part in this problem as the query returns a result and prints it. It is also with noting that in your query in A, the distinct in collect_set(distinct) is redundant, as collect_set's purpose is to collect distinct elements.

SQL server generate number from 1 to nth

I have a table like;
**ID** **CASH** **INTERVAL**
1 60 5
2 10 3
3 20 4
I want to add 2 columns deriving from current ones like; Column MULT means I list numbers from 1 to INTERVAL by commas and for VAL value I substract CASH from 100 and divide it by INTERVAL and list those intervals by comma listed values inside column VAL
**ID** **CASH** **INTERVAL** **MULT** **VAL**
1 60 5 1,2,3,4,5 8,8,8,8,8
2 10 3 1,2,3 30,30,30
3 20 4 1,2,3,4 20,20,20,20
I know it looks like not an informative question but at least anyone know about to list them in single column with commas using STUFF or etc?
Given how you phrase the question and the sample data you provide, I would be tempted to use a very bespoke approach for this:
with params as (
select '1,2,3,4,5,6,7,8,9' as numbers,
'x,x,x,x,x,x,x,x,x' as vals
)
select l.*,
left(numbers, interval * 2 - 1) as mult,
replace(left(vals, interval * 2 - 1), 'x', (100 - cash) / interval) as val
from params cross join
[like] l;
Of course, you might need to extend the strings in the CTE, if they are not long enough (and this might affect the arithmetic).
The advantage to this approach is speed. It should be pretty fast.
Note: you can also use replicate() rather than the vals.

WHERE varchar = variable length of 0's

Table_A
ID Number
-- ------
1 0
2 00
3 0123
4 000000
5 01240
6 000
The 'Number' column is data type varchar.
EDIT for clarity.
My question is, can I easily pull back all rows of data which contain a variable length string of 0's?
I have tried:
SELECT *
FROM Table_A
WHERE LEFT(Number,1) = '0' AND RIGHT(Number,1) = '0'
Using the above, it would still return the below, using the example table provided.
ID Number
-- ------
1 0
2 00
4 000000
5 01240
6 000
I was looking for a function which I could pass the LEN(Number) int into, and then it generates a string of a specfic character (in my case a string of 0's). I wasn't able to find anything though.
Oh, and I also tried adding a SUBSTRING to the WHERE clause, but sometimes the Number column has a number which has a 0's in the middle, so it still returned strings with other numbers except only 0.
SUBSTRING(Number,ROUND(LEN(Number)/2,0),1) = '0'
Any help is appreciated.
So, you want a string that doesn't contain anything that isn't a 0? Sounds like it's time for a double-negative:
SELECT *
FROM Table_A
WHERE NOT Number like '%[^0]%'
AND number like '0%' --But we do want it to contain at least one zero
(The final check is so that we don't match the empty string)
Answer:
Where number like '%0%'
Your can use this query :
SELECT * FROM Table_A WHERE Number LIKE '%0%';
It'll solve your problem.
SELECT *
FROM yourtable
WHERE len(Number) - len(replace(number,'0','')) >= 0
One more approach
You can use this following one also,you will get your expected result.
SELECT *
FROM Table_A
WHERE Nunber not like '%[1-9]%'
Thanks.

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