I am trying to use a with clause within one of the execute immediate statement. It runs fine, but doesn't provide an output. It says anonymous block completed. I have tried SET SERVEROUTPUT ON command and still doesn't work. Could someone please help me out on this one.
begin
execute immediate 'WITH GG AS (
SELECT G46.PROV_NUM ,G46.SEQ_NUM, FM46G_ALTID_TYPE_1 AS ALTID_TYPE ,ALTID_1 AS ALTID ,FM46G_ALTID_SRC_1 AS ALTID_SRC FROM SPSMDMRW.SCW_CFF_46G G46
UNION
SELECT G46.PROV_NUM ,G46.SEQ_NUM, ALTID_TYPE_2 AS ALTID_TYPE,ALTID_2 AS ALTID,FM46G_ALTID_SRC_1 AS ALTID_SRC FROM SPSMDMRW.SCW_CFF_46G G46
UNION
SELECT G46.PROV_NUM ,G46.SEQ_NUM, ALTID_TYPE_3 AS ALTID_TYPE,ALTID_3 AS ALTID,ALTID_SRC_2 AS ALTID_SRC FROM SPSMDMRW.SCW_CFF_46G G46
UNION
SELECT G46.PROV_NUM ,G46.SEQ_NUM, ALTID_TYPE_4 AS ALTID_TYPE ,ALTID_4 AS ALTID ,ALTID_SRC_3 AS ALTID_SRC FROM SPSMDMRW.SCW_CFF_46G G46
)
select * from GG';
end;
It is not the WITH factoring clause, but the fact that you aren't fetching the result into anything.
Should be something like this:
SQL> set serveroutput on
SQL>
SQL> declare
2 l_dname sys.odcivarchar2list;
3 begin
4 execute immediate 'with gg as
5 (select ename from emp where deptno = 10
6 union all
7 select ename from emp where deptno = 30
8 )
9 select ename from gg'
10 bulk collect into l_dname;
11
12 for i in l_dname.first .. l_dname.last loop
13 dbms_output.put_line(l_dname(i));
14 end loop;
15 end;
16 /
ALLEN
WARD
MARTIN
BLAKE
TURNER
JAMES
PL/SQL procedure successfully completed.
SQL>
Related
DECLARE
v_annual_salary NUMBER;
BEGIN
SELECT SAL * 12 INTO v_annual_salary
FROM EMP,DEPT
WHERE EMPNO = 7722;
DBMS_OUTPUT.PUT_LINE ('Annual Salary of 7722 is ' || TO_CHAR(v_annual_salary));
END;
/
Unless DEPT table contains a single row, this query will return TOO_MANY_ROWS. Why do you cross-join EMP and DEPT? Should have been just
SQL> declare
2 v_annual_salary number;
3 begin
4 select sal * 12
5 into v_annual_salary
6 from emp
7 where empno = 7934;
8
9 dbms_output.put_line('Annual salary of 7934 is ' || to_char(v_annual_salary));
10 end;
11 /
Annual salary of 7934 is 15600
PL/SQL procedure successfully completed.
SQL>
(My EMP table doesn't have employee whose EMPNO = 7722 so I used 7934).
Need help understanding how to use a cursor variable in a procedure. And use the anonymous block to call the procedure 6 times to run a set of queries. Trying to figure this out have been giving me a headache, thank you in advance for any help.
CREATE OR REPLACE PROCEDURE City_Jail_SP
(lv_query IN NUMBER,
lv_out out VARCHAR2)
AS
cursor qry_lvl IS
BEGIN
OPEN qry_lvl;
LOOP
FETCH INTO
IF chioce = 1 THEN SELECT AVG(COUNT(*))
FROM crime_officers
GROUP BY officer_id;
ELSIF chioce = 2 THEN SELECT MIN(Fine_amount)
FROM Crime_charges;
ELSIF chioce = 3 THEN COLUMN (hearing_date-date_charged) HEADING DAYS
SELECT crime_id, Classification, date_charged, hearing_date,
( hearing_date-date_charged)
FROM crimes
WHERE hearing_date-date_charged >14;
ELSIF choice = 4 THEN select cl.criminal_id, cl.last, cl.first, cc.Crime_code, cc.Fine_amount
FROM criminals cl
JOIN crimes cr
ON cr.criminal_id = cl.criminal_id
JOIN crime_charges cc
ON cc.crime_id = cr.crime_id;
ELSIF chioce = 5 THEN SELECT LAST, FIRST
FROM officers JOIN crime_officers USING (officer_id)
JOIN crimes USING (crime_id)
GROUP BY (LAST, FIRST)
HAVING COUNT(crime_id)>(SELECT AVG(COUNT(crime_id))
FROM crimes JOIN crime_officers using (crime_id)
GROUP BY officer_id);
ELSIF choice = 6 THEN SELECT DISTINCT FIRST, LAST
FROM criminals JOIN crimes USING (criminal_id)
JOIN crime_charges USING (crime_id)
GROUP BY (FIRST, LAST)
HAVING COUNT(Criminal_ID)<(SELECT AVG(COUNT(Criminal_ID))
FROM crimes JOIN criminals USING (Criminal_ID)
GROUP BY Criminal_ID)
ORDER BY FIRST, LAST;
END IF;
close qry_lvl;
END;
/
It looks as if code you wrote should be shift-deleted so that you could start over.
you started to declare a cursor, but never finished it
you didn't declare any cursor variable to store cursor's values into it
anyway, you'd rather switch to a cursor FOR loop as it is simpler to use
you're fetching into ... what?
there's no end loop
you declared IN and OUT parameters, but never used any of them
there's bunch of select statements in IF, almost all of them returning different data set. Also, there's no into clause in any of them. PL/SQL requires it, so you'll have to declare quite a few local variables
typos, typos, typos ... is it chioce or choice?
what is that column ... heading days thing supposed to do? Sounds like something related to SQL*Plus
Maybe you'd actually want to use refcursors. Here's a simple example based on Scott's schema. Depending on department number, I'm returning different data set.
Sample data:
SQL> SELECT * FROM dept;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
Procedure (kind of simulates what you tried to do):
SQL> CREATE OR REPLACE PROCEDURE p_test (par_deptno IN NUMBER,
2 par_rc OUT SYS_REFCURSOR)
3 IS
4 l_dname dept.dname%TYPE;
5 BEGIN
6 SELECT dname
7 INTO l_dname
8 FROM dept
9 WHERE deptno = par_deptno;
10
11 IF l_dname = 'ACCOUNTING'
12 THEN
13 OPEN par_rc FOR SELECT d.dname, e.ename, e.job
14 FROM dept d
15 JOIN emp e
16 ON e.deptno = d.deptno
17 AND d.deptno = par_deptno;
18 ELSIF l_dname = 'SALES'
19 THEN
20 OPEN par_rc FOR SELECT e.ename, e.job, e.sal
21 FROM emp e
22 WHERE e.job = 'SALESMAN';
23 END IF;
24 END;
25 /
Procedure created.
Testing:
SQL> var l_rc refcursor
SQL> exec p_test(10, :l_rc);
PL/SQL procedure successfully completed.
SQL> print :l_rc
DNAME ENAME JOB
-------------- ---------- ---------
ACCOUNTING CLARK MANAGER
ACCOUNTING KING PRESIDENT
ACCOUNTING MILLER CLERK
SQL> exec p_test(30, :l_rc);
PL/SQL procedure successfully completed.
SQL> print :l_rc
ENAME JOB SAL
---------- --------- ----------
ALLEN SALESMAN 1600
WARD SALESMAN 1250
MARTIN SALESMAN 1250
TURNER SALESMAN 1500
SQL>
Please, read some basic PL/SQL documentation, you can't start coding and making up your own syntax. This is Oracle 12c PL/SQL Language Reference. It will take you some time to read it, but - at least - you'll know what you're doing (I hope so).
I am trying to use variable v_values with set of values inside cursor in the Where clause using IN operator but it returns no record.
create or replace PROCEDURE MyProc IS
/* Cursor decleration */
CURSOR CUR_DUMMY (v_values as varchar2)
IS
SELECT COL1,COL2,COL3
FROM TABLE
WHERE COL1 IN v_values;
l_values varchar2();
BEGIN
l_values:='(''one'',''two'',''three'')';
FOR REC IN CUR_DUMMY (l_values)
LOOP
dbms.output.put_line(REC.col1 || ' ' || REC.col2 || ' ' || REC.col3);
END LOOP;
END;
Any suggestion how to resolve this issue?
IN operator requires a list of values, not the values as comma delimited string.
One simple solution is using nested tables:
create table tab (col1,col2,col3) as
select 'row'||rownum, 2, 3 from dual connect by level<=10
/
create or replace procedure proc is
cursor cur (vl sys.odciVarchar2List) is
select col1,col2,col3
from tab
where col1 in (select column_value val from table (vl));
begin
for rec in cur (sys.odciVarchar2List ('row1','row3','row9')) loop
dbms_output.put_line (rec.col1||' '||rec.col2||' '||rec.col3);
end loop;
end;
/
SQL> exec proc
row1 2 3
row3 2 3
row9 2 3
Here's an example based on Scott's EMP table (as I don't have yours, whose name is invalid anyway). Besides, you should pay attention to fix obvious errors, such as dbms.output (there's no dot but underline), varchar2() variable with no size, v_values as while declaring the cursor (there's no as) and similar stuff which are easy to fix and show that you're actually paying attention to what you're doing, and not typing just because you must.
Read comments within code.
SQL> set serveroutput on;
SQL> create or replace procedure myproc is
2 cursor cur_dummy (v_values varchar2) is
3 -- split V_VALUES into rows
4 select empno, ename, job
5 from emp
6 where job in (select trim(regexp_substr(v_values, '[^,]+', 1, level))
7 from dual
8 connect by level <= regexp_count(v_values, ',') + 1
9 );
10 l_values varchar2(100);
11 begin
12 -- no need to complicate with single quotes and stuff; just name those values
13 l_values:='CLERK, MANAGER';
14
15 for rec in cur_dummy (l_values)
16 loop
17 dbms_output.put_line(rec.empno || ' ' || rec.ename || ' ' || rec.job);
18 end loop;
19 end;
20 /
Procedure created.
SQL> exec myproc;
7369 SMITH CLERK
7566 JONES MANAGER
7698 BLAKE MANAGER
7876 ADAMS CLERK
7900 JAMES CLERK
PL/SQL procedure successfully completed.
SQL>
The question is to retrieve all the students name who have scored more than average marks. So, As i am familiar in SQL i have came up with this query:
SELECT Student_Name
FROM Student
WHERE Mark >
( SELECT AVG(Mark)
FROM Student
);
But i need this query to be in PL/SQL format. Please help me.
It depends on what you want to do, once you convert it to PL/SQL. In PL/SQL, you have to fetch the result into something. For example (based on Scott's schema):
SQL> select ename
2 from emp
3 where sal > (select avg(sal) from emp);
ENAME
----------
JONES
BLAKE
CLARK
SCOTT
KING
FORD
6 rows selected.
You could select into an array:
SQL> set serveroutput on
SQL> declare
2 l_tab sys.odcivarchar2list;
3 begin
4 select ename
5 bulk collect into l_tab
6 from emp
7 where sal > (select avg(sal) from emp);
8
9 for i in l_tab.first .. l_tab.last loop
10 dbms_output.put_line(l_tab(i));
11 end loop;
12 end;
13 /
JONES
BLAKE
CLARK
SCOTT
KING
FORD
PL/SQL procedure successfully completed.
SQL>
Or, you can process those rows directly in a loop:
SQL> begin
2 for cur_e in (select ename
3 from emp
4 where sal > (select avg(sal) from emp))
5 loop
6 dbms_output.put_line(cur_e.ename);
7 end loop;
8 end;
9 /
JONES
BLAKE
CLARK
SCOTT
KING
FORD
PL/SQL procedure successfully completed.
SQL>
Or, you can make a function out of it and return refcursor:
SQL> create or replace function f_test
2 return sys_refcursor
3 is
4 rc sys_refcursor;
5 begin
6 open rc for select ename
7 from emp
8 where sal > (select avg(sal) from emp);
9 return rc;
10 end;
11 /
Function created.
SQL> select f_test from dual;
F_TEST
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
ENAME
----------
JONES
BLAKE
CLARK
SCOTT
KING
FORD
6 rows selected.
SQL>
There might be other options as well. Basically, it just depends on the requirement.
CREATE OR REPLACE PROCEDURE validate_date
AS
strABC DATE;
strDummy VARCHAR2(20);
CURSOR C_Example IS SELECT * from dummytable;
BEGIN
FOR R_Example IN C_RetNxWeek LOOP
strABC := R_RetNxWeek.something;
strDummy := R_RetNxWeek.something;
END LOOP;
IF (something < something) THEN
ELSE
strDummy:= SELECT * FROM sometable WHERE something = something; <-----alternative to do this?
END IF;
END validate_date;
I have a very basic store procedure template like above, i have a cursor that will select some record from a table, in the IF ELSE statement in BEGIN block, i wish to do a checking on a data by selecting a table, since i cannot put cursor in BEGIN block, how can i do that?
The select statement result cannot be stored as you stated,
it should be done via
It should use INTO Clause please refer https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/returninginto_clause.htm
No need of an explicit cursor, use a CURSOR FOR LOOP. I don't know your requirement, since I think it could be done using plain SQL. However, if you really want to use PL/SQL, you can make use of BULK COLLECT and FORALL.
And regarding the SELECT, you need to use INTO clause in PL/SQL.
SQL> DECLARE
2 eno NUMBER;
3 STR_DUMMY VARCHAR2(20);
4 BEGIN
5 FOR i IN
6 (SELECT * FROM emp
7 )
8 LOOP
9 eno := i.empno;
10 dbms_output.put_line(eno);
11 END LOOP;
12 SELECT ENAME INTO STR_DUMMY FROM EMP WHERE EMPNO = 7788;
13 dbms_output.put_line(STR_DUMMY);
14 END;
15 /
7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934
SCOTT
PL/SQL procedure successfully completed.
SQL>