How do I enter the data in this table in the insert? - sql

I am new in pl / sql , I want to enter this data in the insert someone help me please?
I do not know how to enter this data in the insert without making a join
I can not find the way to enter the data in the insert
these SELECT PORCENTAJE
FROM RANGO_SUBIDA_COMISION;
VARIABLE B_ANIO NUMBER;
EXECUTE :B_ANIO := 042018;
DECLARE
V_EMPLEADO_ID EMPLEADOS.EMPLEADO_ID%TYPE;
V_NOMBRE EMPLEADOS.NOMBRE%TYPE;
V_APELLIDO EMPLEADOS.APELLIDO%TYPE;
V_VALOR_COMISION COMISIONES.VALOR_COMISION%TYPE;
V_SUELDO EMPLEADOS.SUELDO%TYPE;
BEGIN
FOR R IN
(
SELECT DISTINCT E.EMPLEADO_ID , E.NOMBRE , E.APELLIDO , C.VALOR_COMISION , E.SUELDO
FROM EMPLEADOS E JOIN COMISIONES C
ON (C.EMPLEADO_ID = E.EMPLEADO_ID)
)
LOOP
V_EMPLEADO_ID := R.EMPLEADO_ID;
V_NOMBRE := R.NOMBRE;
V_APELLIDO := R.APELLIDO;
V_VALOR_COMISION := R.VALOR_COMISION;
V_SUELDO := R.SUELDO;
INSERT INTO INFORME_SUBIDA_COMISION
VALUES ( :B_ANIO ,V_EMPLEADO_ID , V_NOMBRE , V_APELLIDO , V_VALOR_COMISION , V_SUELDO );
END LOOP;
END;

I'm not quite sure what your question is. But I don't understand why you are using a cursor for this. Why not just execute a query like this?
INSERT INTO INFORME_SUBIDA_COMISION (ANIO, EMPLEADO_ID, NOMBRE, APELLIDO, VALOR_COMISION, SUELDO)
SELECT DISTINCT :B_ANIO, E.EMPLEADO_ID, E.NOMBRE, E.APELLIDO,
C.VALOR_COMISION, E.SUELDO
FROM EMPLEADOS E JOIN COMISIONES C
ON C.EMPLEADO_ID = E.EMPLEADO_ID;
Note: I'm guessing what the column names are in INFORME_SUBIDA_COMISION, but you should explicitly list them.

you can use this insert in Bulk Mode if you have huge data to insert
SET SERVEROUTPUT ON
/*use this script to insert data in bulk mode.*/
DECLARE
TYPE array IS
TABLE OF informe_subida_comision%rowtype;
v_data array;
dml_errors EXCEPTION;
PRAGMA exception_init ( dml_errors,-24381 );
CURSOR l_cur IS
SELECT DISTINCT
e.empleado_id,
e.nombre,
e.apellido,
c.valor_comision,
e.sueldo
FROM
empleados e
JOIN comisiones c ON (
c.empleado_id = e.empleado_id
);
v_error_count NUMBER;
v_err VARCHAR2(500);
v_err_indx NUMBER;
BEGIN
OPEN l_cur;
LOOP
BEGIN
FETCH l_cur BULK COLLECT INTO v_data LIMIT 1000;
FORALL i IN 1..v_data.count SAVE EXCEPTIONS
--insert data into the table
INSERT INTO informe_subida_comision VALUES v_data ( i );
-- log any dml errors
EXCEPTION
WHEN dml_errors THEN
v_error_count := SQL%bulk_exceptions.count;
FOR i IN 1..v_error_count LOOP
v_err_indx := SQL%bulk_exceptions(i).error_index;
v_err := sqlerrm(-SQL%bulk_exceptions(i).error_code);
dbms_output.put_line(v_data(v_err_indx).empleado_id
|| ''
|| v_err);
END LOOP;
END;
COMMIT;
EXIT WHEN l_cur%notfound;
END LOOP;
CLOSE l_cur;
END;

Related

Dynamic sql with for loop PL/SQL

The following query needs to convert to dynamic SQL without hard code cursor SQL,
using l_query, I do not know the l_query it will come as a parameter.
Inside the loop, I need to execute another insert query ( l_insert_query) that also comes as a parameter.
Your counsel would be much appreciated
DECLARE
CURSOR cust
IS
SELECT *
FROM customer
WHERE id < 500;
BEGIN
l_query := 'SELECT * FROM customer WHERE id < 5';
l_insert_query :=
'insert into data ( name, mobile) values ( cust.name,cust.mobile)';
FOR r_cust IN cust
LOOP
EXECUTE IMMEDIATE l_insert_query;
END LOOP;
END;
You could do this with a dynamic PL/SQL block:
declare
l_query varchar2(100) := 'SELECT * FROM customer WHERE id < 5';
l_insert varchar2(100) := 'insert into data ( name, mobile) values ( cust.name,cust.mobile)';
l_plsql varchar2(4000);
begin
l_plsql := '
begin
for cust in (' || l_query || ') loop
' || l_insert || ';
end loop;
end;
';
dbms_output.put_line(l_plsql);
execute immediate l_plsql;
end;
/
The l_plsql statement ends up as a generated PL/SQL block using the cursor query and insert statement:
begin
for cust in (SELECT * FROM customer WHERE id < 5) loop
insert into data ( name, mobile) values ( cust.name,cust.mobile);
end loop;
end;
db<>fiddle
But that you can do this doesn't mean you should. This is vulnerable to SQL injection, and doesn't seem like a very safe, sensible or efficient way to handle data manipulation in your system.

character string buffer too small ORA-06502

I am having a problem while concatenating the varchar2 datatype in a cursor loop.
Procedure is iterating in a loop to build the in clause for insert and delete operations in batch.The process will run in batch for every 1000 account numbers.
For small amount of records it works but when it tries to concatenate large amount of records(36451477 in temp table) in a loop it throws.
java.sql.SQLException: ORA-06502: PL/SQL: numeric or value error:
character string buffer too small ORA-06512: at
"QA01BT.LOAD_ITEM_DATA_TO_CONSOLIDATE", line 23 ORA-06512: at line 1
i have put a max limit of search id to 32767 but still it does not work.
is there any other way to achieve this?
create or replace PROCEDURE LOAD_ITEM_DATA_TO_CONSOLIDATE(updatecount OUT NUMBER
)
IS
cnt NUMBER := 0;
c_limit CONSTANT PLS_INTEGER DEFAULT 1000;
search_id varchar2(32727);
TYPE account_array
IS TABLE OF VARCHAR2(255) INDEX BY BINARY_INTEGER;
l_data ACCOUNT_ARRAY;
CURSOR account_cursor IS
SELECT DISTINCT account_no AS account_num
FROM item_temp;
BEGIN
OPEN account_cursor;
LOOP
FETCH account_cursor bulk collect INTO l_data limit c_limit;
search_id := '''';
FOR i IN 1 .. l_data.count LOOP
IF( i != 1 ) THEN
search_id := search_id
|| ','
|| ''''
|| l_data(i)
|| '''';
ELSE
search_id := search_id
|| l_data(i)
|| '''';
END IF;
END LOOP;
BEGIN
SAVEPOINT move_data_to_temp_table;
EXECUTE IMMEDIATE 'delete from item where ACCOUNT_NO IN('||search_id||')';
EXECUTE IMMEDIATE 'insert into item(ID,ACCOUNT_NO,ITEM_ID,ITEM_VALUE) select HIBERNATE_SEQUENCE.nextval,temp.ACCOUNT_NO,temp.ITEM_ID,temp.ITEM_VALUE from item_TEMP temp where ACCOUNT_NO IN('||search_id||')';
cnt := cnt + SQL%rowcount;
COMMIT;
EXCEPTION WHEN OTHERS THEN ROLLBACK to move_data_to_temp_table;
END;
EXIT WHEN account_cursor%NOTFOUND;
END LOOP;
updatecount := cnt;
CLOSE account_cursor;
END LOAD_ITEM_DATA_TO_CONSOLIDATE;
This seems somewhat over-engineered. Why not just this?
create or replace PROCEDURE LOAD_ITEM_DATA_TO_CONSOLIDATE
(updatecount OUT NUMBER)
IS
BEGIN
delete from item
where ACCOUNT_NO IN ( SELECT account_no
FROM item_temp);
insert into item(ID,ACCOUNT_NO,ITEM_ID,ITEM_VALUE)
select HIBERNATE_SEQUENCE.nextval, temp.ACCOUNT_NO, temp.ITEM_ID, temp.ITEM_VALUE
from item_TEMP temp ;
updatecount := SQL%rowcount;
END LOAD_ITEM_DATA_TO_CONSOLIDATE;
If you do decide you need to do this in batches and are worried about that string getting too long or having too many elements in the list (max is 1000), you should try putting your values into an array and then using IN against the array, via a table function or a direct reference to the table.
Extra bonus: no need for dynamic SQL!
Something like this:
CREATE OR REPLACE TYPE strings_t IS TABLE OF VARCHAR2 (255)
/
CREATE OR REPLACE PROCEDURE load_item_data_to_consolidate (
updatecount OUT NUMBER)
IS
cnt NUMBER := 0;
c_limit CONSTANT PLS_INTEGER DEFAULT 1000;
l_data strings_t;
CURSOR account_cursor
IS
SELECT DISTINCT account_no AS account_num FROM item_temp;
BEGIN
OPEN account_cursor;
LOOP
FETCH account_cursor BULK COLLECT INTO l_data LIMIT c_limit;
BEGIN
SAVEPOINT move_data_to_temp_table;
DELETE FROM item
WHERE account_no IN (SELECT COLUMN_VALUE FROM TABLE (l_data));
INSERT INTO item (id,
account_no,
item_id,
item_value)
SELECT hibernate_sequence.NEXTVAL,
temp.account_no,
temp.item_id,
temp.item_value
FROM item_temp temp
WHERE account_no IN (SELECT COLUMN_VALUE FROM TABLE (l_data));
cnt := cnt + SQL%ROWCOUNT;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
ROLLBACK TO move_data_to_temp_table;
END;
EXIT WHEN account_cursor%NOTFOUND;
END LOOP;
END;

Fetching cursor data into array in PL/SQL

I have a problem at one exercise: I have a table with an ussualy column, and another column which is another table, like this:
CREATE OR REPLACE TYPE list_firstnames AS TABLE OF VARCHAR2(10);
then I create the following table:
CREATE TABLE persons (last_name VARCHAR2(10), first_name list_firstnames)
NESTED TABLE first_name STORE AS lista;
I insert:
INSERT INTO persons VALUES('Stewart', list_firstnames('John', 'Jack'));
INSERT INTO persons VALUES('Bauer', list_firstnames('Helen', 'Audrey'));
INSERT INTO persons VALUES('Obrian', list_firstnames('Mike', 'Logan'));
I want to make a cursor to take all last and first names from persons, and then I want to put all of them in an array. After this, I want to count the first names which contains the 'n' letter.
First of all, I want to know how I can put all the information from the cursor in an array. I try this:
DECLARE
CURSOR firstnames_students IS
select last_name,COLUMN_VALUE as "FIRSTNAME" from persons p, TABLE(p.last_name) p2;
v_lastname VARCHAR(50);
v_firstname VARCHAR(50);
v_I NUMBER := 1;
v_count NUMBER := 0;
v_contor INTEGER := 0;
TYPE MyTab IS TABLE OF persons%ROWTYPE INDEX BY VARCHAR2(20);
std MyTab;
BEGIN
OPEN firstnames_students;
LOOP
FETCH firstnames_students INTO v_lastname, v_firstname;
EXIT WHEN firstnames_students%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_lastname || ' ' || v_firstname);
END LOOP;
--select * INTO std FROM firstnames_students;
CLOSE firstnames_students;
END;
SET SERVEROUTPUT ON;
DECLARE
CURSOR students IS
SELECT * FROM persons;
v_row PERSONS%ROWTYPE;
v_names SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST();
v_count INT := 0;
BEGIN
OPEN students;
LOOP
FETCH students INTO v_row;
EXIT WHEN students%NOTFOUND;
v_names.EXTEND;
v_names(v_names.COUNT) := v_row.last_name;
FOR i IN 1 .. v_row.first_name.COUNT LOOP
v_names.EXTEND;
v_names(v_names.COUNT) := v_row.first_name(i);
END LOOP;
END LOOP;
CLOSE students;
FOR i IN 1 .. v_names.COUNT LOOP
IF INSTR( v_names(i), 'n' ) > 0 THEN
v_count := v_count + 1;
DBMS_OUTPUT.PUT_LINE( v_names(i) );
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE( v_count );
END;
Output:
John
Helen
Obrian
Logan
4

Any alternatives to using cursor in SQL procedure in Oracle 10g?

I give the SQL few inputs and I need to get all the ID's and their count that doesn't satisfy the required criteria.
I would like to know if there are there any alternatives to using cursor.
DECLARE
v_count INTEGER;
v_output VARCHAR2 (1000);
pc table1%ROWTYPE;
unmarked_ids EXCEPTION;
dynamic_sql VARCHAR (5000);
cur SYS_REFCURSOR;
id pp.id%TYPE;
pos INTEGER;
BEGIN
v_count := 0;
SELECT *
INTO pc
FROM table1
WHERE id = '&ID';
DBMS_OUTPUT.ENABLE;
dynamic_sql :=
'SELECT ID from pp
WHERE ( TO_CHAR(cdate, ''yyyy/mm/dd'') =
TO_CHAR (:a, ''yyyy/mm/dd''))
AND aid IN (SELECT aid FROM ppd WHERE TO_CHAR(cdate, ''yyyy/mm/dd'') =
TO_CHAR (:b, ''yyyy/mm/dd'')
AND cid = :c )
AND cid <> :d';
OPEN cur FOR dynamic_sql USING pc.cdate, pc.cdate, pc.id, pc.id;
LOOP
FETCH cur INTO id;
EXIT WHEN cur%NOTFOUND;
v_count := v_count + 1;
DBMS_OUTPUT.PUT_LINE (' Id:' || id);
END LOOP;
CLOSE cur;
IF (v_count > 0)
THEN
DBMS_OUTPUT.PUT_LINE ( 'Count: ' || v_count || ' SQL: ' || dynamic_sql);
RAISE unmarked_ids;
END IF;
DBMS_OUTPUT.PUT_LINE('SQL ended successfully');
EXCEPTION
WHEN unmarked_ids
THEN
DBMS_OUTPUT.put_line (
'Found ID's that not marked with the current id.');
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (
'No data found in table1 with the current id ' || '&ID');
END;
There are bind variables in the query. One of them is date, there are three more.
The count and ID's are required to be shown which will later be reported.
You could store the rowid in a temporary table along with an index value (0...n) and then use a while loop to go through the index values and join to the real table using the rowid.

Getting an error in sql, when executing code below.How to declare a table type in plsql. Am a beginner . Please suggest

create or replace procedure BAS_NUM_UPD is
cursor cur is
select distinct o.oi_b,mpr.pa_ke_i,ltrim(substr(convert_171_to_711(cp.p_t_num),1,7),'0') bs_nbr
from t_obj o, mat_pa_rel mp, cor_pa cp
where o.ob_t = 'something'
and o.oi_b = mp.oi_b
and mp.pa_ke_i = cp.pa_ke_i;
l_ba_num_at_i number(10) := get_attribute_id('Ba timber');
flag1 VARCHAR2(10);
type t1 is table of varchar2(10);
par_k t1;
BEGIN
for x in cur loop
BEGIN
select pa_ke_i into par_k from mat_pa_rel where oi_b=x.oi_b ;
if par_k.count=null then
insert into cs_val (oi_b, at_i, value, flag, ) values (x.oi_b, l_ba_num_at_i, null, 1);
end if;
select flag into flag1 from cs_val where at_i = l_ba_num_at_i and oi_b = x.oi_b
and value = x.bs_nbr;
EXCEPTION
when NO_DATA_FOUND THEN
insert into cs_val (oi_b, at_i, value, flag, )
values (x.oi_b, l_ba_num_at_i, x.bs_nbr, 1);
flag1 :='Nothing';
when OTHERS
then
raise_application_error(-20011,'Unknown Exception in PROCEDURE');
END;
end loop;
end BAS_NUM_UPD;
error:
PLS-00642: local collection types not allowed in SQL statements
You should get it running if you do a bulk collect
select pa_ke_i bulk collect into par_k from mat_pa_rel where oi_b=x.oi_b ;
Then I think the if is not right. I think you need to do
if par_k.count = 0 then
But to be honest you might just make a count
select count(*) into l_cnt from mat_pa_rel where oi_b=x.oi_b;
If l_cnt = 0 then ...
Of course l_cnt has to be defined.
You should create type t1 in the schema and not in the pl/sql block.