Multiline bind parameter - sql

I'm trying the following query from DBeaver (backend is oracle):
SELECT * FROM mytable where mycolumn in (REPLACE( :req_id_list, CHR(13), ','))
when it prompts for the value of req_id_list I want to paste the values from Excel, which will be one value per line. the query is failing with ORA-00907: missing right parenthesis. is there a way to convert the multiline value to a CSV one ?

I don't use DBeaver so this is a SQL*Plus example. Basically, you'll have to "split" that multi-line input value into separate rows (that's what subquery in lines #8 - 10 does):
Declaring a bind variable:
SQL> var req_id_list varchar2(20)
Storing A + carriage return + C into it:
SQL> exec :req_id_list := 'A' || chr(13) || 'C';
PL/SQL procedure successfully completed.
Query itself (lines #1 - 5 represent sample data; I expect A and C to be returned as that's what I passed to req_id_list):
SQL> with mytable (mycolumn) as
2 (select 'A' from dual union all
3 select 'B' from dual union all
4 select 'C' from dual
5 )
6 select *
7 from mytable
8 where mycolumn in (select regexp_substr(replace(:req_id_list, chr(13), '#'), '[^#]+', 1, level)
9 from dual
10 connect by level <= regexp_count(:req_id_list, chr(13)) + 1
11 );
M
-
A
C
SQL>

Related

Oracle SQL - find and replace ASCII

In my database, special characters have got inserted with these ASCII values
ASCII(' ') ASCII('')
49828 32
There is ASCII Value 49828 shown in the column description that is showing as special character ¤
How do I find all the values that have this special character? and how to replace it with a regular space (ASCII 32)
I'd say you'd use REPLACE (as you said).
Sample table:
SQL> create table test (col) as
2 select 'x' || chr(67) || 'y' from dual union all
3 select 'x' || chr(49828) || 'y' from dual;
Table created.
Contents (disregard Ą displayed in my SQL*Plus & my database):
SQL> select * from test;
COL
----
xCy
xĄy
Update only rows that contain that value:
SQL> update test set
2 col = replace(col, chr(49828), chr(32))
3 where instr(col, chr(49828)) > 0;
1 row updated.
Result:
SQL> select * from test;
COL
----
xCy
x y
SQL>

my table contain data in below format and does not contain any automated primary key [duplicate]

I have column in my database where the values are coming like the following:
3862,3654,3828
In dummy column any no. of comma separated values can come. I tried with following query but it is creating duplicate results.
select regexp_substr(dummy,'[^,]+',1,Level) as dummycol
from (select * from dummy_table)
connect by level <= length(REGEXP_REPLACE(dummy,'[^,]+'))+1
I am not understanding the problem. Can anyone can help?
Works perfectly for me -
SQL> WITH dummy_table AS(
2 SELECT '3862,3654,3828' dummy FROM dual
3 )
4 SELECT trim(regexp_substr(dummy,'[^,]+',1,Level)) AS dummycol
5 FROM dummy_table
6 CONNECT BY level <= LENGTH(REGEXP_REPLACE(dummy,'[^,]+'))+1
7 /
DUMMYCOL
--------------
3862
3654
3828
SQL>
There are many other ways of achieving it. Read Split single comma delimited string into rows.
Update Regarding the duplicates when the column is used instead of a single string value. Saw the use of DBMS_RANDOM in the PRIOR clause to get rid of the cyclic loop here
Try the following,
SQL> WITH dummy_table AS
2 ( SELECT 1 rn, '3862,3654,3828' dummy FROM dual
3 UNION ALL
4 SELECT 2, '1234,5678' dummy FROM dual
5 )
6 SELECT trim(regexp_substr(dummy,'[^,]+',1,Level)) AS dummycol
7 FROM dummy_table
8 CONNECT BY LEVEL <= LENGTH(REGEXP_REPLACE(dummy,'[^,]+'))+1
9 AND prior rn = rn
10 AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL
11 /
DUMMYCOL
--------------
3862
3654
3828
1234
5678
SQL>
Update 2
Another way,
SQL> WITH dummy_table AS
2 ( SELECT 1 rn, '3862,3654,3828' dummy FROM dual
3 UNION ALL
4 SELECT 2, '1234,5678,xyz' dummy FROM dual
5 )
6 SELECT trim(regexp_substr(t.dummy, '[^,]+', 1, levels.column_value)) AS dummycol
7 FROM dummy_table t,
8 TABLE(CAST(MULTISET
9 (SELECT LEVEL
10 FROM dual
11 CONNECT BY LEVEL <= LENGTH (regexp_replace(t.dummy, '[^,]+')) + 1
12 ) AS sys.OdciNumberList)) LEVELS
13 /
DUMMYCOL
--------------
3862
3654
3828
1234
5678
xyz
6 rows selected.
SQL>
Giving a PL/SQL example where parsing over a table with an ID and column name. This will parse and print out each ID and the parsed value which could then be inserted into a new table or used in some other way.
Input
Column_ID Column_Name
123 (3862,3654,3828)
Output
Column_ID Column_Name
123 3862
123 3654
123 3828
PL/SQL Code
declare
table_name1 varchar2(1000);
string_to_parse varchar2(2000); -- assign string to table name
string_length number := 0; -- string length for loop
string_value varchar2(2000); -- string value to store value in
column_id number;
begin
--some table in the format '123' as column_id, '(3862,3654,3828)' as column_name
--remove the parenthesis or other special characters if needed
update some_table t
set t.column_name = regexp_replace(t.column_name,'\(|\)','');
commit;
for i in (
select * from some_table
) loop
column_id := i.column_id; --assign the id of the colors
string_to_parse := i.column_name; -- assign string to be parsed
if string_to_parse is null then
--at this point insert into a new table, or do whatever else you need
dbms_output.put_line(column_id || ' ' || string_value);
else
--String to parse is the comma
string_to_parse := string_to_parse||',';
string_length := length(string_to_parse) - length(replace(string_to_parse,',',''));
-- Loop through string from parameter
for i in 1 .. string_length loop
-- [^,] matches any character except for the ,
select regexp_substr(string_to_parse,'[^,]+',1,i)
into string_value -- stores value into string_value
from dual; -- dual is a dummy table to work around
--at this point insert into a new table, or do whatever else you need
dbms_output.put_line(column_id || ' ' || string_value);
--clear out the string value
string_value := null;
end loop;
end if;
end loop;
end;

using Oracle SQL - regexp_substr to split a record

I need to split the record for column CMD.NUM_MAI which may contain ',' or ';'.
I did this but it gave me an error:
SELECT REGEXP_SUBSTR (expression.num_mai,
'[^;|,]+',
1,
LEVEL)
FROM (SELECT CMD.num_cmd,
(SELECT COMM.com
FROM COMM
WHERE COMM.cod_soc = CMD.cod_soc AND COMM.cod_com = 'URL_DSD')
AS cod_url,
NVL (CONTACT.nom_cta, TIERS.nom_ct1) AS nom_cta,
NVL (CONTACT.num_mai, TIERS.num_mai) AS num_mai,
NVL (CONTACT.num_tel, TIERS.num_tel) AS num_tel,
TO_CHAR (SYSDATE, 'hh24:MI') AS heur_today
FROM CMD, TIERS, CONTACT
WHERE ( (CMD.cod_soc = :CMD_cod_soc)
AND (CMD.cod_eta = :CMD.cod_eta)
AND (CMD.typ_cmd = :CMD.typ_cmd)
AND (CMD.num_cmd = :CMD.num_cmd))
AND (TIERS.cod_soc(+) = CMD.cod_soc)
AND (TIERS.cod_trs(+) = CMD.cod_trs_tra)
AND (TIERS.cod_soc = CONTACT.cod_soc(+))
AND (TIERS.cod_trs = CONTACT.cod_trs(+))
AND (CONTACT.lib_cta(+) = 'EDITION')) experssion
CONNECT BY REGEXP_SUBSTR (expression.num_mai,'[^;|,]+',1,LEVEL)
Error 1:
The expression in CONNECT BY clause is unary. You have to specify both left and right hand side operands.
Try something like,
CONNECT BY REGEXP_SUBSTR (expression.num_mai,'[^;|,]+',1,LEVEL) IS NOT NULL
Error 2:
Your bind variable name is wrong. Ex: :CMD_cod_eta
Perhaps you wanted this way!
( (CMD.cod_soc = :CMD_cod_soc)
AND (CMD.cod_eta = :CMD_cod_eta)
AND (CMD.typ_cmd = :CMD_typ_cmd)
AND (CMD.num_cmd = :CMD_num_cmd))
This is a common question, I'd put into a function, then call it as needed:
CREATE OR REPLACE function fn_split(i_string in varchar2, i_delimiter in varchar2 default ',', b_dedup_tokens in number default 0)
return sys.dbms_debug_vc2coll
as
l_tab sys.dbms_debug_vc2coll;
begin
select regexp_substr(i_string,'[^' || i_delimiter || ']+', 1, level)
bulk collect into l_tab
from dual
connect by regexp_substr(i_string, '[^' || i_delimiter || ']+', 1, level) is not null
order by level;
if (b_dedup_tokens > 0) then
return l_tab multiset union distinct l_tab;
end if;
return l_tab;
end;
/
This will return a table of varchar2(1000), dbms_debug_vc2coll, which is a preloaded type owned by SYS (or you could create your own type using 4000 perhaps). Anyway, an example using it (with space, comma, or semi-colon used as delimiters):
with test_data as (
select 1 as id, 'A;test;test;string' as test_string from dual
union
select 2 as id, 'Another string' as test_string from dual
union
select 3 as id,'A,CSV,string' as test_string from dual
)
select d.*, column_value as token
from test_data d, table(fn_split(test_string, ' ,;', 0));
Output:
ID TEST_STRING TOKEN
1 A;test;test;string A
1 A;test;test;string test
1 A;test;test;string test
1 A;test;test;string string
2 Another string Another
2 Another string string
3 A,CSV,string A
3 A,CSV,string CSV
3 A,CSV,string string
You can pass 1 instead of 0 to fn_split to dedup the tokens (like the repeated "test" token above)

How to recognize if a variable contains a newline character in Oracle

I have a procedure which takes 2 variables as input, one among them may have string characters separated by enter or space.
Space however is easy to figure out, but how to we figure out if the variable has a newline character in it.
I have tried using chr(10) but no use, because I have to recognize if the strings are separated by a newline character. By the way even chr(10) doesn't work to insert string divided with space.
select 'ABC' || chr(10) || 'DEF' as c from dual
I currently have no such variable as input so can't even experiment to narrow down to some solutions, Also the above query isn't running fine, I mean it's not giving output like below.
ABC
DEF
I have also searched for different oracle documentation, but didn't find any.
Help would be appreciated.
A new line depends on the Operating system. In Unix based OS, it is CHR(10), in Windows it is CHR(13) followed by CHR(10).
You could use either of the following:
LIKE '%'||chr(10)||'%'
INSTR(column_name, chr(10)) > 0
Let's look at test cases in Windows OS:
SQL
Using LIKE
SQL> WITH DATA AS(
2 SELECT 'ABC' || chr(10) || 'DEF' AS c FROM dual UNION ALL
3 SELECT 'PQR' || ' ' || 'XYZ' AS c FROM dual UNION ALL
4 SELECT 'QWE' || CHR(13) || 'RTY' AS c FROM dual UNION ALL
5 SELECT 'no_space' AS c FROM dual
6 )
7 SELECT * FROM DATA WHERE c LIKE '%'||chr(10)||'%';
C
--------
ABC
DEF
SQL>
Using INSTR
SQL> WITH DATA AS(
2 SELECT 'ABC' || chr(10) || 'DEF' AS c FROM dual UNION ALL
3 SELECT 'PQR' || ' ' || 'XYZ' AS c FROM dual UNION ALL
4 SELECT 'QWE' || CHR(13) || 'RTY' AS c FROM dual UNION ALL
5 SELECT 'no_space' AS c FROM dual
6 )
7 SELECT * FROM DATA WHERE INSTR(c, chr(10)) > 0;
C
--------
ABC
DEF
SQL>
PL/SQL
Using LIKE
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 c VARCHAR2(100);
3 BEGIN
4 c:='ABC' || chr(10) || 'DEF';
5 IF c LIKE '%'||chr(10)||'%' THEN
6 dbms_output.put_line('found chr(10)');
7 ELSE
8 dbms_output.put_line('not found');
9 END IF;
10 END;
11 /
found chr(10)
PL/SQL procedure successfully completed.
SQL>
Using INSTR
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 c VARCHAR2(100);
3 BEGIN
4 c:='ABC' || chr(10) || 'DEF';
5 IF INSTR(c, chr(10)) > 0 THEN
6 dbms_output.put_line('found chr(10)');
7 ELSE
8 dbms_output.put_line('not found');
9 END IF;
10 END;
11 /
found chr(10)
PL/SQL procedure successfully completed.
SQL>
create table sample (a varchar2(100));
insert into sample (a) values ('HI_next_line
hello_next_line
hello2');
insert into sample (a) values ('singleline1');
insert into sample (a) values ('singleline2');
SQL> select * from sample;
A
-----------------------------------------------------------------------
HI_next_line
hello_next_line
hello2
singleline1
singleline2
SQL> select *
2 from sample
3 where instr(a, chr(10)) > 0;
A
-----------------------------------------------------------------------
HI_next_line
hello_next_line
hello2

Splitting comma separated values in Oracle

I have column in my database where the values are coming like the following:
3862,3654,3828
In dummy column any no. of comma separated values can come. I tried with following query but it is creating duplicate results.
select regexp_substr(dummy,'[^,]+',1,Level) as dummycol
from (select * from dummy_table)
connect by level <= length(REGEXP_REPLACE(dummy,'[^,]+'))+1
I am not understanding the problem. Can anyone can help?
Works perfectly for me -
SQL> WITH dummy_table AS(
2 SELECT '3862,3654,3828' dummy FROM dual
3 )
4 SELECT trim(regexp_substr(dummy,'[^,]+',1,Level)) AS dummycol
5 FROM dummy_table
6 CONNECT BY level <= LENGTH(REGEXP_REPLACE(dummy,'[^,]+'))+1
7 /
DUMMYCOL
--------------
3862
3654
3828
SQL>
There are many other ways of achieving it. Read Split single comma delimited string into rows.
Update Regarding the duplicates when the column is used instead of a single string value. Saw the use of DBMS_RANDOM in the PRIOR clause to get rid of the cyclic loop here
Try the following,
SQL> WITH dummy_table AS
2 ( SELECT 1 rn, '3862,3654,3828' dummy FROM dual
3 UNION ALL
4 SELECT 2, '1234,5678' dummy FROM dual
5 )
6 SELECT trim(regexp_substr(dummy,'[^,]+',1,Level)) AS dummycol
7 FROM dummy_table
8 CONNECT BY LEVEL <= LENGTH(REGEXP_REPLACE(dummy,'[^,]+'))+1
9 AND prior rn = rn
10 AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL
11 /
DUMMYCOL
--------------
3862
3654
3828
1234
5678
SQL>
Update 2
Another way,
SQL> WITH dummy_table AS
2 ( SELECT 1 rn, '3862,3654,3828' dummy FROM dual
3 UNION ALL
4 SELECT 2, '1234,5678,xyz' dummy FROM dual
5 )
6 SELECT trim(regexp_substr(t.dummy, '[^,]+', 1, levels.column_value)) AS dummycol
7 FROM dummy_table t,
8 TABLE(CAST(MULTISET
9 (SELECT LEVEL
10 FROM dual
11 CONNECT BY LEVEL <= LENGTH (regexp_replace(t.dummy, '[^,]+')) + 1
12 ) AS sys.OdciNumberList)) LEVELS
13 /
DUMMYCOL
--------------
3862
3654
3828
1234
5678
xyz
6 rows selected.
SQL>
Giving a PL/SQL example where parsing over a table with an ID and column name. This will parse and print out each ID and the parsed value which could then be inserted into a new table or used in some other way.
Input
Column_ID Column_Name
123 (3862,3654,3828)
Output
Column_ID Column_Name
123 3862
123 3654
123 3828
PL/SQL Code
declare
table_name1 varchar2(1000);
string_to_parse varchar2(2000); -- assign string to table name
string_length number := 0; -- string length for loop
string_value varchar2(2000); -- string value to store value in
column_id number;
begin
--some table in the format '123' as column_id, '(3862,3654,3828)' as column_name
--remove the parenthesis or other special characters if needed
update some_table t
set t.column_name = regexp_replace(t.column_name,'\(|\)','');
commit;
for i in (
select * from some_table
) loop
column_id := i.column_id; --assign the id of the colors
string_to_parse := i.column_name; -- assign string to be parsed
if string_to_parse is null then
--at this point insert into a new table, or do whatever else you need
dbms_output.put_line(column_id || ' ' || string_value);
else
--String to parse is the comma
string_to_parse := string_to_parse||',';
string_length := length(string_to_parse) - length(replace(string_to_parse,',',''));
-- Loop through string from parameter
for i in 1 .. string_length loop
-- [^,] matches any character except for the ,
select regexp_substr(string_to_parse,'[^,]+',1,i)
into string_value -- stores value into string_value
from dual; -- dual is a dummy table to work around
--at this point insert into a new table, or do whatever else you need
dbms_output.put_line(column_id || ' ' || string_value);
--clear out the string value
string_value := null;
end loop;
end if;
end loop;
end;