i get ORA-01722: invalid number error in plsql - sql

i have problem about ora 01722 i have string prols it is like "1501,1701,1901,2001,2501,2601" or "2321,1331,111231,35501" and i want control table x' column x.rol_id include prols or not but i get error in my code. here is part of my code. thanks.
function get_menu_detay_01(pmenu_kod varchar2,
proller varchar2) return sys_refcursor is
v_cr_1 sys_refcursor;
begin
open v_cr_1 for
select distinct mtd.sira_no,
mtd.seviye_1,
mtd.fa_icon_1,
mtd.seviye_2,
mtd.fa_icon_2,
mtd.seviye_3,
mtd.fa_icon_3,
ut.uygulama_tanim_id,
ut.aciklama,
ut.path,
ut.fa_icon,
ut.href,
ut.onclick
from uat.menu_tanim_d mtd
left join uat.uygulama_tanim ut
on ut.uygulama_tanim_id = mtd.uygulama_tanim_id
left join uat.uygulama_yetki uy
on mtd.uygulama_tanim_id = uy.uygulama_tanim_id
where mtd.menu_kod = pmenu_kod
and uy.rol_id in (select regexp_substr(tt.rol, '[^,]+', 1, level)
from (select proller rol
from dual t) tt
connect by regexp_substr(tt.rol, '[^,]+', 1, level) is not null)
order by mtd.sira_no;
return v_cr_1;
end;

If you say the strings you are splitting has separator , then you need to change the regular expression [^,]+ to to include , instead ; or the other way around
I just tried and its working,
WITH tst
AS
(SELECT 1501 rol_id FROM dual
UNION ALL
SELECT 1701 FROM dual
UNION ALL
SELECT 1901 FROM dual
UNION ALL
SELECT 2001 FROM dual
UNION ALL
SELECT 2501 FROM dual
UNION ALL
SELECT 2601 FROM dual
)
SELECT *
FROM tst x
WHERE x.rol_id in (select regexp_substr(tt.rol, '[^,]+', 1, LEVEL)
from (select '1701,1901,2001,2501,2601' rol
from dual t) tt
connect by regexp_substr(tt.rol, '[^,]+', 1, level) is not null);
EDIT: Test with function Please check how you call the function and pass the string in proper format or not
CREATE OR REPLACE FUNCTION get_menu_detay_01(proller VARCHAR2)
RETURN SYS_REFCURSOR
IS
v_cr_1 SYS_REFCURSOR;
BEGIN
OPEN v_cr_1 FOR
SELECT *
FROM ( SELECT 1501 rol_id FROM dual
UNION ALL
SELECT 1701 FROM dual
UNION ALL
SELECT 1901 FROM dual
UNION ALL
SELECT 2001 FROM dual
UNION ALL
SELECT 2501 FROM dual
UNION ALL
SELECT 2601 FROM dual
) x
WHERE x.rol_id IN (SELECT regexp_substr(tt.rol,'[^,)]+',1,LEVEL)
FROM (SELECT proller rol FROM dual t) tt
CONNECT BY regexp_substr(tt.rol,'[^,]+',1,LEVEL) IS NOT NULL);
RETURN v_cr_1;
END get_menu_detay_01;
Test:
set serveroutput on;
DECLARE
lo_ref_cur SYS_REFCURSOR;
lo_number NUMBER;
BEGIN
lo_ref_cur := get_menu_detay_01('1701,1901,2001,2501,2601');
LOOP
FETCH lo_ref_cur INTO lo_number;
EXIT WHEN lo_ref_cur%NOTFOUND;
dbms_output.put_line(lo_number);
END LOOP;
END;
/
Output:
------
1701
1901
2001
2501
2601
PL/SQL procedure successfully completed.

Related

I want to Create a function that returns the number of employees in a department

The query I tried is this,
CREATE OR REPLACE FUNCTION get_dno (d_no IN Employee.DepartmentNo%TYPE)
RETURN NUMBER
IS
d_cnt NUMBER;
BEGIN
SELECT COUNT(*) INTO d_cnt
FROM employee GROUP BY DeptNo=d_no;
RETURN d_cnt;
END get_dno;
and use this query below to get value from user.
DECLARE
get_dptno NUMBER;
BEGIN
get_dptno := get_dno(:d_no);
DBMS_OUTPUT.PUT_LINE('No of employees in searched DeptNo : ' ||get_dptno);
END;
But I couldn't even get the Function part to run.
The error I got was where I used GROUP BY, I think
This is the error message I got
Is there any workaround for the same logic ???
When you group by column there is no condition accept please remove code after column name DeptNo.
CREATE OR REPLACE FUNCTION get_dno (d_no IN Employee.DepartmentNo%TYPE)
RETURN NUMBER
IS
d_cnt NUMBER;
BEGIN
SELECT COUNT(*) INTO d_cnt
FROM employee GROUP BY DeptNo;
RETURN d_cnt;
END get_dno;
You are almost there, you want WHERE rather than GROUP BY and you need to work out if the column name is DepartmentNo or DeptNo and use the correct column name in the signature and in the SELECT query:
CREATE FUNCTION get_dno (
d_no IN Employee.DepartmentNo%TYPE
) RETURN NUMBER
IS
d_cnt NUMBER;
BEGIN
SELECT COUNT(*)
INTO d_cnt
FROM employee
WHERE DepartmentNo=d_no;
RETURN d_cnt;
END get_dno;
/
Then:
DECLARE
get_dptno NUMBER;
BEGIN
get_dptno := get_dno(:d_no);
DBMS_OUTPUT.PUT_LINE('No of employees in searched DeptNo : ' ||get_dptno);
END;
/
Works and, for the sample data:
CREATE TABLE employee (id, departmentno) AS
SELECT 1, 1 FROM DUAL UNION ALL
SELECT 2, 1 FROM DUAL UNION ALL
SELECT 3, 1 FROM DUAL UNION ALL
SELECT 4, 1 FROM DUAL UNION ALL
SELECT 5, 2 FROM DUAL UNION ALL
SELECT 6, 2 FROM DUAL UNION ALL
SELECT 7, 3 FROM DUAL UNION ALL
SELECT 8, 3 FROM DUAL UNION ALL
SELECT 9, 3 FROM DUAL UNION ALL
SELECT 10, 4 FROM DUAL;
If :dno is 1 then outputs:
No of employees in searched DeptNo : 4
db<>fiddle here

Error: inserting data into hana from oracle using dblink

I am trying to insert into hana database from oracle using dblink.I am getting the below error:
ERROR at line 1: ORA-20001: ORA-28500: connection from ORACLE to a
non-Oracle system returned this message: [SAP AG][LIBODBCHDB
SO][HDBODBC] General error;12000 user-defined error: line 2 col 142
(at pos 277): [12000] (range 3) user-defined error exception: no table
change allowed {HY000,NativeErr = 12000} ORA-06512: at
"POP_REMOTE_TABLES", line 58 ORA-06512: at line 1
Below is the code:
CREATE OR REPLACE VIEW VIEW_TEST_DYNAMIC
(
TRANS_OUT
)
AS
select 'insert into test_dynamic#dblink_hana(cust_id,address) values ('||cust_id||','''||address||''')' as trans_out from
(
select 10 cust_id,'9 Help Street, Level 4' address from dual union all
select 11 cust_id,'22 Victoria Street' address from dual union all
select 12 cust_id,'1495 Franklin Str.' address from dual union all
select 13 cust_id,'30 Hasivim St.,Petah-Tikva' address from dual union all
select 14 cust_id,'2 Jakaranda St' address from dual union all
select 15 cust_id,'61, Science Park Rd' address from dual union all
select 16 cust_id,'61, Social park road.' address from dual union all
select 17 cust_id,'Av. Hermanos Escobar 5756' address from dual union all
select 18 cust_id,'Ave. Hermanos Escobar 5756' address from dual union all
select 19 cust_id,'8000 W FLORISSANT Ave.' address from dual union all
select 20 cust_id,'8600 MEMORIAL PKWY SW' address from dual union all
select 21 cust_id,'8200 FLORISSANTMEMORIALWAYABOVE SW' address from dual union all
select 22 cust_id,'8600 MEMORIALFLORISSANT PKWY SW.' address from dual
) t1;
create table test_remote(local_table_name varchar2(50));
insert into test_remote values('VIEW_TEST_DYNAMIC');
procedure:
CREATE OR REPLACE PROCEDURE pop_remote_tables(p_table_name in varchar2 default 'ALL') as
l_cursor sys_refcursor;
l_trans_out varchar2(32000) := NULL;
l_processed_cnt number := 0;
cursor tab_cur is
select upper(local_table_name) local_table_name from test_remote where active_yn='Y' and
upper(local_table_name) = nvl(decode(upper(p_table_name),'ALL',NULL,upper(p_table_name)),upper(local_table_name));
BEGIN
dbms_output.put_line('Started');
for tab_rec in tab_cur
loop
dbms_output.put_line('Started processing:'||tab_rec.local_table_name);
l_processed_cnt := 0;
open l_cursor for 'select trans_out from ' || dbms_assert.sql_object_name(tab_rec.local_table_name);
loop
fetch l_cursor into l_trans_out;
exit when l_cursor%notfound;
execute immediate l_trans_out;
l_processed_cnt := l_processed_cnt + 1;
end loop;
commit;
close l_cursor;
dbms_output.put_line( 'No of records Inserted:' || l_processed_cnt);
end loop;
dbms_output.put_line('Ended');
EXCEPTION
when others then
raise_application_error(-20001, sqlerrm);
END;
/
sho err;
Can someone please help how to resolve this issue?

How can I pass comma separated value in cursor's select statement where clause

I have following Block which has a cursor and a select query. I want to pass the output of select, which is comma separated into
the cursor's select statement, into the where clause.
I know below code will throw an error because of SQL query in Declare section but how I achieve this using array or collection.
here, id column is number
code snippet:
declare
test varchar2(30);
SELECT LISTAGG(value, ', ') WITHIN GROUP (ORDER BY value2) into test from table3 where value2=12;
cursor c1 (select * from table where id in (test))
begin
for i in c1 loop
null;
end loop;
end;
Why would you ever do this?
You can simple write you select as:
Select * from table where id in (select value from table3 where value2=12)
Edit:
Also you need to open your cursor c1, for it to work AFAIK.
You can use a collection and the MEMBER OF operator:
Oracle Setup:
CREATE TYPE IntegerList AS TABLE OF NUMBER(8,0);
/
CREATE TABLE table1 ( value, value2 ) AS
SELECT 1, 1 FROM DUAL UNION ALL
SELECT 3, 4 FROM DUAL UNION ALL
SELECT 5, 3 FROM DUAL UNION ALL
SELECT 7, 2 FROM DUAL;
CREATE TABLE table2 ( id, value ) AS
SELECT 1, 11 FROM DUAL UNION ALL
SELECT 2, 22 FROM DUAL UNION ALL
SELECT 3, 33 FROM DUAL UNION ALL
SELECT 7, 77 FROM DUAL;
PL/SQL:
DECLARE
test IntegerList;
c1 SYS_REFCURSOR;
BEGIN
SELECT value
BULK COLLECT INTO test
FROM table1;
FOR r IN ( SELECT * FROM table2 WHERE id MEMBER OF test ) LOOP
DBMS_OUTPUT.PUT_LINE( r.id || ', ' || r.value );
END LOOP;
END;
/
Output:
1, 11
3, 33
7, 77
db<>fiddle here

ORA-01790 datatype: how to add the ability to use the text in the name, and not just numbers

I've got next code that I need to understand and make some changes.
To be more specific is the next challenge:
I need to give the possibility to choose not only the number, but the string for the name of the some panel.
Instead of this:
select -1 as num from dual union all
I should do this(name must contain text instead of number in this case)
select 'some_text' as num from dual union all
When I make this change, an error occurs as follows:
PL/SQL: ORA-01790: expression must have same datatype as corresponding
expression
Here is a code
REQUEST_SCRIPT:
declare
l_data clob := request_pkg.get_request_data('panel_rza');
l_panel constant varchar2(2000) := tpl_pkg.get_block(l_data, 'panel');
l_panels clob;
l_count integer := 0;
begin
l_panels := '
';
for c in(
select 9 as num from dual union all
select -1 as num from dual union all
select 2 as num from dual union all
select 4 as num from dual union all
select 19 as num from dual union all
select 23 as num from dual union all
select 18 as num from dual union all
select 22 as num from dual union all
select 8 as num from dual union all
select -3 as num from dual union all
select 20 as num from dual union all
select -2 as num from dual union all
select 24 as num from dual
) loop
dbms_lob.append(l_panels, replace(l_panel, '{num}', c.num));
select count(*)
into l_count
from dual
where exists(
select *
from v_scheme_element_panel
where upper(fk_table_name) = upper('panel_rza_' || c.num)
and upper(type) = 'BLINKER'
and upper(value) = 'ON'
);
if(l_count = 1) then
tpl_pkg.set_block(l_panels, 'active', tpl_pkg.get_block(l_panel, 'active'));
tpl_pkg.clear_block(l_panels, 'inactive');
else
select count(*)
into l_count
from dual
where exists(
select *
from v_scheme_element_panel
where upper(fk_table_name) = upper('panel_rza_' || c.num)
and upper(type) = 'BLINKER'
and upper(value) = 'CLOSED'
);
if(l_count = 1) then
tpl_pkg.set_block(l_panels, 'inactive', tpl_pkg.get_block(l_panel, 'inactive'));
tpl_pkg.clear_block(l_panels, 'active');
else
tpl_pkg.clear_block(l_panels, 'active');
tpl_pkg.clear_block(l_panels, 'inactive');
end if;
end if;
end loop;
:result := '<dialog id="dialog_panel_rza"><title>Выбор Панелей РЗА</title><text><![CDATA[';
dbms_lob.append(:result, l_data);
tpl_pkg.set_block(:result, 'panel', l_panels);
dbms_lob.append(:result, ']]></text></dialog>');
end;
REQUEST_CODE:
<table>
<!-- BEGIN panel -->
<tr>
<td>
Панель управления РЗА № {num}
</td>
<td>
<td align="right">
<!-- BEGIN active --><img height="24" src="./images/panel/panel_rza_alarm.png"><!-- END active -->
<!-- BEGIN inactive --><img height="24" src="./images/panel/panel_rza_inactive.png"><!-- END inactive -->
</td>
</tr>
<!-- END panel -->
</table>
TPL_PKG:
function get_block(
p_text clob,
p_block_name varchar2
) return clob
is
l_block_text clob;
begin
l_block_text := regexp_substr(p_text, '<!-- BEGIN '||p_block_name||' -->.*<!-- END '||p_block_name||' -->',1,1,'inm');
l_block_text := replace(l_block_text, '<!-- BEGIN '||p_block_name||' -->');
l_block_text := replace(l_block_text, '<!-- END '||p_block_name||' -->');
return l_block_text;
end;
Thanks
You should use to_char when you have varying datatypes.
select to_char(1) from dual
union all
select 'abc' from dual
If you wish to mix strings and numbers you have to explicitly convert the numbers into strings, i.e.:
select to_char(9) as num from dual union all
select to_char(-1) as num from dual union all
select to_char(2) as num from dual union all
select 'some_text' as num from dual union all

Oracle sql terminator screening (+strange behavior)

I have a query, say this one
SELECT to_char(regexp_substr(q'{select * from dual minus select * from dual; select * from dual minus select * from dual;}'
, '[^;]+', 1, LEVEL)) FROM dual
CONNECT BY to_char(regexp_substr(q'{select * from dual minus select * from dual; select * from dual minus select * from dual;}', '[^;]+', 1, LEVEL)) IS NOT NULL;
and it works fine - splits my row
select * from dual minus select * from dual; select * from dual
minus select * from dual;
into two
select * from dual minus select * from dual
select * from dual
minus select * from dual
Everything is fine until I add some line brakes, like this
SELECT to_char(regexp_substr(q'{select * from dual minus select * from dual;
select * from dual minus select * from dual;}'
, '[^;]+', 1, LEVEL)) FROM dual
CONNECT BY to_char(regexp_substr(q'{select * from dual minus select * from dual;
select * from dual minus select * from dual;}', '[^;]+', 1, LEVEL)) IS NOT NULL;
and here it turns to hell: sql treats ; inside a string like an actual end of the query, ORA-01756 and stuff...
And everything is fine again if I add a random symbol after the ;, this way
SELECT to_char(regexp_substr(q'{select * from dual minus select * from dual;%
select * from dual minus select * from dual;}'
, '[^;]+', 1, LEVEL)) FROM dual
CONNECT BY to_char(regexp_substr(q'{select * from dual minus select * from dual;%
select * from dual minus select * from dual;}', '[^;]+', 1, LEVEL)) IS NOT NULL;
Please explain this behavior and suggest a workaround.
UPD: tried this in different IDE (SQL developer instead of PL/SQL developer). No errors. Maybe it's all about encoding...
UPD2: SQLPlus works the same way PL/SQL developer does in this case. SQL developer seems to be a bit 'smarter'. Still, no idea why.
Try:
SELECT to_char(regexp_substr(q'{select * from dual minus select * from dual;
select * from dual minus select * from dual;}'
, '[^;[:cntrl:]]+', 1, LEVEL)) FROM dual
CONNECT BY to_char(regexp_substr(q'{select * from dual minus select * from dual;
select * from dual minus select * from dual;}', '[^;[:cntrl:]]+', 1, LEVEL)) IS NOT NULL;
Output:
select * from dual minus select * from dual
select * from dual minus select * from dual
The reason is the regexp_substr looks for the next pattern you specify, which in your case was originally [^;]+ and this pattern would find the ; and the next char would be the linefeed. The simple solution if you wanted to break up the lines like this is to also exclude control chars in the regex search via [:cntrl:]
I created the open source project plsql_lexer to solve these kinds of problems.
Splitting can get tricky for complex SQL statements. And after the statements are split you will probably want to know what to do with them, and how to report on them. The procedures STATEMENT_CLASSIFIER.CLASSIFY and STATEMENT_FEEDBACK.GET_FEEDBACK_MESSAGE can help with that task.
Sample code
Here are some samples, starting with your example and adding a few other cases. Each sample splits the string into two statements.
declare
procedure print_split_strings(p_statements nclob) is
v_split_statements nclob_table;
begin
v_split_statements := statement_splitter.split(p_statements);
for i in 1 .. v_split_statements.count loop
dbms_output.put_line('Statement '||i||': '||v_split_statements(i));
end loop;
end;
begin
--This is a simple case.
print_split_strings('select * from dual minus select * from dual; select * from dual minus select * from dual;');
--Ignore semicolons in comments.
print_split_strings('select * from dual a;/* a comment ; */ select * from dual b;');
--Ignore semicolons in strings.
print_split_strings(q'{select '''' || q'!'!' from dual a;select * from dual b;}');
--Ignore semicolons in matching BEGIN/ENDs in PLSQL_DECLARATIONS:
print_split_strings('with function f return number is begin return 1; end; function g return number is begin return 2; end; select f from dual;select 1 from dual;');
end;
/
Statement 1: select * from dual minus select * from dual;
Statement 2: select * from dual minus select * from dual;
Statement 1: select * from dual a;
Statement 2: /* a comment ; */ select * from dual b;
Statement 1: select '''' || q'!'!' from dual a;
Statement 2: select * from dual b;
Statement 1: with function f return number is begin return 1; end; function g return number is begin return 2; end; select f from dual;
Statement 2: select 1 from dual;