Procedure select 1 and delete - oracle

I am trying to create a procedure that
1. Selects the first record.
2. Deletes the record and returns it to the caller.
I have the following code (mind you I am fairly new to PLSQL).
I got it from looking at other SO questions and the oracle docs.
CREATE PROCEDURE TAKE_1_DELETE_1
AS
BEGIN
DELETE FROM my_table
where rownum = 1
RETURNING *
INTO v_event;
END TAKE_1_DELETE_1;
I get the following error:
[Error] PLS-00103 (7: 3): PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
; <an identifier> <a double-quoted delimited-identifier>
current delete exists prior <a single-quoted SQL st
I have tried numerous things, but none have worked thus far.
Our Data-Warehouse people are saying "We don't know what is wrong".
Dear SO gods... what do I need to do, to get my procedure to do what I want? :)

There's a couple of errors here:
You haven't declared v_event so you're trying to return data into a uninstantiated variable/out parameter
You can't "return" * you have to explicitly state all columns - this is the actual error you're getting
Assuming a table that looks like this
create table my_table (a number, b number);
Your procedure would look like the following:
create or replace procedure take_1_delete_1 is
v_event my_table%rowtype;
begin
delete from my_table
where rownum = 1
returning a, b
into v_event;
end take_1_delete_1;
Or, if you wanted to use the returning value outside the procedure you can use an OUT parameter rather than declaring a local variable
create or replace procedure take_1_delete_1 (p_event out my_table%rowtype) is
begin
delete from my_table
where rownum = 1
returning a, b
into p_event;
end take_1_delete_1;

Related

How do I convert SQL code to PL/SQL for an APEX process

I've got the below code which works perfectly in SQL Developer, but I need to input the code within a process block in APEX and it is only giving me a PL/SQL option. Below is the code which I've written:
BEGIN
truncate table TEMP_UPLOAD;
Merge into INVOICE b
USING (
SELECT CUSTOMER_CLASS,RULE_AGGREGATOR,BA
FROM CUSTOMER_TEMP_UPLOAD
WHERE CUSTOMER_CLASS = 'CUSTOMER88') u
ON (b.BA = u.BA)
WHEN MATCHED THEN UPDATE SET b.CUSTOMER88_DATE_UPDATED = sysdate
WHEN NOT MATCHED THEN
INSERT (b.CUSTOMER_CLASS,b.RULE_AGGREGATOR,b.BA,b.CUSTOMER88_DATE_ADDED)
VALUES (u.CUSTOMER_CLASS,u.RULE_AGGREGATOR,u.BA,sysdate);
UPDATE INVOICE a
SET a.CUSTOMER88_DATE_REMOVED = sysdate
WHERE BA IN
(select b.BA
from INVOICE b
left join CUSTOMER_temp_upload u
on b.BA = u.BA
where u.BA is null and b.CUSTOMER_CLASS = 'CUSTOMER88');
END;
Getting following error
1 error has occurred
•ORA-06550: line 3, column 14: PLS-00103: Encountered the symbol "TABLE" when expecting one of the following: := . ( # % ;
The error message is pointing you to your TRUNCATE TABLE command.
TRUNCATE is a DDL command - don't call it from PL/SQL. Instead, use a DELETE so that your process will be transaction-safe.
(P.S. it is technically possible to run DDL from PL/SQL using EXECUTE IMMEDIATE - but I don't advise it)
Seems that the issue was it did not like my BEGIN and END; in uppercase. When I changed it to Begin and end; as well as changed the TRUNCATE table command to a delete, it then accepted it and the PL/SQL command worked as intended.

Error(5,1): PLS-00103: Encountered the symbol "CREATE" error while creating function

Error(5,1): PLS-00103:
Encountered the symbol "CREATE" when expecting one of the following:
( begin case declare exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
Below the code I've written.
CREATE OR replace FUNCTION First_three_records
RETURN NUMBER AS
BEGIN
CREATE TEMPORARY TABLE temp_emp ON COMMIT DROP AS
SELECT *
FROM emp
WHERE deptno=20;
INSERT INTO tgt
SELECT *
FROM temp_emp;
END;
Oracle does not have local temporary tables, and you can't create objects within a PL/SQL block unless you use dynamic SQL; and it's very rarely necessary or a good idea. Your schema should be created in a controlled way, not on the fly.
You could use a collection instead but there is no point here, you can just do:
INSERT INTO tgt
SELECT *
FROM emp
WHERE deptno=20;
I'm not sure why you're wrapping that in a function at all; your function is also declared to return a number, but you have no return statement.

PLS-00103: Encountered the symbol "(" when expecting one of the following:

I am trying to retrieve a customer id pk column from a report page to a form page that gets automatically incremented whenever the user moves from the report page to the form page using oracle application express.So i am trying to create a trigger that returnns a number having the value of the final row along with a +1 increment to it. However i get this error
Error at line 8: PLS-00103: Encountered the symbol "(" when expecting one of the following:
, from
6. INTO number
7. FROM (SELECT a.cust_id, max(cust_id) over() as max_pk FROM customer a)
8. WHERE cust_id = max_pk;
9. number:=(cust_id+1);
10. END;
This is my PL/SQL procedure.
CREATE OR REPLACE FUNCTION cust_id_incremental(cust_id IN number)
RETURN number;
BEGIN
SELECT cust_id
INTO number
FROM (SELECT a.cust_id, max(cust_id) over() as max_pk FROM customer a)
WHERE cust_id = max_pk;`enter code here`
number:=(cust_id+1);
END;
number is a reserve word, you need to call it something else like l_number to be a variable name.
You need to define a variable to contain the result, populate it, then return it. The corrected procedure might look like this:
CREATE OR REPLACE FUNCTION cust_id_incremental (cust_id IN NUMBER)
RETURN NUMBER IS
v_cust_id NUMBER;
BEGIN
SELECT cust_id
INTO v_cust_id
FROM (SELECT a.cust_id, MAX (cust_id) OVER () AS max_pk
FROM customer a)
WHERE cust_id = max_pk;
v_cust_id := v_cust_id + 1;
RETURN v_cust_id;
END;
Taking a second look, the structure of this procedure is far more convoluted than it needs to be. Unless I'm missing something, you could accomplish the same thing with a procedure that looked like this:
CREATE OR REPLACE FUNCTION cust_id_incremental
RETURN NUMBER IS
v_cust_id NUMBER;
BEGIN
SELECT MAX (cust_id) + 1
INTO v_cust_id
FROM customer a;
RETURN v_cust_id;
END;
It occurred to me as I was writing this that you may have namespace issue: your original function accepts a parameter CUST_ID, then queries a table with column CUST_ID. All of the references to CUST_ID in the query will refer to the column, not the parameter. If the parameter serves a purpose, it is being obscured.
However, you really shouldn't be doing this. If two sessions call this procedure simultaneously and insert the resulting value into a new row, you'll have a primary key violation. This is the entire reason that sequences exist. As sequences are not transactional, multiple sessions that access the same sequence will get different values.

How to return a table of values from a function in oracle

I have tried some of the answers and could not make my code work:
Here is what I want and here is what I did:
I have a table which is two column type and I want to query that table using a function to return exactly the same table to be routed to VB.NET so that I can display it in a DatagridView control.
I am a novice to PL/SQL which is the problem for me.
The first problem I intended to solve is to create the function.
-- DECLARE A RECORD TYPE
create or replace type shipper_type AS OBJECT
(
shipper_id number, shipper_name varchar2(7)
);
/
CREATE TYPE t_shipper as table of shipper_type;
/
create or replace function get_shipper return t_shipper is
temp_list t_shipper:= t_shipper();
is
-- shipper_record shipper_type;
begin
for i in ( (select shipper.shipper_id, shipper.shipper_name) list from shipper)
loop
temp_list.extend;
temp_list(temp_list.last):= t_shipper(list);
end loop;
return(temp_list);
end get_shipper;
/
When I try to compile this code I am getting the following errors:
Errors for FUNCTION GET_SHIPPER:
LINE/COL ERROR
-------- -----------------------------------------------------------------
3/1 PLS-00103: Encountered the symbol "IS" when expecting one of the
following:
begin function pragma procedure subtype type <an identifier>
<a double-quoted delimited-identifier> current cursor delete
exists prior
6/63 PLS-00103: Encountered the symbol ")" when expecting one of the
following:
. ( , * # % & - + / at mod remainder rem <an identifier>
<a double-quoted delimited-identifier> <an exponent (**)> as
from || multiset
You get those compilation messages because you have several syntax errors in your code. Two instances of IS, missing the type in the select, those unnecessary brackets in the return. You can correct those but you should simplify your code too.
The easiest way to populate a nested table is with a bulk collect.
create or replace function get_shipper return t_shipper is
temp_list t_shipper:= t_shipper();
begin
select shipper_type(shipper.shipper_id, shipper.shipper_name)
bulk collect into temp_list
from shipper;
return temp_list ;
end get_shipper;
/
Try it without () in the return statement and add an end; at the end.
return temp_list;
end;
Also you might want to take a look at so called pipelined functions:
http://www.oracle-base.com/articles/misc/pipelined-table-functions.php

Writing Oracle Stored Procedure

I haven't written many stored procedures with oracle. I read through some tutotorials (for example: http://plsql-tutorial.com/plsql-procedures.htm) and tried to model my sp after what I saw, but I am still encountering an error. Here's is a small sample procedure and error:
create or replace
PROCEDURE TEST_SP()
BEGIN
insert into tablespace.tablename
select * from testtable;
END TEST_SP;
PLS-00103: Encountered the symbol ")" when expecting one of the following:
<an identifier> <a double-quoted delimited-identifier>
I get the impression that I am missing the declaration section, but I do not understand what I am supposed to be declaring :-/
Any help would be appreciated.
Followed Justin's advice from first response, now getting different error:
create or replace
PROCEDURE TEST_SP
AS
BEGIN
insert into tablespace.tablename (col1, col2)
select (col1, col2) from testtable;
END TEST_SP;
PLS-00103: Encountered the symbol "AS" when expecting one of the following:
. , # in <an identifier> <a double-quoted delimited-identifier> partition subpartition
It sounds like you're after something like this. You don't want to have parenthesis after the name of the procedure if you are not declaring any parameters. And you need the keyword AS (or IS) before your BEGIN even if you're not going to declare any local variables.
create or replace PROCEDURE TEST_SP
AS
BEGIN
insert into tablespace.tablename
select * from testtable;
END TEST_SP;
Generally, however, it's a bad idea to write code like this that omits the list of columns. That assumes that the two tables have exactly the same columns defined in exactly the same order so if someone decides to add another column to one of the tables, your code will break. It also creates the possibility that you're inadvertently copying data from the wrong column. It is generally more robust to write something like
create or replace PROCEDURE TEST_SP
AS
BEGIN
insert into tablespace.tablename( <<list of columns>> )
select <<list of columns>>
from testtable;
END TEST_SP;
As an example
SQL> create table foo( col1 number );
Table created.
SQL> create table foo_cpy( col1 number );
Table created.
SQL> ed
Wrote file afiedt.buf
1 create or replace procedure test_sp
2 as
3 begin
4 insert into foo( col1 )
5 select col1
6 from foo_cpy;
7* end test_sp;
SQL> /
Procedure created.

Resources