how to create index by using dynamic sql? - plsql

----------- it is giving below error ,where i did mistake ---------------
declare l1 integer;
begin execute immediate q '!
begin
execute immediate ' CREATE INDEX S_ACCNT_ATT_P1 ON S_ACCNT_ATT(ROW_ID) PARALLEL 4 ';
execute immediate ' CREATE INDEX S_ACCNT_ATT_U1 ON S_ACCNT_ATT(PAR_ROW_ID, FILE_NAME, FILE_EXT, CONFLICT_ID) PARALLEL 4 ';
execute immediate '
select 1 from dual '
into :l1;
end;!' using out l1;
end;
------- error -------------------
ORA-06550: line 2, column 27:
PLS-00103: Encountered the symbol "!
begin
execute immediate " when expecting one of the following:

The issue is the incorrect q-quoting syntax. That is causing the error you're seeing.
DECLARE
BEGIN
EXECUTE IMMEDIATE q '!BEGIN NULL; END;!';
END;
/
Error report -
ORA-06550: line 3, column 23:
PLS-00103: Encountered the symbol "!BEGIN NULL; END;!" when expecting one of the following:
. ( * # % & = - + ; < / > at in is mod remainder not rem
return returning <an exponent (**)> <> or != or ~= >= <= <>
and or like like2 like4 likec between into using || multiset
bulk member submultiset
The symbol "*" was substituted for "!BEGIN NULL; END;!" to continue.
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
There should be no space between the q and the ':
DECLARE
BEGIN
EXECUTE IMMEDIATE q'!BEGIN NULL; END;!';
END;
/
PL/SQL procedure successfully completed.

How/where exactly did you run that piece of code? I tested it on TOAD and SQL*Plus in Oracle 11g.
Sample table:
SQL> CREATE TABLE s_accnt_att
2 (
3 row_id NUMBER,
4 par_row_id NUMBER,
5 file_name NUMBER,
6 file_ext NUMBER,
7 conflict_id NUMBER
8 );
Table created.
Procedure:
SQL> SET SERVEROUTPUT ON;
SQL>
SQL> DECLARE
2 l1 INTEGER;
3 BEGIN
4 EXECUTE IMMEDIATE q'[
5 begin
6 execute immediate ' CREATE INDEX S_ACCNT_ATT_P1 ON S_ACCNT_ATT ( ROW_ID ) PARALLEL 4 ';
7 execute immediate ' CREATE INDEX S_ACCNT_ATT_U1 ON S_ACCNT_ATT ( PAR_ROW_ID , FILE_NAME , FILE_EXT , CONFLICT_ID ) PARALLEL 4 ';
8 execute immediate ' select 1 from dual '
9 into :l1;
10 end;
11 ]'
12 USING OUT l1;
13
14 DBMS_OUTPUT.put_line ('L1 = ' || l1);
15 END;
16 /
L1 = 1
PL/SQL procedure successfully completed.
SQL>
Seems to be OK.
As your target database is 19c, I tried it there as well; no problem.
SQL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
SQL> DECLARE
2 l1 INTEGER;
3 BEGIN
4 EXECUTE IMMEDIATE q'[
5 begin
6 execute immediate ' CREATE INDEX S_ACCNT_ATT_P1 ON S_ACCNT_ATT ( ROW_ID ) PARALLEL 4 ';
7 execute immediate ' CREATE INDEX S_ACCNT_ATT_U1 ON S_ACCNT_ATT ( PAR_ROW_ID , FILE_NAME , FILE_EXT , CONFLICT_ID ) PARALLEL 4 ';
8 execute immediate ' select 1 from dual '
9 into :l1;
10 end;
11 ]'
12 USING OUT l1;
13
14 DBMS_OUTPUT.put_line ('L1 = ' || l1);
15 END;
16 /
L1 = 1
PL/SQL procedure successfully completed.
SQL>
Therefore, maybe it is about your migration tool (which one is it) that doesn't recognize the q-quoting mechanism. If that's so, don't use it and double single quotes instead:
SQL> DECLARE
2 l1 INTEGER;
3 BEGIN
4 EXECUTE IMMEDIATE '
5 begin
6 execute immediate '' CREATE INDEX S_ACCNT_ATT_P1 ON S_ACCNT_ATT ( ROW_ID ) PARALLEL 4 '';
7 execute immediate '' CREATE INDEX S_ACCNT_ATT_U1 ON S_ACCNT_ATT ( PAR_ROW_ID , FILE_NAME , FILE_EXT , CONFLICT_ID ) PARALLEL 4 '';
8 execute immediate '' select 1 from dual ''
9 into :l1;
10 end;
11 '
12 USING OUT l1;
13
14 DBMS_OUTPUT.put_line ('L1 = ' || l1);
15 END;
16 /
PL/SQL procedure successfully completed.
SQL>

Related

PLS-00201 Error in Pipelined Function in PL/SQL

I was trying to create a pipelined table function in PL/SQL but facing the below error. Is this an syntax error?
CREATE OR REPLACE FUNCTION FUNC_IDS(
IDS_IN IN VARCHAR2
) RETURN IDS_T
PIPELINED
IS
BEGIN
select * from dual;
return;
END func_ids;
Script Output:
Function FUNC_IDS compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
0/0 PL/SQL: Compilation unit analysis terminated
3/10 PLS-00201: identifier 'IDS_T' must be declared
Errors: check compiler log
I missed to create the row and table types before creating the func. Have created them later as below and trying to create the function that gets input as a string of IDs and pipe out the individual IDs to another function.
CREATE TYPE TF_ROW AS OBJECT (ID NUMBER);
CREATE TYPE IDS_T IS TABLE OF TF_ROW;
create or replace function func_ids (ids_in in varchar2) return ids_t pipelined is
n_start pls_integer := 1;
n_end pls_integer := 1;
--
begin
loop
-- find the first and next comma in string
n_start := instr(ids_in, ',', n_start, 1);
n_end := instr(ids_in, ',', n_start, 2);
--
if (n_end <= 0) then
exit;
end if;
-- get the string and pipe it back out
pipe row (to_number(substr(ids_in, n_start+1, n_end - n_start - 1)));
-- ready for next one
n_start := n_end;
end loop;
return;
end func_ids;
Script Output:
Function FUNC_IDS compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
22/5 PL/SQL: Statement ignored
22/15 PLS-00382: expression is of wrong type
Errors: check compiler log
What's wrong with the expression here?pipe row (to_number(substr(ids_in, n_start+1, n_end - n_start - 1)));
As you were told, IDS_T isn't declared.
Here's an example which works. See how I did it, do it yourself with your data.
Types:
SQL> create or replace type t_row is object (empno number, ename varchar2 (20));
2 /
Type created.
SQL> create or replace type t_tab is table of t_row;
2 /
Type created.
Function:
SQL> create or replace function func_ids (ids_in in varchar2)
2 return t_tab
3 pipelined
4 is
5 begin
6 for cur_r in (select empno, ename
7 from emp
8 where deptno = ids_in)
9 loop
10 pipe row (t_row (cur_r.empno, cur_r.ename));
11 end loop;
12
13 return;
14 end func_ids;
15 /
Function created.
Testing:
SQL> select * from table(func_ids (20));
EMPNO ENAME
---------- --------------------
7369 SMITH
7566 JONES
7788 SCOTT
7876 ADAMS
7902 FORD
SQL>
How to use the result returned by FUNC_IDS? I'm doing it using code you posted as a comment (the FUNC_ENAME function); I marked what you did wrong.
SQL> CREATE OR REPLACE FUNCTION func_ename (ids t_tab)
2 RETURN VARCHAR2
3 IS
4 l_tmp VARCHAR2 (100);
5 l_result VARCHAR2 (400);
6 BEGIN
7 l_result := ';';
8
9 FOR i IN ids.FIRST .. ids.LAST
10 LOOP
11 SELECT l.ename
12 INTO l_tmp
13 FROM emp l
14 WHERE l.empno = ids (i).empno; --> this line was wrong
15
16 l_result := l_result || l_tmp || ';';
17 END LOOP;
18
19 RETURN l_result;
20 END;
21 /
Function created.
SQL> SELECT func_ename (func_ids (10)) FROM DUAL;
FUNC_ENAME(FUNC_IDS(10))
------------------------------------------------------------------
;CLARK;KING;MILLER;
SQL>

ERROR at line 6: PL/SQL: SQL Statement ignored

I am getting an error at line 6: PL/SQL: SQL Statement ignored.
The line with "select count(*) into ecount" gives the error.
Could anyone help me?
My code:
create or replace function empcount(department in table_employee.dept_name%type)
return integer
as
ecount integer;
begin
select count(*) into ecount
from table_employee
where table_employee.dept_name=deparment and salary>500000;
return ecount;
end;
What is obvious is this: department vs. deparment:
create or replace function empcount(department in table_employee.dept_name%type)
^^^^^^^^^^
vvvvvvvvv
where table_employee.dept_name =deparment and salary>500000;
Apart from that, should be OK:
SQL> create or replace function empcount
2 (department in table_employee.dept_name%type)
3 return integer
4 as
5 ecount integer;
6 begin
7 select count(*) into ecount
8 from table_employee
9 where table_employee.dept_name = department --> fixed
10 and salary > 50000;
11 return ecount;
12 end;
13 /
Function created.
SQL> select empcount(20) from dual;
EMPCOUNT(20)
------------
2
SQL>

Use cursor in LOOP in new QUERY

"I missing the forest through the trees..."
I want to query each column of a table which I retrieve in a FOR LOOP, but the inner query doesn't return the right thing.
Seems that the inner query not use the current column_name.
DECLARE
v_max_TS TIMESTAMP;
BEGIN
FOR cols IN (SELECT column_name FROM all_tab_cols WHERE table_name = '<tablename>')
LOOP
SELECT
MAX(CURR_TIMESTAMP) INTO v_max_TS
FROM <tablename>
WHERE cols.column_name IS NOT NULL
ORDER BY TO_TIMESTAMP(CURR_TIMESTAMP,'MM/DD/YYYY HH24:MI:SS') DESC;
dbms_output.put_line(cols.column_name || ' ' || v_max_TS);
END LOOP;
END;
Apart from the fact that your query doesn't make much sense (as Boneist wrote as a comment), that won't work as you need to use dynamic SQL (execute immediate) for such a purpose.
Here's an example based on Scott's schema. Have a look, adjust it if necessary.
SQL> set serveroutput on
SQL> declare
2 l_str varchar2(200); -- will hold the SELECT statement
3 v_max varchar2(30);
4 begin
5 for cols in (select column_name
6 from all_tab_cols
7 where table_name = 'DEPT'
8 )
9 loop
10 l_str := 'select max(' || cols.column_name ||') from dept';
11 execute immediate l_str into v_max;
12 dbms_output.put_line(cols.column_name ||': '|| v_max);
13 end loop;
14 end;
15 /
DEPTNO: 40
DNAME: SALES
LOC: NEW YORK
PL/SQL procedure successfully completed.
SQL>

How To solve this pl sql oracle query?

Write a PL/SQL program using While Loop to display all DEPTNO,DNAME and LOC
from DEPT table. Assuming the difference between two deptno is 10.
I am beginer and i am very confuse to solve this query please help to solve this problem.
Something like this?
SQL> set serveroutput on
SQL> declare
2 i dept.deptno%type; -- loop counter
3 l_max_deptno dept.deptno%type; -- upper limit
4 l_dept_row dept%rowtype; -- will contain the whole DEPT table row
5 begin
6 -- MIN -> i (which will be the starting point); MAX -> l_max_deptno (which will be the end)
7 select min(deptno), max(deptno)
8 into i, l_max_deptno
9 from dept;
10
11 while i <= l_max_deptno
12 loop
13 -- select the whole row into L_DEPT_ROW
14 select *
15 into l_dept_row
16 from dept
17 where deptno = i;
18
19 dbms_output.put_line(l_dept_row.deptno ||' - '||
20 l_dept_row.dname ||' - '||
21 l_dept_row.loc);
22 -- increment counter by 10 (because, as you said, the difference is 10)
23 i := i + 10;
24 end loop;
25 end;
26 /
10 - ACCOUNTING - NEW YORK
20 - RESEARCH - DALLAS
30 - SALES - CHICAGO
40 - OPERATIONS - BOSTON
PL/SQL procedure successfully completed.
SQL>
Here is how you do what you asked for, but bear in mind this is not the optimum way to do it. if your target is to train your self on the While loop in PLSQL, then here you go.
DECLARE
CURSOR C_DEPTS
IS
SELECT DEPTNO, DNAME, LOC FROM DEPT;
V_DEPTNO VARCHAR2 (255);
V_DNAME VARCHAR2 (255);
V_LOC VARCHAR2 (255);
BEGIN
OPEN C_DEPTS;
FETCH C_DEPTS INTO V_DEPTNO, V_DNAME, V_LOC;
WHILE C_DEPTS%FOUND
LOOP
DBMS_OUTPUT.PUT_LINE ('DEPTNO = ' || V_DEPTNO);
DBMS_OUTPUT.PUT_LINE ('DNAME = ' || V_DNAME);
DBMS_OUTPUT.PUT_LINE ('LOC = ' || V_LOC);
FETCH C_DEPTS INTO V_DEPTNO, V_DNAME, V_LOC;
END LOOP;
END;

Issue with returning bulk collect . The code is thowing error

Error while executing below code. Unable to figure out the issue?
Seems like the Variable V1 is unable to hold too many values
SQL> declare
2 type T1 is table of employee%rowtype index by binary_integer;
3 V1 T1;
4 begin
5 update employee set salary=salary+500
6 where DESCRIPTION ='Tester'
7 returning first_name,last_name,salary,description
8 bulk collect into V1;
9 dbms_output.put_line ('updated # of Tester are : ' ||sql%rowcount);
10
11 for i in V1.FIRST .. V1.LAST
12 loop
13 dbms_output.put_line (V1(i).first_name || ' ' ||
14 V1(i).last_name || ' ' ||
15 V1(i).salary || ' ' ||
16 V1(i).description );
17 end loop;
18 end;
19 /
bulk collect into V1;
*
ERROR at line 8:
ORA-06550: line 8, column 21:
PL/SQL: ORA-00913: too many values
ORA-06550: line 5, column 1:
PL/SQL: SQL Statement ignored
I would love it if we could do what you're suggesting.
You're returning 4 columns, so you must specify 4 targets; unfortunately this means you'll need 4 arrays, not a single array of records.
declare
type first_names_t is table of employee.first_name%type index by binary_integer;
type last_names_t is table of employee.last_name%type index by binary_integer;
type salaries_t is table of employee.salary%type index by binary_integer;
type descriptions_t is table of employee.description%type index by binary_integer;
first_names first_names_t;
last_names last_names_t;
salaries salaries_t;
descriptions descriptions_t;
begin
update employee set salary=salary+500
where DESCRIPTION ='Tester'
returning first_name,last_name,salary,description
bulk collect into first_names,last_names,salaries,descriptions;
...

Resources