How to convert automatically $10k to 10000 in SQL query - sql

How to covert 10k to 10000 in SQL query

Use REPLACE
SELECT REPLACE('$10k', 'k', '000')
Returns
REPLACE('$10k', 'k', '000')
'$10000'

Try this - it's pretty foolproof:
WITH
indata(amount) AS (
SELECT '10000' FROM dual
UNION ALL SELECT '10k' FROM dual
UNION ALL SELECT '200' FROM dual
)
SELECT
CASE
WHEN LOWER(amount) LIKE '%k'
THEN CAST(RTRIM(LOWER(amount),'k') AS NUMBER(9,0)) * 1000
ELSE CAST(AMOUNT AS NUMBER(9,0))
END AS numeric_amount
FROM indata
-- out numeric_amount
-- out ----------------
-- out 10000
-- out 10000
-- out 200

Related

Query works in SQL Server, trying to replicate in Oracle

I have a query that works as intended in SQL Server, but when I try to replicate it in Oracle, it doesn't work.
In SQL Server, it returns Column1 with 5 characters.
In Oracle, it is returning the original values.
Oracle syntax isn't my strong point, how can I get this to work, any suggestions would be appreciated
SELECT
CASE
WHEN Column1 LIKE '__-____'
THEN CONCAT('000', (SUBSTR(LTRIM(RTRIM(Column1)), 1, 2)))
WHEN Column1 LIKE '___-____'
THEN CONCAT('00', (SUBSTR(LTRIM(RTRIM(Column1)), 1, 3)))
WHEN Column1 LIKE '_______-_____'
THEN (SUBSTR(LTRIM(RTRIM(Column1)), 3, 5))
ELSE Column1
END AS NewColumn
FROM
schema.table1
Here it is again with a CTE so you can see it works as intended in SQL Server:
WITH cte_test AS
(
SELECT '12-3456' AS Column1
UNION ALL
SELECT '78-9101'
UNION ALL
SELECT '1234567-89101'
UNION ALL
SELECT '123-4321'
)
SELECT
CASE
WHEN Column1 LIKE '__-____'
THEN CONCAT('000', (SUBSTRING(LTRIM(RTRIM(Column1)), 1, 2)))
WHEN Column1 LIKE '___-____'
THEN CONCAT('00', (SUBSTRING(LTRIM(RTRIM(Column1)), 1, 3)))
WHEN Column1 LIKE '_______-_____'
THEN (SUBSTRING(LTRIM(RTRIM(Column1)), 3, 5))
ELSE Column1
END AS NewColumn
FROM
cte_test
The issue is that you've declared the column in the Oracle table as char(20). char(20) is a fixed width data type so it will always be space padded out to 20 characters. Given your sample data, that wastes space and means that neither of your like clauses are going to match the sample data because of the trailing spaces. You really want to declare the column in the table as varchar2(20) so that it is not blank padded.
If you just take the CTE from your SQL Server example and use it with your Oracle code, the query returns what you want because Oracle treats the column in the CTE as a varchar2
WITH cte_test AS
(
SELECT '12-3456' AS Column1 from dual
UNION ALL
SELECT '78-9101' from dual
UNION ALL
SELECT '1234567-89101' from dual
UNION ALL
SELECT '123-4321' from dual
)
SELECT
CASE
WHEN Column1 LIKE '__-____'
THEN CONCAT('000', (SUBSTR(LTRIM(RTRIM(Column1)), 1, 2)))
WHEN Column1 LIKE '___-____'
THEN CONCAT('00', (SUBSTR(LTRIM(RTRIM(Column1)), 1, 3)))
WHEN Column1 LIKE '_______-_____'
THEN (SUBSTR(LTRIM(RTRIM(Column1)), 3, 5))
ELSE Column1
END AS NewColumn
FROM cte_test
If you create the table as a char(20) and insert the data, it gets space padded so the like statements don't do what you want
create table char_test( column1 char(20) );
insert into char_test
WITH cte_test AS
(
SELECT '12-3456' AS Column1 from dual
UNION ALL
SELECT '78-9101' from dual
UNION ALL
SELECT '1234567-89101' from dual
UNION ALL
SELECT '123-4321' from dual
)
select * from cte_test;
SELECT
CASE
WHEN Column1 LIKE '__-____'
THEN CONCAT('000', (SUBSTR(LTRIM(RTRIM(Column1)), 1, 2)))
WHEN Column1 LIKE '___-____'
THEN CONCAT('00', (SUBSTR(LTRIM(RTRIM(Column1)), 1, 3)))
WHEN Column1 LIKE '_______-_____'
THEN (SUBSTR(LTRIM(RTRIM(Column1)), 3, 5))
ELSE Column1
END AS NewColumn
FROM char_test
You can work around that by trimming Column1 before doing the like
SELECT
CASE
WHEN trim(Column1) LIKE '__-____'
THEN CONCAT('000', (SUBSTR(Column1, 1, 2)))
WHEN trim(Column1) LIKE '___-____'
THEN CONCAT('00', (SUBSTR(Column1, 1, 3)))
WHEN trim(Column1) LIKE '_______-_____'
THEN (SUBSTR(Column1, 3, 5))
ELSE Column1
END AS NewColumn
FROM char_test
But a better solution would be to declare the column as varchar2 in the first place so that you don't have the space padding to work around
create table varchar_test( column1 varchar2(20) );
insert into varchar_test
WITH cte_test AS
(
SELECT '12-3456' AS Column1 from dual
UNION ALL
SELECT '78-9101' from dual
UNION ALL
SELECT '1234567-89101' from dual
UNION ALL
SELECT '123-4321' from dual
)
select * from cte_test;
SELECT
CASE
WHEN Column1 LIKE '__-____'
THEN CONCAT('000', SUBSTR(Column1, 1, 2))
WHEN Column1 LIKE '___-____'
THEN CONCAT('00', SUBSTR(Column1, 1, 3))
WHEN Column1 LIKE '_______-_____'
THEN (SUBSTR(Column1, 3, 5))
ELSE Column1
END AS NewColumn
FROM varchar_test
Here is a fiddle that shows the various options.
Oracle alternative which (in temp CTE) extracts the first part of the string (up to the minus sign), and then - depending on its length - left pads it with zeros up to 5 characters in length, or takes the last 5 characters):
SQL> WITH cte_test AS
2 (
3 SELECT '12-3456' AS Column1 from dual
4 UNION ALL
5 SELECT '78-9101' from dual
6 UNION ALL
7 SELECT '1234567-89101' from dual
8 UNION ALL
9 SELECT '123-4321' from dual
10 ),
11 temp as
12 (select column1,
13 substr(column1, 1, instr(column1, '-') - 1) val
14 from cte_Test
15 )
16 select column1,
17 lpad(case when length(val) < 5 then val
18 else substr(val, -5)
19 end, 5, '0'
20 ) as result
21 from temp;
COLUMN1 RESULT
------------- --------------------
12-3456 00012
78-9101 00078
1234567-89101 34567
123-4321 00123
SQL>
You want something like:
SELECT CASE
WHEN Column1 LIKE '__-____ '
THEN '000' || SUBSTR(Column1, 1, 2)
WHEN Column1 LIKE '___-____ '
THEN '00' || SUBSTR(Column1, 1, 3)
WHEN Column1 LIKE '_______-_____ '
THEN SUBSTR(Column1, 3, 5)
ELSE Column1
END AS NewColumn
FROM schema.table1
or:
SELECT CASE
WHEN REGEXP_LIKE( Column1, '^\d{2}-\d{4}\s*$' )
THEN '000' || SUBSTR(Column1, 1, 2)
WHEN REGEXP_LIKE( Column1, '^\d{3}-\d{4}\s*$' )
THEN '00' || SUBSTR(Column1, 1, 3)
WHEN REGEXP_LIKE(Column1, '^\d{7}-\d{5}\s*$' )
THEN SUBSTR(Column1, 3, 5)
ELSE Column1
END AS NewColumn
FROM schema.table1
Or, more simply:
SELECT SUBSTR(
'000' || SUBSTR(column1, 1, INSTR(column1, '-') - 1),
-5
) AS newcolumn
FROM schema.table1
Which, for the sample data:
CREATE TABLE schema.table1( column1 CHAR(20) );
INSERT INTO schema.table1(column1)
SELECT '12-3456' FROM DUAL UNION ALL
SELECT '78-9101' FROM DUAL UNION ALL
SELECT '1234567-89101' FROM DUAL UNION ALL
SELECT '123-4321' FROM DUAL;
All output:
NEWCOLUMN
00012
00078
34567
00123
db<>fiddle here

Add numbers within a string in an SQL statement

I have below query of which i would like to modify.
I want to sum all the numbers that occur within a string with the condition that it is joined with the text GB or MB .
If it is in GB it first has to be converted to MB. (This i have done simply by multiplying by 1024)
SELECT /*+ PARALLEL */
'SOME TEXT 20GB+2GB+SOMETEXT' SOMETEXT,
CASE
WHEN REGEXP_SUBSTR('SOME TEXT 20GB+2GB+SOMETEXT','GB',1,1) = 'GB'
THEN 1024*to_number(regexp_replace(REGEXP_SUBSTR('SOME TEXT 20GB+2GB+SOMETEXT','(\d+)GB',1,1), '[^0-9]', ''))
ELSE to_number(regexp_replace(REGEXP_SUBSTR('SOME TEXT 20GB+2GB+SOMETEXT','(\d+)MB',1,1), '[^0-9]', ''))
END TOTAL_MBs
FROM DUAL;
TEST STRINGS
TEXT TEXT_35MB+ MORETEXT
OTHERTEXT 480MB + 3MB AND_TEXT
SOMETEXT 7MB + 7NUMBER
TEXT 1GB AND SOME_TEXT
SOME TEXT 20GB+2GB+SOMETEXT
Here is where i am stuck: To add the numbers that occur more than once in one text
For example:-
For this text OTHERTEXT 480MB + 3MB AND_TEXT I want my result to have 483 as TOTAL_MBS and not 480
Think you are searching for something like:
with da as (
select 1 id, 'TEXT TEXT_35MB+ MORETEXT' tcase from dual
union all select 2 id,'OTHERTEXT 480MB + 3MB AND_TEXT' tcase from dual
union all select 3 id,'SOMETEXT 7MB + 7NUMBER' tcase from dual
union all select 4 id,'TEXT 1GB AND SOME_TEXT' tcase from dual
union all select 5 id,'SOME TEXT 20GB+2GB+SOMETEXT' tcase from dual
union all select 6 id,'SOME TEXT 20MB+2GB+SOMETEXT' tcase from dual
),
split as(
select id
, tcase
, REGEXP_SUBSTR(tcase,'(\d+)(M|G)B',1,level) ot
from da
connect by REGEXP_SUBSTR(tcase,'(\d+)(M|G)B',1,level)is not null
and prior id = id
and PRIOR DBMS_RANDOM.VALUE IS NOT NULL)
select id
, tcase
, sum( case when ot like '%GB%' then 1024 else 1 end * regexp_substr(ot,'\d+')) v
from split
group by id
,tcase
order by id;
Result:
1 TEXT TEXT_35MB+ MORETEXT 35
2 OTHERTEXT 480MB + 3MB AND_TEXT 483
3 SOMETEXT 7MB + 7NUMBER 7
4 TEXT 1GB AND SOME_TEXT 1024
5 SOME TEXT 20GB+2GB+SOMETEXT 22528
6 SOME TEXT 20MB+2GB+SOMETEXT 2068
You can use a recursive sub-query factoring clause:
SELECT sometext,
COALESCE(
REGEXP_SUBSTR( sometext, '(\d+)([MG])B', 1, 1, NULL, 1 )
* CASE REGEXP_SUBSTR( sometext, '(\d+)([MG])B', 1, 1, NULL, 2 )
WHEN 'M' THEN 1
WHEN 'G' THEN 1024
END,
0
),
1,
REGEXP_COUNT( sometext, '(\d+)([MG])B' )
FROM test_data
UNION ALL
SELECT sometext,
total_mb
+ REGEXP_SUBSTR( sometext, '(\d+)([MG])B', 1, i + 1, NULL, 1 )
* CASE REGEXP_SUBSTR( sometext, '(\d+)([MG])B', 1, i + 1, NULL, 2 )
WHEN 'M' THEN 1
WHEN 'G' THEN 1024
END,
i + 1,
num_terms
FROM terms
WHERE i < num_terms
)
SELECT sometext,
total_mb
FROM terms
WHERE i >= num_terms;
which for the test data:
CREATE TABLE test_data ( sometext ) AS
SELECT 'SOME TEXT 20GB+2GB+SOMETEXT' FROM DUAL UNION ALL
SELECT '1MB+1GB+10MB+10GB' FROM DUAL;
outputs:
SOMETEXT | TOTAL_MB
:-------------------------- | -------:
SOME TEXT 20GB+2GB+SOMETEXT | 22528
1MB+1GB+10MB+10GB | 11275
db<>fiddle here
below I used a view/memory table to assign regex function to the specific string and it worked for me
with tbl1 as (
select 1 pd, ' 20GB+2GB sometext +7500 + 45sometext' string from dual
),
tbl2 as(
select pd
, string
, REGEXP_SUBSTR(string,'(\d+)(M|G)B',1,level) string2
from tbl1
connect by REGEXP_SUBSTR(string,'(\d+)(M|G)B',1,level)is not NULL
and prior pd = pd
and PRIOR DBMS_RANDOM.VALUE IS NOT NULL)
select pd
, string
, sum( case when string2 like '%GB%' then 1024 end * regexp_substr(string2,'\d+')) string3
from tbl2
group by pd
,string
order by pd;

Unique alphanumeric key generation in MSSQL

I have table with char(4) field which is used as key. Value for that is generated (max + 1). But not it has reached to it's max(9999). Cannot change the data type of the column since that is used it so many places.
I came up with a solution like below...
9999 -> A000...A999->B000...B999->Z999 -> ZA00->ZZZZ (zzzz will be OK for another 10 years)
Please tell me is there an easy way to generate this other than doing substring() and string manipulation ?
Current Code :
DECLARE #cle smallint
SELECT #cle = isnull(MAX(CONVERT(smallint,RTRIM(cle))),0) from smnf
INSERT INTO smnf (sup, cle, dsc, exc, dirty) VALUES (#sup, CONVERT(char(4), #cle+1), #dsc, 0, 'A')
SELECT i INTO #t FROM (SELECT '0' i UNION ALL SELECT '1' UNION ALL SELECT '2' UNION ALL SELECT '3' UNION ALL SELECT '4' UNION ALL SELECT '5' UNION ALL SELECT '6' UNION ALL SELECT '7' UNION ALL SELECT '8' UNION ALL SELECT '9' UNION ALL SELECT 'A' UNION ALL SELECT 'B' UNION ALL SELECT 'C' UNION ALL SELECT 'D' UNION ALL SELECT 'E' UNION ALL SELECT 'F' UNION ALL SELECT 'G' UNION ALL SELECT 'H' UNION ALL SELECT 'I' UNION ALL SELECT 'J' UNION ALL SELECT 'K' UNION ALL SELECT 'L' UNION ALL SELECT 'M' UNION ALL SELECT 'N' UNION ALL SELECT 'O' UNION ALL SELECT 'P' UNION ALL SELECT 'Q' UNION ALL SELECT 'R' UNION ALL SELECT 'S' UNION ALL SELECT 'T' UNION ALL SELECT 'U' UNION ALL SELECT 'V' UNION ALL SELECT 'W' UNION ALL SELECT 'X' UNION ALL SELECT 'Y' UNION ALL SELECT 'Z') t
CREATE TABLE id_list (id char(4) PRIMARY KEY);
INSERT id_list
SELECT c1.i+c2.i+c3.i+c4.i
FROM #t c1, #t c2, #t c3, #t c4
WHERE c1.i+c2.i+c3.i+c4.i NOT LIKE '[0-9]%[A-Z]%' --Eliminate alphas in the first 10000 to preserve existing ids.
When you need the next id:
DECLARE #curr_id char(4) = '9ZZZ'
DECLARE #next_id char(4)
SELECT TOP 1 #next_id = [id] FROM id_list WHERE [id] > #curr_id
PRINT #next_id
A000

create a list of the alphabet via SQL

I would like to produce results from the alphabet via SQL?
Something like this:
A
B
C
D
E
F
I have tried:
SELECT
'A','B','C'
But this just produces the letters across in columns.
Use table spt_values and convert values to chars
SELECT Char(number+65)
FROM master.dbo.spt_values
WHERE name IS NULL AND
number < 26
EDIT: This table is undocumented. But, it's used by many system storedprocedures and it's extremely unlikely for this table to disappear, since all those procs should be rewritten. This would be like poking a sleeping lion.
--
-- tally = 9466 rows in my db, select upper & lower alphas
--
;
with
cte_tally as
(
select row_number() over (order by (select 1)) as n
from sys.all_columns
)
select
char(n) as alpha
from
cte_tally
where
(n > 64 and n < 91) or
(n > 96 and n < 123);
go
The sys.all_columns is a documented table. It will be around for a while.
http://technet.microsoft.com/en-us/library/ms177522.aspx
It seems clear that the table, sp_values, is undocumented and can be removed in the future without any comment from Microsoft.
Try:
select 'A' union
select 'B' union
select 'C'
If you want to print from A to Z, then:
DECLARE #i int=65
WHILE #i < 91
BEGIN
PRINT CHAR(#i);
SET #i=#i+1;
END
You could use U-SQL
Select
[letter]
From
(
Values
('A')
,('B')
,('C')
) As [Letters]([letter])
with AlphabetList as
(
select char(65) letter
union all
select char(ascii(letter) + 1)
from AlphabetList
where letter <> 'Z'
)
select *
from AlphabetList
Using a recursive CTE (common table expression) to output the alphabet, A-Z, one row per letter/character:
;WITH cteAZ AS
(
SELECT ASCII('A') [AlphaCode],CAST('A' AS CHAR(1)) [Alpha]
UNION ALL
SELECT a.AlphaCode + 1 [AlphaCode],CAST(CHAR(a.AlphaCode + 1) AS CHAR(1)) [Alpha]
FROM cteAZ a WHERE a.AlphaCode < ASCII('Z')
)
SELECT
az.AlphaCode,az.Alpha
FROM
cteAZ az
Try this
;WITH CHARA2Z
AS (
SELECT
[ASCII] = ASCII('A'),
[LETTER] = CHAR(ASCII('A'))
UNION ALL
SELECT
[ASCII] + 1,
[LETTER] = CHAR([ASCII]+1)
FROM
CHARA2Z
WHERE
[ASCII] < ASCII('Z')
)
SELECT * FROM CHARA2Z
Replace 'A' & 'Z' by 'a' & 'z' for small letters.
Stemming from #MarkoJuvančič's answer, but a solution that will work on every SQL DBMS:
CREATE TEMPORARY TABLE alphabet (ltr CHAR(1));
SET #row_number = 0;
INSERT INTO alphabet
SELECT
CHAR((#row_number:=#row_number + 1) +64) -- 'A' is the 65th character on the ASCII table
FROM customer -- any table with 26 or more rows could suffice for this job
WHERE #row_number < 26;
SELECT 'A' letter
UNION ALL
SELECT 'B' letter
UNION ALL
SELECT 'C' letter
UNION ALL
SELECT 'D' letter
UNION ALL
SELECT 'E' letter
UNION ALL
SELECT 'F' letter
UNION ALL
SELECT 'G' letter
UNION ALL
SELECT 'H' letter
UNION ALL
SELECT 'I' letter
UNION ALL
SELECT 'J' letter
UNION ALL
SELECT 'K' letter
UNION ALL
SELECT 'L' letter
UNION ALL
SELECT 'M' letter
UNION ALL
SELECT 'N' letter
UNION ALL
SELECT 'O' letter
UNION ALL
SELECT 'P' letter
UNION ALL
SELECT 'Q' letter
UNION ALL
SELECT 'R' letter
UNION ALL
SELECT 'S' letter
UNION ALL
SELECT 'T' letter
UNION ALL
SELECT 'U' letter
UNION ALL
SELECT 'V' letter
UNION ALL
SELECT 'W' letter
UNION ALL
SELECT 'X' letter
UNION ALL
SELECT 'Y' letter
UNION ALL
SELECT 'Z' letter;

how to convert string format

How can I convert a number to a formatted string of fixed length in SQL Server 2005 using T-SQL?
e.g.
Inputs: 5,01,007,0009,00011,01200
Result: 000005,000007,000009,0000011,001200
Looks like you want it 6 wide. Try putting your pad characters, in this case, zeros, to the left of your int/string, and then take the 6 chars on the right side of the string.
How about this?
DECLARE #i int;
SELECT #i = 1200;
SELECT RIGHT('000000'+ CAST(#i as varchar(10)), 6);
The best way I've found to do this is using the STR statement:
SELECT REPLACE(STR(123, 6), ' ', '0')
The above statement will result in 000123. It basically converts 123 to a string of 6 characters (padded with spaces), then uses REPLACE to replace the spaces with zeros.
TRY THIS
WITH t(c) AS
(
SELECT 1.99 UNION ALL
SELECT 21.34 UNION ALL
SELECT 1797.94 UNION ALL
SELECT 300.36 UNION ALL
SELECT 21.99 UNION ALL
SELECT -2.31
)
select
c,
replicate(0,4-len(replace(substring(cast(c as varchar(10)),1,charindex('.',c)-1),'-','')))+''+
replace(replace(substring(cast(c as varchar(10)),1,charindex('.',c)-1),'-',''),'','-') +''+
replace(substring(cast(c as varchar(10)),charindex('.',c),len(c)),'-','')
from t
i will still optimize it
Best way for dynamic leading zero allocation
WITH t(c) AS ( SELECT 1.99 UNION ALL
SELECT 21.34 UNION ALL SELECT
1797.94 UNION ALL SELECT 300.36 UNION ALL SELECT 21.99 UNION ALL
SELECT 2.31 ),
Final (a,b,c,d) as ( Select c,
substring(cast(c as
varchar(10)),1,charindex('.',c)-1) ,
(select max(len(substring(cast(c as
varchar(10)),1,charindex('.',c)-1)))
from t), substring(cast(c as
varchar(10)),charindex('.',c)+1,len(c))
From t group by c )
select a,
right(replicate('0',c)+''+b,4)+'.'+d
from final
declare #i int
set #i=10
print replace(str(#i),' ','0')