HANA SQL function to split a comma delimited string into substrings - sql

I have the following HANA Procedure:
CREATE PROCEDURE SP_LIT()
AS
BEGIN
DECLARE count INT;
DECLARE pos INT;
DECLARE value NVARCHAR(100);
value := 'R,A';
IF LENGTH(:value) > 0 THEN
value := :value + ',';
pos := LOCATE(:value,',',1);
END IF;
WHILE :pos > 0 DO
BEGIN
INSERT INTO [O/P table] VALUES (LEFT(:value,:pos-1));
value := RIGHT(:value, LENGTH (:value)-:pos);
pos := LOCATE(:value,',',1);
END;
END WHILE;
END;
Everything seems fine but on execution the following error is thrown:
Error: invalid number exception: invalid number: not a valid number string 'R,A'
Any idea where am I going wrong?

I found the solution.
The '+' sign in concatenation should be replaced by '||' pipe operator.

Related

PLS-00382: expression is of wrong type, can't show DBMS_OUTPUT.PUT_LINE

Encountered this problem several times, that SQL Developer can't show DBMS_OUTPUT.PUT_LINE despite already turning serveroutput on and Dbms Output turned on from View toolbar
set serveroutput on;
accept p_angka prompt 'Input Number : ';
declare
a integer;
b integer :=&p_angka;
begin
dbms_output.put_line('---ODD NUMBER---');
for a in 1..b loop
if (a mod 2) then
dbms_output.put_line(a);
end if;
end loop;
end;
Console succesfully asking for input but can't show the desired output anywhere with
ORA-06550: line 8, column 12:
PLS-00382: expression is of wrong type
ORA-06550: line 8, column 9: error
I think there are several mistakes in your code which is mentioned inline in the following code:
set serveroutput on;
-- accept p_angka prompt 'Input Number : '; -- not needed
declare
--a integer; -- not needed
b integer := &p_angka;
begin
dbms_output.put_line('---ODD NUMBER---');
for a in 1..b loop
if (mod(a,2) = 0) then -- mod function should be used like this
dbms_output.put_line(a);
end if;
end loop;
end;
/
DB<>Fiddle with constant value for b.

Handle a very large string in pl/sql script

I am trying to run below code which reads the index definition for table A so that it can be created again after I delete/create that in this script. This script runs fine when the returned value(ddl) is small but in other environments where the value is large with 140K characters in one row this script fails with below mentioned error. Please note that I cannot use spool in this case due to some restrictions. Could someone help on how to resolve this issue or suggest some another approach?
Thanks in advance.
"An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2)."
SET SERVEROUTPUT ON;
DECLARE
my_cursor SYS_REFCURSOR;
TYPE clob_array IS VARRAY(15) OF CLOB;
index_array clob_array := clob_array();
v_clob CLOB;
--index_array SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST();
BEGIN
OPEN my_cursor FOR 'select replace(dbms_metadata.get_ddl (''INDEX'', index_name), ''"C",'', '''')
from user_indexes
where table_name = ''A''';
LOOP FETCH my_cursor INTO v_clob;
EXIT WHEN my_cursor%NOTFOUND;
index_array.extend;
index_array(index_array.count) := v_clob;
dbms_output.put_line(index_array(index_array.count));
END LOOP;
CLOSE my_cursor;
END;
/
I simulated this issue you are getting this error because of the dbms_output.put_line which displays the output.Try switching to UTL_FILE at the server side OR Try for any alternatives
By the way, the code can be simplified to:
declare
type clob_array is table of clob;
index_array clob_array := clob_array();
begin
for r in (
select replace(dbms_metadata.get_ddl('INDEX', index_name), '"C",') as index_ddl
from user_indexes
where table_name = 'A'
)
loop
index_array.extend;
index_array(index_array.count) := r.index_ddl;
dbms_output.put_line(substr(index_array(index_array.count), 1, 32767));
end loop;
end;
I used substr() to limit the value passed to dbms_output.put_line to its documented limit. You could probably work around it by splitting the text into smaller chunks, and maybe finding the position of the last blank space before position 32767 in order to avoid splitting a word.
Here's what I came up with:
declare
type clob_array is table of clob;
index_array clob_array := clob_array();
procedure put_line
( p_text clob )
is
max_len constant simple_integer := 32767;
line varchar2(max_len);
remainder clob := p_text;
begin
while dbms_lob.getlength(remainder) > max_len loop
line := dbms_lob.substr(remainder,max_len);
line := substr(line, 1, instr(line, ' ', -1));
remainder := substr(remainder, length(line) +1);
dbms_output.put_line(line);
end loop;
if length(trim(remainder)) > 0 then
dbms_output.put_line(remainder);
end if;
end put_line;
begin
for r in (
select replace(dbms_metadata.get_ddl('INDEX', index_name), '"C",') as index_ddl
from user_indexes
where table_name = 'A'
)
loop
index_array.extend;
index_array(index_array.count) := r.index_ddl;
put_line(index_array(index_array.count));
end loop;
end;

ORA-00917: Missing Comma in PLSQL

I have written a PL SQL script to add values stored in an array into a temp table. I have used Execute immediate to execute the insert query inside a loop.
I have checked the number of single quotes and the number of commas and they are closed. Still, I'm getting the error code
ORA-00917: missing comma.
declare
type post_CODS IS VARRAY(34) OF VARCHAR2(20);
type locality_ID IS VARRAY(34) OF NUMBER(9);
pc post_CODS;
Y varchar2(1);
lid locality_ID;
total integer;
begin
Y := 'Y';
lid := locality_ID(2380,3785,8710,17895,20345,24630,26814,28525,29130,31025,31265,32445,36940,40590,54290,83775,83780,83785,83790,83795,88483,93480,94560,96670,1000524,1000628,1000738,1000857,1000988,1001103,1001466,1001575,1001707,1001744);
pc := post_CODS(2822,2739,2822,2372,2817,4314,4300,4726,4300,4884,4314,4314,4300,5719,3026,4314,4314,4314,4314,4314,873,2582,2817,4314,5723,5440,2083,2575,873,2372,5440,5440,5715,5440);
total := lid.count;
FOR i in 1 .. total LOOP
execute immediate 'insert into tmp_ref_lc_pc_cods values('||lid(i)||','||pc(i)||','||Y||',89987,'||sysdate||')';
END LOOP;
END;
This is the error I am getting
Error report:
ORA-00917: missing comma
ORA-06512: at line 14
00917. 00000 - "missing comma"
I'm working on an oracle machine.
Wrap your insert statement in q'[]' and try
execute immediate q'[insert into tmp_ref_lc_pc_cods values('||lid(i)||','||pc(i)||','||Y||',89987,'||sysdate||')]';
Update
It is recommended to use bind variable. You can try the below. It is working for me and inserting the data.
declare
type post_CODS IS VARRAY(34) OF NUMBER(20);
type locality_ID IS VARRAY(34) OF NUMBER(9);
pc post_CODS;
Y varchar2(1);
lid locality_ID;
total integer;
begin
Y := 'Y';
lid := locality_ID(2380,3785,8710,17895,20345,24630,26814,28525,29130,31025,31265,32445,36940,40590,54290,83775,83780,83785,83790,83795,88483,93480,94560,96670,1000524,1000628,1000738,1000857,1000988,1001103,1001466,1001575,1001707,1001744);
pc := post_CODS(2822,2739,2822,2372,2817,4314,4300,4726,4300,4884,4314,4314,4300,5719,3026,4314,4314,4314,4314,4314,873,2582,2817,4314,5723,5440,2083,2575,873,2372,5440,5440,5715,5440);
total := lid.count;
FOR i in 1 .. total LOOP
execute immediate q'[insert into tmp_ref_lc_pc_cods values(:var1,:var2,'Y',89987,sysdate)]' using lid(i),pc(i);
END LOOP;
END;
A good trick when trying to execute immediate is making sure that the statements created are formatted correctly, printing the code you've written reveals that the Y is not inside of apostrophes
insert into tmp_ref_lc_pc_cods values(2380,2822,Y,89987,23-APR-19)
So when dynamically creating code make sure that all strings created have the right amount of apostrophes.
dbms_output.put_line('insert into tmp_ref_lc_pc_cods values('||lid(i)||','||pc(i)||','''||Y||''',89987,'||sysdate||')');

PLS-00103: Encountered the symbol "&" when expecting one of the following

PLS-00103: Encountered the symbol "&" when expecting one of the following...
code:
Declare
num number;
Begin
num := &num;
if num > 0 then
dbms_output.put_line(‘Hello’);
end if;
end;
/
I'm not sure why I'm getting this message when I'm not seeing anything wrong.
Oracle Live SQL is a tool for trying out SQL and PL/SQL but it doesn't support substitution variable syntax (&var.).
Instead, you can create tables, populate them with data, then run SQL or PL/SQL using them, e.g.:
create table inputs (num number);
insert into inputs values (10);
Declare
num number;
Begin
select num into num from inputs;
if num > 0 then
dbms_output.put_line('Hello');
end if;
end;
/
(p.s. I had to fix the quotes around 'Hello' for this to work)
Oracle live does not support & for get value.
Instead you can initialize the Variable
Declare
num number := 10;
Begin
if num > 0 then
dbms_output.put_line(‘Hello’);
end if;
end;
/

Dynamic update query with parameters in SAP HANA procedures

I have a SAP HANA procedures to update a table. I'm trying to create a dynamic sql query, this is my example:
declare _field varchar(100) := 'NAME';
declare _name varchar(100) := 'david';
declare _id integer := 1;
DECLARE SQL_STR VARCHAR(3000);
SQL_STR := 'UPDATE "_SYS_BIC"."TEST_TABLE" SET "'||_field||'" = '||_name||' WHERE "ID" = '||:_id;
EXECUTE IMMEDIATE (:SQL_STR);
But in the console I have this error:
Service exception: [260] invalid column name
How can I fix it?
I found the correct syntax to fix it
declare _id integer := 1;
declare _name varchar(100) := 'david';
declare _field varchar(100) := 'NAME';
DECLARE SQL_STR VARCHAR(3000);
SQL_STR := 'UPDATE "_SYS_BIC"."TEST_TABLE" SET "'||_field||'" = '''||_name||''' WHERE "ID" = '||_id;
EXECUTE IMMEDIATE (:SQL_STR);
If I have to set a column or table name the right syntax is
"'||_field||'"
To set a string value the syntax is '''||_name||''' the first two apostrophes are used for the escape so we can say to the query that the value is a string, the last one apostrophe is used to concatenate the value to the rest of the query string. The three apostrophes must be written without spaces among them.