I want to create a procedure to insert values in a table. My table has default values for certain fields. I want the same defaults in my procedure without manually typing it in my procedure. eg
create table products
(
prod_id number primary key,
stock number default 0
);
My procedure declaration:
create procedure insert_product
(
prod_id number,
stock number default products.stock.default
);
But I get:
Error(58,99): PLS-00103: Encountered the symbol "DEFAULT" when
expecting one of the following: current delete exists prior The symbol " was inserted before "DEFAULT" to continue.
I tried:
stock number default );
stock number default products.stock );
But they give errors too. Can the table's default value be accessed by the procedure without typing it explicitly in the procedure ? I know
stock number default 0 ); works fine.
I am new to PLSQL so forgive me if it's a silly question.
You can you a private procedure within your main procedure and achieve this. Please check below: Please see that the code is just an example and not tested.
create or replace procedure abc
as
v_num number;
--Private Proc to Main procedure abc
Procedure insert_product ( prod_id number,
stock number )
Is
begin
<you logic>;
end;
Begin
select stock
into v_num
from products
where <condition>;
insert_product(PROD_ID,v_num);
End ;
Related
I'm working on a procedure that will declare a variable, take the value from a procedure that increments, and inserts that value along with other parameters into a table. I thought I had it all worked out, but then I got hit with PLS-00103: Encountered symbol "DECLARE" and Encountered symbol "end-of-file". I feel like I'm so close, so any help would be majorly appreciated! Thank you!
create or replace procedure Order_Create(date_order string, cust_id char, total float, employ_id number)
is
DECLARE NewKey;
BEGIN
NewKey := order_auto_inc.nextval;
UPDATE Progressive_Keys set Order_Limit = NewKey;
insert into ORDERS VALUES (Progressive_Keys.Order_Limit, to_date(date_order, 'yyyy-mm-dd'), cust_id, total, employ_id);
commit;
END;
Remove the declare it's not needed in a stored procedures (as documented in the manual).
A variable declaration needs a data type.
As the parameter order_date is supposed to be a date, it should be declared with that type.
You can't access the column order_limit outside of a statement that uses the table progressive_keys so you need to use the variable in the insert statement as well.
It's also good coding practice to always list the target columns in an INSERT statement (note that I just invented some column names for the orders table you will have to adjust them to reflect the real names in your table)
create or replace procedure Order_Create(date_order date, cust_id varchar, total float, employ_id number)
is
NewKey number;
BEGIN
NewKey := order_auto_inc.nextval;
UPDATE Progressive_Keys set Order_Limit = NewKey;
insert into ORDERS (some_key, order_date, customer_id, total, employee_id)
VALUES (newkey, date_order, cust_id, total, employ_id);
commit;
END;
The UPDATE looks a bit strange as it will update all rows in the thable progressive_keys not just one row.
I am facing a challenge in implementing a scenario in code.
I am trying to use record type, collections and bulk collect at the same time during a proof of concept. But I am unable to and I am getting errors.
I don't know how to pass the bulk collect argument as an input parameter to the proc which I had created in the package below...
CREATE OR REPLACE PACKAGE poc1
AS
TYPE poc_rectype IS RECORD
(
id VARCHAR2 (20),
name VARCHAR2 (20)
);
PROCEDURE poc1_prc (poc_rec1 IN poc_rectype);
END poc1;
CREATE OR REPLACE PACKAGE BODY poc1
AS
PROCEDURE poc1_prc (poc_rec1 IN poc_rectype)
IS
BEGIN
FOR i IN 1 .. poc_rec1.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE ('poc_rec1' || poc_rec1.COUNT);
END LOOP;
*-- i want to print the records passed from the execution script here
-- later i want to do some insertion in some table..*
DBMS_OUTPUT.PUT_LINE ('executed');
END poc1_prc;
END poc1;
Here I am trying to pass only one record for now..
But, I wish to pass a collection of records and print it out or do some insertion in the package containing the procedure above.
/* execution script for the above package*/
DECLARE
l_rec_type poc1.poc_rectype;
BEGIN
SELECT (SELECT 100, 'Jack' FROM DUAL)
BULK COLLECT INTO l_rec_type
FROM DUAL;
poc1.poc1_prc (l_rec_type);
END;
Please could someone help me on implementing this POC.
I tried everything. but i am feeling helpless
You were close, but you were missing a nested table to hold the values. You had a record type and a record variable. But a record variable can only hold a single row of data. To hold multiple rows of data, you need a record type, a nested table, and a nested table variable.
Here's the package to contain the types and process the data:
CREATE OR REPLACE PACKAGE poc1
AS
TYPE poc_rectype IS RECORD
(
id VARCHAR2 (20),
name VARCHAR2 (20)
);
TYPE poc_tab is table of poc_rectype;
PROCEDURE poc1_prc (poc_recs IN poc_tab);
END poc1;
/
CREATE OR REPLACE PACKAGE BODY poc1
AS
PROCEDURE poc1_prc (poc_recs IN poc_tab)
IS
BEGIN
FOR i IN 1 .. poc_recs.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE ('poc_recs.id: ' || poc_recs(i).id);
END LOOP;
END poc1_prc;
END poc1;
/
Here's an anonymous block that populates the nested table variable and passes it to the collection for processing:
DECLARE
l_pocs poc1.poc_tab;
BEGIN
SELECT id, name
BULK COLLECT INTO l_pocs
FROM
(
SELECT 100 id, 'Jack' name FROM DUAL UNION ALL
SELECT 101 id, 'Jill' name FROM DUAL
);
poc1.poc1_prc(l_pocs);
END;
/
Output:
-------
poc_recs.id: 100
poc_recs.id: 101
Since you tagged the question with 10g, you might need to add an extra step, and create the record type and nested table as separate variables. Older versions of Oracle couldn't always convert from SQL to PL/SQL types.
I have a PL/SQL script which executes a number of procedures on an oracle DB.
The script defines:
DECLARE
productkey VARCHAR2(100);
BEGIN
productKey := '000000000070307037';
...
ProcedureName(productKey);
The procedure expects a VARCHAR2
PROCEDURE ProcedureName (
productKey VARCHAR2
)
The procedure inserts into a table:
BEGIN
Insert into Mytable
(
THIS_PRODUCT_KEY
)
Values
(productKey);
When I query that table, the product Key = 70307037, ie the leading 0's have been lost.
I saw some similar questions where TO_CHAR was suggested, I tried defining productKey in the script using TO_CHAR, and also modifiying the procedure to write using TO_CHAR:
BEGIN
Insert into Mytable
(
THIS_PRODUCT_KEY
)
Values
(TO_CHAR(productKey,'000000000000000000'));
Still coming through without the leading 0's.
There are multiple queries that join using the product key and don't work when the 0's are missing.
Why would I lose the 0's when the variable is a VARCHAR ?
I believe that "THIS_PRODUCT_KEY" column in your "Mytable" table is not a varchar2 column. I think it is number. If you change the datatype of the "THIS_PRODUCT_KEY" column to varchar2, it won't lose the 0s.
My terminology will be loose but the point will be clear. I have built a procedure which merges data using Merge Statement. Now my list of tables is growing and I am at a point where I think I need generic function so I just pass table name of source, destination and on condition and can achieve merge.
This will make my code less complex to maintain, otherwise I have to write one procedure per table to make it easy to maintain but still not compact.
Although due to professional reasons a linear code is more efficient as end product but that is less relevant.
Here is my general code.
SET DEFINE OFF;
PROMPT drop Procedure XXX_PROJECTS_MERGE;
DROP PROCEDURE CUSTOM.XXX_PROJECTS_MERGE;
PROMPT Procedure XXX_PROJECTS_MERGE;
/***************************************************************************************************
Prompt Procedure XXX_PROJECTS_MERGE;
--
-- XXX_PROJECTS_MERGE (Procedure)
--
***************************************************************************************************/
CREATE OR REPLACE PROCEDURE CUSTOM.XXX_PROJECTS_MERGE (
errbuf OUT VARCHAR2,
retcode OUT NUMBER,
x_Start_Period_Name IN VARCHAR2)
AS
x_retcode NUMBER := 0;
x_errbuf VARCHAR2 (200) := NULL;
BEGIN
-- Update or insert non transactional tables ------------------------------
-- Refreshing Key Project Table--------------------------------------------------------------------
FND_FILE.PUT_LINE (FND_FILE.LOG, 'Starting Project Table Refresh Process');
MERGE INTO CUSTOM.XXX_PROJECT GPRJ
USING (SELECT ROWID,
PROJECT_ID,
set of columns
FROM PA.PA_PROJECTS_ALL
WHERE ORG_ID = 21
AND LAST_UPDATE_DATE >=
(SELECT MAX (LAST_UPDATE_DATE)
FROM CUSTOM.XXX_PROJECT)) OPRJ
ON (GPRJ.PROJECT_ID = OPRJ.PROJECT_ID AND GPRJ.ROWID = OPRJ.ROWID)
WHEN MATCHED
THEN
UPDATE SET
GPRJ.NAME = OPRJ.NAME,
Above set of columns in above update form
WHEN NOT MATCHED
THEN
INSERT (set of columns)
VALUES (set of values as selected above);
COMMIT;
FND_FILE.PUT_LINE (
FND_FILE.LOG,
'Number of Rows Processed or Merged For XXX_PROJECT Table '
|| TO_CHAR (SQL%ROWCOUNT));
END;
/
SHOW ERRORS;
Now I want above to be generic procedure where I pass different set of inputs and can run for any table.
CREATE TABLE:
create table customer (Name varchar2(10), Address varchar(40), Contact number);
CREATE PROCEDURE FOR INSERT:
CREATE OR REPLACE PROCEDURE SP_CUSTOMER (
p_name customer.Name%TYPE,
p_address customer.Address%TYPE,
p_contact customer.Contact%TYPE)
IS
BEGIN
INSERT INTO customer ("Name", "Address", "Contact")
VALUES (p_name, p_address, p_contact);
COMMIT;
END;
/
ERROR:
IT SHOWS: Warning: Procedure created with compilation errors.
CREATE PROCEDURE FOR SELECT:
CREATE OR REPLACE PROCEDURE SP_SELECT_CUSTOMER (
p_name customer.Name%TYPE,
p_address customer.Address%TYPE,
p_contact customer.Contact%TYPE)
IS
BEGIN
SELECT Name, Address, Contact FROM customer;
END;
/
ERROR:
IT SHOWS: Warning: Procedure created with compilation errors.
What is the problem.? How to solve it.?
Whenever you compile something in SQL*Plus and you get "compilation errors", the first thing you want to do is to SHOW ERRORS, which will tell you what actually went wrong.
Your first procedure has a problem where the column names will not match the column names from your table. Your table definition has Name, Address and Contact, but because you haven't used double-quotes, the column names will actually be NAME, ADDRESS and CONTACT - but your insert statement uses double-quotes, so it tries to insert into Name etc. Just get rid of the double-quotes, you don't need them here.
In your second procedure, you have a SELECT statement in PL/SQL, but you don't specify where to put the resulting data. You at least need an INTO clause, or perhaps do a LOOP over the resulting records.
--you need not to put the column in quotes
CREATE OR REPLACE PROCEDURE SP_CUSTOMER (
p_name customer.Name%TYPE,
p_address customer.Address%TYPE,
p_contact customer.Contact%TYPE)
IS
BEGIN
INSERT INTO customer (Name, Address, Contact)
VALUES (p_name, p_address, p_contact);
COMMIT;
END;
/
--just use a refcursor to return the resultset
CREATE OR REPLACE PROCEDURE SP_SELECT_CUSTOMER (
p_cust_details OUT SYS_REFCURSOR)
IS
BEGIN
OPEN p_cust_details for SELECT Name, Address, Contact FROM customer;
END;
/
EDIT if you want to find details based on name ,then pass an IN parameter and use it as filter condition.
CREATE OR REPLACE PROCEDURE SP_SELECT_CUSTOMER (
p_cust_name IN customer.Name%TYPE
p_cust_details OUT SYS_REFCURSOR)
IS
BEGIN
OPEN p_cust_details for SELECT Name, Address, Contact FROM customer
WHERE name=p_cust_name ;
END;
/
select * from user_errors where name='SP_SELECT_CUSTOMER'