Subquery in SQL with LOOP - sql

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. ;)

Related

Using variables in Oracle SQL query

I need use variable in select statement, but I don't know what I doing wrong.
If I run the test script bellow, it's works fine:
DECLARE
SalesOrderId VARCHAR(10);
BEGIN
SalesOrderId := '138296584';
dbms_output.put_line(SalesOrderId);
END;
But, if I put a select query inside Begin-End block, don't work. Here the code:
DECLARE
SalesOrderId VARCHAR(10);
BEGIN
SalesOrderId := '138296584';
dbms_output.put_line(SalesOrderId);
SELECT * FROM tblOrders tbl WHERE tbl.SalesOrderId = SalesOrderId;
END;
And throws the error:
[Error] Execution (8: 5): ORA-06550: line 8, column 5: PLS-00428: an INTO clause is expected in this SELECT statement
What I doing wrong?
Thanks.
There error is clear, you need to store the output somewhere (make sense) , so use the INTO :
SELECT tbl.SalesOrderId,tbl.column1
INTO varSalesOrderId,varColumn1
FROM tblOrders tbl
WHERE tbl.SalesOrderId = SalesOrderId;

Cursor with a where clause

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);

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.

Error(2,7): PLS-00428: an INTO clause is expected in this SELECT statement

I'm trying to create this trigger and getting the following compiler errors:
create or replace
TRIGGER RESTAR_PLAZAS
AFTER INSERT ON PLAN_VUELO
BEGIN
SELECT F.NRO_VUELO, M.CAPACIDAD, M.CAPACIDAD - COALESCE((
SELECT count(*) FROM PLAN_VUELO P
WHERE P.NRO_VUELO = F.NRO_VUELO
), 0) as PLAZAS_DISPONIBLES
FROM VUELO F
INNER JOIN MODELO M ON M.ID = F.CODIGO_AVION;
END RESTAR_PLAZAS;
Error(2,7): PL/SQL: SQL Statement ignored
Error(8,5): PL/SQL: ORA-00933: SQL command not properly ended
Error(8,27): PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: begin case declare end exception exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe
Error(2,1): PLS-00428: an INTO clause is expected in this SELECT statement
What's wrong with this trigger?
You won't be allowed to
SELECT count(*) FROM PLAN_VUELO
in a trigger on PLAN_VUELO
Don't use a trigger. Use a stored procedure.
Inside a PL/SQL block you have to SELECT ... INTO something. I had an example of this in an answer to one of your questions yesterday. In this case you may want to select into a local variable, and use the result to then update another table.
But it looks like you're probably going to get lots of results back because you haven't restricted to the value you're interested in; the WHERE clauses don't filter on any of the inserted row's :NEW values. That will cause an ORA-02112. You need to make sure your select will return exactly one row, or look at cursors if you actually want multiple rows.
Just add the into clause according to the result type, one example:
declare
my_result VUELO%rowtype;
begin
select v.* into my_result from VUELO v where id = '1';
end;

Using variables in PLSQL SELECT statement

I have a query that queries on ReportStartDate and ReportEndDate so I thought I would use variables in PLSQL. Not sure what I am missing here, but I get an error:
CLEAR;
DECLARE
varReportStartDate Date := to_date('05/01/2010', 'mm/dd/yyyy');
varReportEndDate Date := to_date('05/31/2010', 'mm/dd/yyyy');
BEGIN
SELECT
'Value TYPE',
1 AS CountType1,
2 AS CountType2,
3 AS CountType3
FROM DUAL;
SELECT COUNT (*)
FROM CDR.MSRS_E_INADVCH
WHERE 1=1
AND ReportStartDate = varReportStartDate
AND ReportEndDate = varReportEndDate
;
END;
/
The Error is:
Error starting at line 2 in command:
Error report:
ORA-06550: line 6, column 5:
PLS-00428: an INTO clause is expected in this SELECT statement
ORA-06550: line 8, column 5:
PLS-00428: an INTO clause is expected in this SELECT statement
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
This happens in Toad as well as in SQL Developer.
What is the proper way of using the variables in my WHERE clause?
You cannot use SQL statements directly in a PL/SQL block ( unless you use EXECUTE IMMEDIATE). The columns will need to be fetched into variables ( which is what PL/SQL is telling you with PLS-00428: an INTO clause is expected in this SELECT statement error). So you'll have to rewrite your statements as below.
SELECT
'Value TYPE',
1 AS CountType1,
2 AS CountType2,
3 AS CountType3
INTO
V_VALUE_TYPE,
V_CountType1,
V_CountType2,
V_CountType3
FROM DUAL;
SELECT COUNT(*)
INTO V_COUNT
FROM CDR.MSRS_E_INADVCH
WHERE 1=1
AND ReportStartDate = varReportStartDate
AND ReportEndDate = varReportEndDate
Be sure to add Exception Handlers, since PL/SQL expects only 1 row to be returned. If the statement returns no rows, you'll hit a NO_DATA_FOUND exception - and if the statement fetches too many rows, you'll hit a TOO_MANY_ROWS exception.
The question you have to answer is what do you want to do with the data that has been selected?
Sathya gave you one approach - declare variables in your PL/SQL block and select the columns INTO those variables. Note that this requires that the SELECT statement returns exactly one row - any more or less rows will throw an error. Another way is to declare collection types using the BULK COLLECT option: http://oracletoday.blogspot.com/2005/11/bulk-collect_15.html
Yet another option is to have the procedure return a cursor. This is useful in the case where the calling code expects to be able to fetch the data that the procedure has selected:
PROCEDURE GET_MY_REPORT( varReportStartDate in date, varReportEndDate in date, cur out sys_refcursor) is
begin
OPEN cur FOR SELECT *
FROM CDR.MSRS_E_INADVCH
WHERE 1=1
AND ReportStartDate = varReportStartDate
AND ReportEndDate = varReportEndDate;
END GET_MY_REPORT;