ORA-01722: invalid number with RPAD - sql

There is a case where I want to take the date of birth and pad it with eight ' ' empty spaces
This is what I have
CASE
WHEN Date_of_Birth IS NULL THEN rpad(' ', 8, ' ')
ELSE substr(
(replace(
to_char(to_date(DATE_OF_BIRTH,'YYYY-MM-DD HH24:MI:SS'), 'MM/DD/YYYY'),
'/',
''
) + rpad(' ',(length(' ') * 8),' '))
,1,8
)
END Date_of_Birth_1,
The DATE_OF_BIRTH is NVARCHAR2. I'm getting the error saying that RPAD is an invalid number,
I figured changing the date to a to_char would change it to a string then to add the spaces at the end of it.

You appear to want to convert the string DATE_OF_BIRTH column from YYYY-MM-DD HH24:MI:SS format to MMDDYYYY format and if it is NULL then provide 8 spaces.
That can be achieved without the complicated use of string functions using:
COALESCE(
TO_CHAR(TO_DATE(DATE_OF_BIRTH,'YYYY-MM-DD HH24:MI:SS'), 'MMDDYYYY'),
' '
) AS Date_of_Birth_1,
Note: there is no need to replace the / separators in a date or to remove trailing spaces if you never include them in the first palce.

by the + sign, did you mean to concatenate strings like in Javascript? String concatenation in Oracle uses ||
Aside from that, you should also check to make sure date_of_birth is in fact in the YYYY-MM-DD HH24:MI:SS format in your data or you can get the same error.

It is the concatenation operator (as Paul already said).
Though, you could simplify that code.
date_of_birth is the original value, stored in the table
date_of_birth_1 is result based on your code
date_of_birth_2 is result on my (simplified) code
SQL> set null 'null'
SQL> select
2 id,
3 date_of_birth,
4 --
5 CASE WHEN Date_of_Birth IS NULL THEN
6 rpad(' ', 8, ' ')
7 ELSE substr( (replace( to_char(to_date(DATE_OF_BIRTH,'YYYY-MM-DD HH24:MI:SS'), 'MM/DD/YYYY'), '/', '' ) || rpad(' ',(length(' ') * 8),' ')) ,1,8 )
8 END Date_of_Birth_1,
9 --
10 case when date_of_birth is null then ' '
11 else to_char(to_date(date_of_birth, 'yyyy-mm-dd hh24:mi:ss'), 'mmddyyyy')
12 end date_of_birth_2
13 from test;
ID DATE_OF_BIRTH DATE_OF_BIRTH_1 DATE_OF_BIRTH_2
---------- -------------------- -------------------- --------------------
1 2020-08-25 13:20:28 08252020 08252020
2 2015-03-18 03182015 03182015
3 null
SQL>

Related

Oracle SQL developer shows invalid number for the code below

I'm trying to subtract two columns which holds "systimestamp" as the date and time value. i'm getting
'ORA-01722: invalid number'
as the error message. Would be of great help if somebody can help out.
I tried googling this error and it says the character string might not be a valid literal . It works fine for other records , only problem is when i'm trying to subtract it.
SELECT ETL_BATCH_ID,
ETL_BATCH_GROUP_NAME,
TO_CHAR(BATCH_START_TS,'DD-MON-YY')
|| ' '
||TO_CHAR(BATCH_START_TS,'HH24:MI:SS') "BATCH_START_TS",
TO_CHAR(DW_DM_END_TS ,'DD-MON-YY')
||' '
||TO_CHAR(DW_DM_END_TS , 'HH24:MI:SS') "DW_DM_END_TS" ,
(TO_CHAR(DW_DM_END_TS , 'HH24:MI:SS')) - (TO_CHAR(BATCH_START_TS,'HH24:MI:SS')) "COMPLETION_TIME"
FROM bi_etl.bi_etl_batch
WHERE ETL_BATCH_GROUP_NAME = 'CMD';
For ex ,
BATCH_START_TS || DW_DM_END_TS || COMPLETION_TIME
01-OCT-19 3:18:00 ||01-OCT-19 3:20:00 || 00:02:00
So the completion time is (DW_DM_END_TS) - (BATCH_START_TS) = COMPLETION_TIME
But it's throwing the particular error as shown above
Apply Substraction directly on those timestamp values :
select DW_DM_END_TS - BATCH_START_TS as "COMPLETION_TIME"
from bi_etl_batch;
COMPLETION_TIME
-000000000 00:02:00.000000
Demo
Substraction is impossible and has no sense among two string type values.
U cann't any arifmetic operation on char.
so change To_char -> To_date, or remove to_char if fields is date
For an exact result, You need to retrieve hour, minute and second from the difference in the timestamp , Like the following:
SELECT
ETL_BATCH_ID,
ETL_BATCH_GROUP_NAME,
BATCH_START_TS,
DW_DM_END_TS,
LPAD(EXTRACT(HOUR FROM COMPLETION_TIME), 2, 0)
|| ':'
|| LPAD(EXTRACT(MINUTE FROM COMPLETION_TIME), 2, 0)
|| ':'
|| LPAD(ROUND(EXTRACT(SECOND FROM COMPLETION_TIME)), 2, 0) AS COMPLETION_TIME
FROM
(
SELECT
ETL_BATCH_ID,
ETL_BATCH_GROUP_NAME,
TO_CHAR(BATCH_START_TS, 'DD-MON-YY')
|| ' '
|| TO_CHAR(BATCH_START_TS, 'HH24:MI:SS') "BATCH_START_TS",
TO_CHAR(DW_DM_END_TS, 'DD-MON-YY')
|| ' '
|| TO_CHAR(DW_DM_END_TS, 'HH24:MI:SS') "DW_DM_END_TS",
DW_DM_END_TS - BATCH_START_TS "COMPLETION_TIME"
FROM
BI_ETL.BI_ETL_BATCH
WHERE
ETL_BATCH_GROUP_NAME = 'CMD'
);
Example:
SQL> SELECT
2 LPAD(EXTRACT(HOUR FROM DIFF), 2 , 0) || ':' ||
3 LPAD(EXTRACT(MINUTE FROM DIFF), 2 , 0) || ':' ||
4 LPAD(ROUND(EXTRACT(SECOND FROM DIFF)), 2 , 0) as diff
5 FROM
6 (
7 SELECT
8 SYSTIMESTAMP - ( SYSTIMESTAMP - 2 / 1440 ) AS DIFF
9 FROM
10 DUAL
11 );
DIFF
--------------------------
00:02:01
SQL>
Cheers!!

How to use IN operator within the table data when using Oracle SQL Developer?

I have one table which contains columns and data as below:
KEY(string) DAY(string)
1 (1,2,3,4)
2 (2,3,4,5)
I would like to select the row which has 1 inside the day column. Therefore, I construct the following statement:
select * from test where 1 in day;
I got an error after running this:
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number.
But if I write the statement as below:
select * from test where 1 in (1,2,3,4,5);
It works fine.
How can I use IN operator within the list stored in the table?
That would be LIKE:
select * from test
where day like '%1%'
It presumes that there aren't 10 or 11 or 31 days in that column, otherwise LIKE will find all of them, which is probably not what you wanted. In that case, see if %,1,% helps (which is a simple "solution").
But, if days are "7 days in a week", the initial statement should be OK.
If you have to compare today's day number with the DAY values, then see if this helps: you don't have to use Julian dates, MOD function, whatever you planned to do as Oracle offers TO_CHAR's D format mask which returns day number. For example, today is Thursday, 10th of October 2019. Function returns
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> select sysdate today,
2 to_char(sysdate, 'd') todays_number
3 from dual;
TODAY T
---------- -
10.10.2019 4
so you can use it in like:
SQL> with test (key, day) as
2 (select 1, '1,2,3,4' from dual union all
3 select 2, '2,3,4,5' from dual
4 )
5 select key,
6 day,
7 to_char(sysdate, 'd') todays_number
8 from test
9 where day like '%' || to_char(sysdate, 'd') || '%';
KEY DAY T
---------- ------- -
1 1,2,3,4 4
2 2,3,4,5 4
SQL>
If today was, for example, Friday 25th of October 2019, then you'd have
SQL> with test (key, day) as
2 (select 1, '1,2,3,4' from dual union all
3 select 2, '2,3,4,5' from dual
4 )
5 select key,
6 day,
7 to_char(date '2019-10-25', 'd') todays_number
8 from test
9 where day like '%' || to_char(date '2019-10-25', 'd') || '%';
KEY DAY T
---------- ------- -
2 2,3,4,5 5
SQL>
Basically, I think that it might work.
(1,2,3,4) is not a list or numbers it is a string with the characters '(', '1', ',', '2', ',', '3', ',', '4' and ')'.
Your query is effectively:
SELECT *
FROM DUAL
WHERE 1 IN ( '(a,b,c,d)' )
Where the a, b, c and d character just happen to have been replaced with numeric characters.
You get the error because the data-types do not match as 1 is a number and days is a string (it is not a list of numbers).
Instead you can use:
select *
from test
where REPLACE( REPLACE( days, '(', ',' ), ')', ',' ) LIKE '%,' || 1 || ',%';
Alternatively, you could store the "list" as an actual collection/nested table (rather than a delimited string):
CREATE TYPE int_list IS TABLE OF INT;
CREATE TABLE test ( key NUMBER, days int_list )
NESTED TABLE days STORE AS test__days;
INSERT INTO test ( key, days ) VALUES ( 1, int_list( 1, 2, 3, 4 ) );
INSERT INTO test ( key, days ) VALUES ( 2, int_list( 2, 3, 4, 5 ) );
Then you can use:
SELECT *
FROM test
WHERE 1 MEMBER OF days

Oracle - String to Double - Dynamic Scale

I am in the situation that inside the database various double values are stored as a string.
(this can not be changed due to some other reasons!)
The numbers can have a different amount of numbers after & before the decimal separator.
The decimal separator of the stored values is a .
The default decimal separator of the database might possibly change in the future.
Examples:
1.1
111.1
1.111
11.11
1.1111
I now need to select those as numbers to be able to compare for bigger or smaller values, etc.
Therefore I tried to convert the strings to numbers. I found a hint at this answer: click.
Unfortunately using this as a test:
SELECT TO_NUMBER('10.123', TRANSLATE('10.123', ' 1,234.567890', TO_CHAR(9999.9, '9G999D9') || '99999'))
FROM DUAL;
Somehow converts the number to 10123, completely removing the decimal separation, so this query gives no result (just for verification):
SELECT * FROM(SELECT TO_NUMBER('10.123', TRANSLATE('10.123', ' 1,234.567890', TO_CHAR(9999.9, '9G999D9') || '99999')) AS NUM
FROM DUAL) WHERE NUM < 11;
So I stepped through the single parts to see if I can find an error:
SELECT TO_CHAR(9999.9, '9G999D9') FROM DUAL; -- 9.999,9
SELECT TO_CHAR(9999.9, '9G999D9') || '99999' FROM DUAL; -- 9.999,999999
SELECT TRANSLATE('10.123', ' 1,234.567890', ' 9.999,999999')
FROM DUAL; -- 99,999
SELECT TRANSLATE('10.123', ' 1,234.567890', TO_CHAR(9999.9, '9G999D9') || '99999')
FROM DUAL; -- 99,999
As you can see I get a . as group separator and a , as decimal separator for the database.
I do not understand why it does not correctly convert the number.
Thank you already for any help!
Try using this version of to_number
TO_NUMBER( string1 [, format_mask] [, nls_language])
For example:
SELECT to_number('1.1111','9G990D00000', 'NLS_NUMERIC_CHARACTERS = ''.,''') FROM DUAL
You can try this,
alter session set NLS_NUMERIC_CHARACTERS = '.,';
WITH INPUT_TEST AS (
SELECT '.' decimal_operator, '1.1' num_in_char from dual
UNION ALL
SELECT '.' decimal_operator, '111.1 ' from dual
UNION ALL
SELECT '.' decimal_operator, '1.111 ' from dual
UNION ALL
SELECT '.' decimal_operator, '11.11 ' from dual
UNION ALL
SELECT '.' decimal_operator, '1.1111' from dual)
SELECT TO_NUMBER(REPLACE(num_in_char, '.', decimal_separator)) to_num
FROM input_test a, (select SUBSTR(value, 1, 1) decimal_separator
from nls_session_parameters
where parameter = 'NLS_NUMERIC_CHARACTERS') b;
TO_NUM
----------
1.1
111.1
1.111
11.11
1.1111
alter session set NLS_NUMERIC_CHARACTERS = ',.';
Run the select statement above again.
TO_NUM
----------
1,1
111,1
1,111
11,11
1,1111

How to convert negative and comma separated values to numbers oracle?

I have values like -
43,042
- 1
44,889
35,224
- 1,000
17,683
and the data type is obviously varchar 2.
I have to put a condition in the column to select values above 5000 but I am unable to convert it to number due to presence of commas and negative signs.
How can I convert it to number to perform this check.
Thanks in advance.
try this
select to_number(replace(your_varchar_column,',','.'))
from your_table
where to_number(replace(your_varchar_column,',','.')) >5000
CREATE OR REPLACE function to_numeric(v in varchar2)
return number as
num number;
begin
num := to_number(v);
return num;
exception
when others then
return null;
end;
/
You can use to_number() with a suitable format model to convert your strings to numbers:
to_number(your_string, '999,999,999')
with the appropriate number of groups and group separators. I'm assuming, given that you're looking for values above 5000, that the commas represent group separators in your string and not decimal separators. It would be safer, to avoid relying on your session NLS settings, to be more explicit about it:
to_number(replace(your_string, ' '), '999G999G999', 'NLS_NUMERIC_CHARACTERS=''.,''')
The slight complication in your sample data is the presence of spaces in the strings too. You can use replace() to strip those out:
to_number(replace(your_string, ' '), '999,999,999')
so your condition could be:
where to_number(replace(your_string, ' '), '999,999,999') > 5000
or more safely:
where to_number(replace(your_string, ' '), '999G999G999', 'NLS_NUMERIC_CHARACTERS=''.,''')
> 5000
Demo with your strings coming from a CTE:
with t (n) as (
select '43,042 ' from dual
union all select '- 1' from dual
union all select '44,889' from dual
union all select '35,224' from dual
union all select '- 1,000' from dual
union all select '17,683' from dual
)
select n, to_number(replace(n, ' '), '999,999,999') as converted
from t
where to_number(replace(n, ' '), '999,999,999') > 5000;
N CONVERTED
------- ----------
43,042 43042
44,889 44889
35,224 35224
17,683 17683
or more safely:
with t (n) as (
select '43,042 ' from dual
union all select '- 1' from dual
union all select '44,889' from dual
union all select '35,224' from dual
union all select '- 1,000' from dual
union all select '17,683' from dual
)
select n, to_number(replace(n, ' '), '999G999G999', 'NLS_NUMERIC_CHARACTERS=''.,''')
as converted
from t
where to_number(replace(n, ' '), '999G999G999', 'NLS_NUMERIC_CHARACTERS=''.,''') > 5000;
Of course, you should not be storing numbers as string in the first place. Use the correct data type and you don't have to deal with this sort of issue. You also don't have to worry about string which are not in the format you expect, and which can therefore cause ORA-01722 errors for many reasons... even a number that doesn't have group separators, or has them in the wrong place, will error if you've stated they should be in certain places.

Oracle SQL inserting parenthesis into phone number

The original format:
123-456-7890
My goal format:
(123)456-7890
I wanted to go the route of concatenating between substrings but I continually get flagged for errors. I am unsure of a better method to go about implementing a way to format.
My query:
select || '(' || substr(telephone,0, 3)|| ')' ||
substr(telephone,4, 3)|| ' '||
substr(telephone,7, 4)) as telephone,
from book;
My current error:
"missing expression"
You have an extra dangling parenthesis at the end of your SELECT, and you also have a dangling concatenation operator || in the front. Try this:
SELECT '(' || SUBSTR(telephone, 0, 3) || ')' ||
SUBSTR(telephone, 4, 3) || ' ' || SUBSTR(telephone, 7, 4) AS telephone
FROM book
Update:
You should really use this query, because it turns out you also had a problem with forming your desired output as well:
SELECT '(' || SUBSTR(telephone, 1, 3) || ')' || SUBSTR(telephone, 5, 8) AS telephone
FROM book
You can use regular expressions to do.
select regexp_replace
(phoneNo,
'([[:digit:]]{3})\-([[:digit:]]{3})\-([[:digit:]]{4})',
'(\1)\2-\3'
)
from(
select '123-456-7890' as phoneNo from dual)
Output
(123)456-7890
SELECT '123-456-7890','('||SUBSTR('123-456-7890',1,3)||')'||SUBSTR('123-456-7890',5,8) FROM dual;
Using SUBSTR:
SQL> WITH sample_data AS(
2 SELECT '123-456-7890' num FROM dual
3 )
4 -- end of sample_data mimicking real table
5 SELECT num,
6 '('
7 || SUBSTR(num, 1, 3)
8 ||
9 ')'
10 || SUBSTR(num, 5, 8) AS my_num
11 FROM sample_data;
NUM MY_NUM
------------ ---------------
123-456-7890 (123)456-7890
SQL>
Remember, the index for SUBSTR starts from 1. It is bad practice to use 0 as starting index.
You could also do it using REGEXP_REPLACE.
Pattern: (\d{3})(-)(\d{3})(-)(\d{4})
Expression: regexp_replace(num, '(\d{3})(-)(\d{3})(-)(\d{4})', '(\1)\3\4\5')
For example,
SQL> WITH sample_data AS(
2 SELECT '123-456-7890' num FROM dual
3 )
4 -- end of sample_data mimicking real table
5 SELECT num,
6 regexp_replace(num, '(\d{3})(-)(\d{3})(-)(\d{4})', '(\1)\3\4\5') my_num
7 FROM sample_data;
NUM MY_NUM
------------ ---------------
123-456-7890 (123)456-7890
SQL>