how to insert the value into a table type through a select statement in oracle? - oracle11g

I am a beginner in Oracle. I created the table type as like as follows:
TYPE metertable IS TABLE OF pseb.metermaster.meterid%type;
I dnt know how to insert the value into that table type. I need to store the whole resultset of the following query into the table type.
select distinct(meterid)
from pseb.consumerfeedermetermapper
where feederid in (select distinct (fm.FeederID)
from pseb.feedermaster fm,pseb.consumerfeedermetermapper cfm
where fm.substationid=v_v_type
and cfm.feederid=fm.feederid
and cfm.FeederID>0)
and meterid >0
order by meterid;
Help me to do that.

Use BULK COLLECT to select the data into a variable of that type:
declare
mt metertable;
begin
select distinct(meterid)
bulk collect into mt
from pseb.consumerfeedermetermapper
where feederid in (select distinct (fm.FeederID)
from pseb.feedermaster fm,pseb.consumerfeedermetermapper cfm
where fm.substationid=v_v_type
and cfm.feederid=fm.feederid
and cfm.FeederID>0)
and meterid >0
order by meterid;
-- Now use mt...
end;

I had the same issue, and this code help me :
SET SERVEROUTPUT ON
DECLARE
TYPE t_bulk_collect_test_tab IS TABLE OF bulk_collect_test%ROWTYPE;
l_tab t_bulk_collect_test_tab;
l_cursor SYS_REFCURSOR;
BEGIN
-- Way 1
OPEN l_cursor FOR 'SELECT * FROM bulk_collect_test';
FETCH l_cursor
BULK COLLECT INTO l_tab;
CLOSE l_cursor;
DBMS_OUTPUT.put_line('Dynamic FETCH : ' || l_tab.count);
-- Way 2
EXECUTE IMMEDIATE 'SELECT * FROM bulk_collect_test' BULK COLLECT INTO l_tab;
DBMS_OUTPUT.put_line('Dynamic EXECUTE: ' || l_tab.count);
END;
/
http://www.dba-oracle.com/plsql/t_plsql_dynamic.htm

declare
type tab_type is table of consumerfeedermetermapper%rowtype;
tab_t tab_type;
begin
select distinct(meterid) bulk collect into tab_t
from pseb.consumerfeedermetermapper
where feederid in (select distinct (fm.FeederID)
from pseb.feedermaster fm,pseb.consumerfeedermetermapper cfm
where fm.substationid=v_v_type
and cfm.feederid=fm.feederid
and cfm.FeederID>0)
and meterid >0
order by meterid;
end;
You can use the above code

Related

Does Oracle support non-scalar cursor parameter?

This is a question about Oracle PL/SQL.
I have a procedure in which the exact WHERE clause is not known until the run time:
DECLARE
CURSOR my_cursor is
SELECT ...
FROM ...
WHERE terms in (
(SELECT future_term2 FROM term_table), -- whether this element should be included is conditional
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
);
BEGIN
(the processing)
END;
/
What the (SELECT ... FROM term_table) query returns is a 4-character string.
For a solution to this, I am thinking of using a parameterized cursor:
DECLARE
target_terms SOME_DATATYPE;
CURSOR my_cursor (pi_terms IN SOME_DATATYPE) IS
SELECT ...
FROM ...
WHERE terms in my_cursor.pi_terms;
BEGIN
target_terms := CASE term_digit
WHEN '2' THEN (
(SELECT future_term2 FROM term_table),
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
) ELSE (
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
)
END;
FOR my_record IN my_cursor (target_terms) LOOP
(the processing)
END LOOP;
END;
/
The problem is what the datatype for SOME_DATATYPE should be is not known to me, nor is it known whether Oracle supports such a cursor parameter at all. If supported, is the way shown above to fabricate the value for target_terms correct? If not, how?
Hope someone who know can advise. And thanks a lot for the help.
You can certainly pass a parameter to a cursor, just like you can to a function - but only IN parameters. However, PL/SQL is a strongly typed language, so the datatype must be specified at the time of compilation.
It looks to me like what you will need to do is construct the query dynamically and then use
OPEN cursor FOR l_query;
where l_query is the constructed string. This should give you a feel for what you can do:
CREATE OR REPLACE PACKAGE return_id_sal
AUTHID DEFINER
IS
TYPE employee_rt IS RECORD
(
employee_id employees.employee_id%TYPE,
salary employees.salary%TYPE
);
FUNCTION allrows_by (append_to_from_in IN VARCHAR2 DEFAULT NULL)
RETURN SYS_REFCURSOR;
END return_id_sal;
/
CREATE OR REPLACE PACKAGE BODY return_id_sal
IS
FUNCTION allrows_by (append_to_from_in IN VARCHAR2 DEFAULT NULL)
RETURN SYS_REFCURSOR
IS
l_return SYS_REFCURSOR;
BEGIN
OPEN l_return FOR
'SELECT employee_id, salary FROM employees ' || append_to_from_in;
RETURN l_return;
END allrows_by;
END return_id_sal;
/
DECLARE
l_cursor SYS_REFCURSOR;
l_row return_id_sal.employee_rt;
BEGIN
l_cursor := return_id_sal.allrows_by ('WHERE department_id = 10');
LOOP
FETCH l_cursor INTO l_row;
EXIT WHEN l_cursor%NOTFOUND;
END LOOP;
END;
/
You will need to take precautions against SQL injection with this sort of code. Certainly a user should never be able to pass SQL text directly to such a function!
You can use also some built-in VARRAY SQL types like SYS.ODCIVARCHAR2LIST or create your own :
CREATE OR REPLACE NONEDITIONABLE TYPE VARCHARLIST
AS VARRAY(32767) OF VARCHAR2(4000);
Then you can use it with SELECT COLUMN_VALUE FROM TABLE(COLLECTION) statement in your cursor:
DECLARE
l_terms SYS.ODCIVARCHAR2LIS; --or VARCHARLIST
CURSOR my_cursor (p_terms IN SYS.ODCIVARCHAR2LIS) IS
SELECT your_column
FROM your_table
WHERE terms in (select COLUMN_VALUE from table (p_terms));
BEGIN
select term
bulk collect into l_terms
from (
select 'term1' term from dual
union all
select 'term2' term from dual
);
FOR my_record IN my_cursor (l_terms) LOOP
--process data from your cursor...
END LOOP;
END;

Not able to use dynamic SQL in bulk collect and forall

Hi friends am writing a stored procedure that selects and inserts data from one table to another table in the same database but different users, to speed up the insert am trying to use bulk collect and forall but the problem is am using dynamic SQL in the procedure that picks table name, it's corresponding primary key name and the date validation columns from another status table
For eg: consider the following query
Select empid from emp_tab where trunc(insert_time)=trunc(sysdate)
Here the PRIMARY KEY - empid, TABLENAME- emp_tab, date validation column - insert_time will be dynamically picked by the procedure during run time of the procedure from another status table but am not able incorporate the bulk collect and forall into dynamic SQL for bulk collect am getting
inconsistent data type
error and forall am getting
virtual column
error
Does bulk and forall supports dynamic sql????
If not then is there any other way to speed up the insert like forall
Any suggestions are welcome
Thanks in advance
Yes, they do. Despite BULK COLLECT being a powerful tool, it can be tricky with all its limitation. Here is a example using REF CURSOR, but you can build the TYPES according to your necessity.
-- create source data
CREATE TABLE temp_table_source AS
(SELECT ROWNUM id,
dbms_random.String('U', 10) name,
Round(dbms_random.Value(1, 7000)) salary
FROM dual
CONNECT BY LEVEL <= 5000 -- number of rows for the test
);
-- create destination table (empty)
CREATE TABLE temp_table_dest AS
SELECT * FROM temp_table_source WHERE 1 = 2;
-- Dynamic bulk anonymous block
DECLARE
v_stmt VARCHAR2(100);
v_insert VARCHAR2(100);
TYPE rec_source IS RECORD ( -- a type to represent your data
id temp_table_source.id%TYPE,
name temp_table_source.name%TYPE,
salary temp_table_source.salary%TYPE
);
TYPE t_source IS TABLE OF rec_source;
m_source t_source;
TYPE l_cursor_type IS REF CURSOR;
l_cursor l_cursor_type;
BEGIN
v_stmt := 'SELECT * FROM temp_table_source where 1 = :x';
v_insert := 'INSERT INTO temp_table_dest (id, name, salary) VALUES (:a, :b, :c)';
OPEN l_cursor FOR v_stmt USING 1; -- example of filtering
LOOP -- use limits to test performance, but the LOOP is optional
FETCH l_cursor BULK COLLECT INTO m_source LIMIT 1000;
--
FORALL i IN 1 .. m_source.COUNT
EXECUTE IMMEDIATE v_insert
USING m_source(i).id, m_source(i).name, m_source(i).salary;
--
COMMIT;
EXIT WHEN m_source.COUNT = 0;
END LOOP;
END;
/
-- See the result
Select count(1) from temp_table_dest;
If you need a dynamic TYPE as well, you will need to create it and drop at the end of your procedure instead of declare it in your package.

oracle plsql procedure dynamic count of the tables in cursor loop

I want to update all the tables having ABC column.Need to skip the tables which doesn't have data.I am having problem in checking the count of the table in a cursor loop.
PLSQL code
create or replace procedure testp is
CURSOR c_testp
IS
SELECT table_name,
column_name
FROM all_tab_columns
WHERE column_name IN('ABC')
ORDER BY table_name;
c int;
BEGIN
FOR table_rec IN c_testp
LOOP
BEGIN
SELECT COUNT(*)
INTO c
FROM table_rec.table_name;
IF(c>0) THEN
query := 'update '||table_rec.table_name||' set '||table_rec.column_name ||'= xyz';
EXECUTE IMMEDIATE query;
COMMIT;
END IF;
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('data not found');
WHEN OTHERS THEN
dbms_output.put_line('others');
END;
END LOOP;
END;
In your code, use this:
EXECUTE IMMEDIATE 'SELECT count(*) FROM ' || table_rec.table_name INTO c;
instead of this:
SELECT COUNT(*)
INTO c
FROM table_rec.table_name;
However, as mentioned in comments - there is actually no need to perform that condition check, as no update will be performed when table is empty.

In pl/sql how can I execute a select statement stored in CLOB type of field?

In Oracle DB, I have a large select staetment with lots of joins and cases that is stored in a CLOB field in one of my tables.
How can i execute this statement from the CLOB?
Look into the EXECUTE IMMEDIATE syntax.
Example table:
CREATE TABLE test(id number, largedata clob);
INSERT INTO test VALUES (1, 'select name from v$database');
commit;
select * from test;
DECLARE
l_sql clob;
l_result VARCHAR2(50);
BEGIN
SELECT LARGEDATA INTO l_sql FROM TEST;
EXECUTE IMMEDIATE l_sql INTO l_result;
dbms_output.put_line(l_result);
END;
/
Output is the DB name.

pl/sql displaying all columns of a table

employee table schema
employee(id, name, company, salary);
procedure created to display all the column values
create or replace procedure p1
IS
BEGIN
select * from employee;
END;
/
exe p1;
However, this does not display the data.
Your PL/SQL block is not valid, and won't even run. You need to either return the data back to the client, or if you're using SQL*Plus use dbms_output.put_line to print the query resultset.
create or replace procedure p1
IS
BEGIN
DBMS_OUTPUT.ENABLE;
FOR emp_rec in select * from employee LOOP
dbms_output.put_line('EMployee id: || emp_rec.emp_id || ' Name: ' || emp_rec ename);
END LOOP
END;
/
Change the column name suitably

Resources