Cursor with a where clause - sql

I am trying to use a cursor with a where clause. It shouldnt be much different from the simple cursor I assume. I tried the following in my case but doesnt seem to print any output.
Declare
BG_TOTAL number;
SDO_GEOM varchar2 ;
cursor c1 is
select
SDO_GEOM.SDO_AREA(GEOMETRY, 0.005,'unit = SQ_MILE')
from <tablename>
where SITE_ID= 8;
Type SITE_TAB_TYPE is table of c1%ROWTYPE;
SITE_LIST SITE_TAB_TYPE;
Begin
open c1;
FETCH c1 BULK COLLECT INTO SITE_LIST;
close c1;
DBMS_OUTPUT.PUT_LINE(SITE_LIST(1).SDO_GEOM);
Exception
When others then
DBMS_OUTPUT.PUT_LINE(sqlerrm);
End;
[Error] Execution (3: 11): ORA-06550: line 3, column 11:
PLS-00215: String length constraints must be in range (1 .. 32767)
ORA-06550: line 7, column 5:
PLS-00487: Invalid reference to variable 'SDO_GEOM'
ORA-06550: line 7, column 5:
PLS-00487: Invalid reference to variable 'SDO_GEOM'
ORA-06550: line 22, column 40:
PLS-00302: component 'SDO_GEOM' must be declared
ORA-06550: line 22, column 6:
PL/SQL: Statement ignored

The problem is that you are trying to output the whole table object to standard output, whereas you should iterate through it. Instead of:
DBMS_OUTPUT.PUT_LINE(SITE_LIST.SDO_GEOM);
Use something like this:
FOR v_i IN 1..SITE_LIST.LAST
LOOP
dbms_output.put_line(SITE_LIST(v_i).SOME_COLUMN_NAME);
END LOOP;
Replace the SOME_COLUMN_NAME with a name of a column selected in your cursor.
Edit
You have to provide an index of the element of your collection to which you want to refer to:
dbms_output.put_line(site_list(1).SDO_GEOM);
Edit #2
Yes.. you didn't specify column alias for value selected in your query. Try this cursor instead:
cursor c1 is
select
SDO_GEOM.SDO_AREA(GEOMETRY, 0.005,'unit = SQ_MILE') AS my_value
from <tablename>
where SITE_ID= 8;
And then:
dbms_output.put_line(site_list(1).my_value);

Related

Subquery in SQL with LOOP

I am getting an error when trying to run a select statement in a PLSQL loop. How can I get it to work?
DECLARE
v_gsp_cnt number := 0;
BEGIN
WHILE v_gsp_cnt > (select max(eachesrem) from salesplan)
LOOP
insert into salesplanexp (select SPNUM,ORDNUM,DMDTYPE,ORDSTATUS,ITEM,LOC,ITEMDESCR,FCST,ORDTYPE,DELSERVLVL,SHIPMETHOD,CARRIER,EACHES,SHIPPEDEACHES,EACHESREM,WEIGHT,VOLUME,STARTSHIPDATE,ENDSHIPDATE,ACTSHIPDATE,STARTDELDATE,ENDDELDATE,ACTDELDATE,ORDCREATEDATE,ORDCONFDATE,BILLCUSTNAME,BILLADD1,BILLADD2,BILLCITY,BILLSTATE,BILLCOUNTRY,BILLZIP,SHIPCUSTNAME,SHIPADD1,SHIPADD2,SHIPCITY,SHIPSTATE,SHIPCOUNTRY,SHIPZIP,LOCPHONE,LOCEMAIL,ACTITEMCOST,ACTITEMPRICE,ACTITEMMARGIN,ACTSHIPCOST,ACTSHIPPRICE,ACTSHIPMARGIN,ACTTOTCOST,ACTTOTPRICE,ACTTOTMARGIN,BRAND,CHANNEL,EXTORDID,EXTLINEID,SOURCESYS,CREATEDATE,LASTUPDATEDDATE from salesplan);
commit;
select x.new_cnt into v_gsp_cnt from (select v_gsp_cnt+1 from dual) x;
commit;
END LOOP;
END;
The error is
ORA-06550: line 4, column 23:
PLS-00405: subquery not allowed in this context
ORA-06550: line 4, column 5:
PL/SQL: Statement ignored
The error, I believe, is from the select statement. But with the loop, I'm not sure another way to make it run properly
The error is coming from this line:
WHILE v_gsp_cnt > (select max(eachesrem) from salesplan)
the actual error is a bit deceiving, but that's the source (note it says "line 4" .. count from DECLARE).
You can't have a query like this in this place.
try this instead:
select max(eachesrem) into v_max from salesplan;
WHILE v_gsp_cnt > v_max
(and as well mentioned by JNevill: you need to alias the inner "v_gsp_cnt+1" as new_cnt ... ) but that's a different error which will show up after you fix the one above. ;)

hierarchical query task with pl/sql

It's my first question.I have such task in school to do.We have table with columns NAME,PARENT,MONEY,CITY.The task is to produce output names,money and average money of descendants for whom it is true, that the average money
of the descendants is greater than the person's money.
I write this code but can't understand error...
CREATE OR REPLACE PROCEDURE rich_avg_descendant IS
cnt INTEGER;
BEGIN
FOR rec IN (SELECT name, money,AVG(money) FROM ourtable) loop
SELECT count(*) INTO cnt FROM ourtable
GROUP BY name
HAVING AVG(money)> rec.money
START WITH name = rec.name CONNECT BY PRIOR name = parent;
IF cnt > 0 THEN dbms_output.put_line(name,money,AVG(money)); END IF;
END loop;
END;
/
Error is in START WITH clause that is START underlined.
Error starting at line : 14 in command -
BEGIN rich_avg_descendant(); END;
Error report -
ORA-06550: line 1, column 7:
PLS-00905: object myschoolcode.RICH_AVG_DESCENDANT is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Can you please tell my mistake in this code?
Thanks in advance.
the connect by clause should be preceding the start with clause

How to get result/data from procedure from SQL command line

looking for what causing to error message below:
[Error] Execution (4: 5): ORA-06550: line 4, column 5: PLS-00306:
wrong number or types of arguments in call to 'ALLOC_DAY_GRAPH_KTL'
ORA-06550: line 4, column 39: PLS-00363: expression '01-Oct-2012'
cannot be used as an assignment target ORA-06550: line 4, column 5:
PLS-00306: wrong number or types of arguments in call to
'ALLOC_DAY_GRAPH_KTL' ORA-06550: line 4, column 5: PL/SQL: Statement
ignored
Thanks in advance
If this is a package existing in a db, you could write a simple pl sql procedure block which calls the required procedure in the package and save it a s a sql script. It can then be called from the sqlplus commandline using #filename.sql
This could be a simple way:
setup:
SQL> CREATE OR REPLACE PACKAGE reports AS
2 TYPE rep_type IS REF CURSOR;
3 END reports;
4 /
Package created.
SQL>
SQL> create or replace procedure testCursor(pIn in number, pCursOut in OUT reports.rep_type) is
2 begin
3 open pCursOut for
4 select 1 as one,
5 'something' as text,
6 pIn as parameter
7 from dual;
8 end;
9 /
Procedure created.
call:
SQL> variable vCur refCursor
SQL> exec testCursor(999, :vCur);
PL/SQL procedure successfully completed.
SQL> print :vCur
ONE TEXT PARAMETER
---------- --------- ----------
1 something 999
SQL>
If you are not in SQLPlus, you may need a plSQL block:
declare
vCur reports.rep_type;
begin
testCursor(999, vCur);
/* code to use the cursor */
end;
/
In this case you need to write some code to do whatever you need with the cursor returned by the procedure.

Using type "is table of" in a select statement

I am trying to create a select statement to select the fields that were select in a previous select statement, as per below code (using oracle 11g):
Declare
type NumberArray IS TABLE OF Number;
v_medium NumberArray;
v_medium_final NumberArray := NumberArray();
v_count number;
type VarcharArray IS TABLE OF VARCHAR2(60);
v_Type VarcharArray
--Select all Regions and Locality affected by the fault
cursor Locality_cur is
Select LocalityCode from AvaFaultLocality where FAULTID=36841 and SITEID=1;
Locality_rec Locality_cur%ROWTYPE;
cursor Region_cur is
Select RegionCode from avafaultregion where FAULTID=36841 and SITEID=1;
Region_rec Region_cur%ROWTYPE;
Begin
v_count := 1;
FOR Region_rec IN Region_cur
LOOP
dbms_output.put_line(Region_rec.RegionCode);
Select RECIPIENTMEDIUMID BULK COLLECT into v_medium from AvaRecipientAreaRegion where RegionCode = Region_rec.RegionCode;
FOR idx IN 1..v_medium.COUNT LOOP
v_medium_final.extend();
v_medium_final(v_count) := v_medium(idx);
dbms_output.put_line(TO_CHAR(v_medium(idx)));
v_count:= v_count + 1;
END LOOP;
dbms_output.put_line('End Loop for Region '||Region_rec.RegionCode);
END LOOP;
dbms_output.put_line(TO_CHAR(v_medium_final.count));
Select MEDIUMTYPECODE BULK COLLECT into v_Type from AvaRecipientMedium where RECIPIENTMEDIUMID in (SELECT * FROM TABLE(v_medium_final)); <--- Line with problem
End;
Mainly what I am trying to do is to select the content of all regions, loop this result and get the content of all locality in those regions, and then get all the RecipientMediumID for each locality and add the result in a variable called v_medium_final. This part is working perfectly.
The problem is when I try to use the result of this selection to select the values in a RecipientMedium table where all the values is in the variable v_medium_final.
I try use:
Select MEDIUMTYPECODE BULK COLLECT into v_Type from AvaRecipientMedium where RECIPIENTMEDIUMID in (SELECT * FROM TABLE(v_medium_final));
or
Select MEDIUMTYPECODE BULK COLLECT into v_Type from AvaRecipientMedium where RECIPIENTMEDIUMID in v_medium_final;
But I always get the errors:
[Error] Execution (32: 126): ORA-06550: line 32, column 126:
PLS-00642: local collection types not allowed in SQL statements
ORA-06550: line 32, column 120:
PL/SQL: ORA-22905: cannot access rows from a non-nested table item
ORA-06550: line 32, column 7:
PL/SQL: SQL Statement ignored
and for the second case:
[Error] Execution (32: 106): ORA-06550: line 32, column 106:
PLS-00642: local collection types not allowed in SQL statements
As the error indicates, you can't use a local collection type. You'd need to use a collection type defined at the SQL level.
CREATE TYPE NumberArray
AS TABLE OF NUMBER;
DECLARE
v_medium NumberArray;
...
This would require that you have the CREATE TYPE privilege and it would mean that your type definition would be visible to anyone with privileges to see it rather than having the scope just of your PL/SQL block.
Personally, I would avoid using Array in the name of a collection type that wasn't a VARRAY simply because the name could be confusing. If I see a type NumberArray, I would guess that it was defined as a VARRAY(n) OF NUMBER rather than a nested table type. Using a ntt suffix for a nested table type would seem more sensible (create type number_ntt as table of number).

OracleEE 11g WITH clause causing error procedure won't compile

This is my first run through with PL SQL so I might be making some sort of silly error.
I am trying to write a procedure in Oracle Express Edition 11g. I am running into an error that has to do with my WITH clause in the procedure body.
Whenever I try and run it I see two errors.
Error report:
ORA-06550: line 14, column 50:
PL/SQL: ORA-00918: column ambiguously defined
ORA-06550: line 12, column 7:
PL/SQL: SQL Statement ignored
ORA-06550: line 29, column 3:
PLS-00306: wrong number or types of arguments in call to 'FIND_HIGH_AVG'
ORA-06550: line 29, column 3:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Code for the procedure is found below.
DECLARE
myTerm courses.term%type;
myLine courses.lineno%type;
procedure find_high_avg (term IN courses.term%type,
line IN courses.lineno%type,
s_fname OUT students.fname%type,
s_lname OUT students.lname%type,
s_sid OUT students.side%type,
s_avg OUT number) is
begin
WITH grades as (select * from components co --line 12 here
join scores sc on co.term = sc.term and co.lineno = sc.lineno and CO.COMPNAME = SC.COMPNAME
where sc.lineno = line and sc.term = term) --line 14 here
select *
into s_fname, s_lname, s_sid, s_avg
from (
select s.fname, s.lname, s.sid, round(sum(points/maxpoints * weight),0) as AV
from grades, students
join students s on grades.sid = s.sid
group by s.sid, s.fname, s.lname
order by AV)
where rownum = 1;
end;
BEGIN
myTerm:='F12';
myLine:='1031';
find_high_avg(myTerm, myLine); --line 29 here
END;
The error at line 10 occurs because parameters to stored procedures do not take a length. The procedure declaration should be something like
procedure find_high_avg (term IN courses.term%type,
line IN courses.lineno%type,
s_fname OUT students.fname%type,
s_lname OUT students.lname%type,
s_sid OUT students.side%type,
average OUT number)
is
The error at line 14 is likely because the parameters to your procedure have the same name as columns in your table. In a SQL statement's scope resolution rules, column names take precedence over local PL/SQL variables. So when you code something like
sc.term = term
Oracle tries to resolve the unqualified TERM using a column in one of the tables. If both tables have a column named TERM, that generates an ambiguous column reference-- Oracle doesn't know which of the two tables to use. Of course, in reality, you don't want it to use the column from either table, you want it to use the parameter. The most common approach to this problem is to add a prefix to your parameter names to ensure that they do not collide with the column names. Something like
procedure find_high_avg (p_term IN courses.term%type,
p_line IN courses.lineno%type,
s_fname OUT students.fname%type,
s_lname OUT students.lname%type,
s_sid OUT students.side%type,
p_average OUT number)
is
The error on line 29 occurs because the procedure takes 6 parameters-- 2 IN and 4 OUT. In order to call it, therefore, you would need to use 6 parameters. Something like
DECLARE
myTerm courses.term%type;
myLine courses.lineno%type;
l_fname students.fname%type;
l_lname students.lname%type;
l_sid students.side%type;
l_avg number;
BEGIN
myTerm:='F12';
myLine:='1031';
find_high_avg(myTerm, myLine,l_fname,l_lname, l_sid, l_avg);
END;
I think it should be end find_high_avg; instead of end; after the select statement.