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'
Related
I am facing a weird problem here.
PROCEDURE USL_EMPLOYEEBYID (
EMPLOYEE_ID IN NUMBER,
EMPIDCURSOR OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN EMPIDCURSOR FOR
SELECT emp.employee_id,emp.employee_name,emp.present_address,emp.permanent_address,emp.status
FROM Employee_Info emp
WHERE emp.employee_id = EMPLOYEE_ID;
END;
This procedure should give me a single employee upon entering the employee Id. But it is returning all the employees.
What am I doing wrong here?
In your query, Oracle interprets EMPLOYEE_ID as the column EMPLOYEE_ID, not the input parameter, here you find something more; in this way, your where condition is something like a=a.
Change the parameter name to distinguish it from the table column:
PROCEDURE USL_EMPLOYEEBYID (
p_EMPLOYEE_ID IN NUMBER,
po_EMPIDCURSOR OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN po_EMPIDCURSOR FOR
SELECT emp.employee_id,emp.employee_name,emp.present_address,emp.permanent_address,emp.status
FROM Employee_Info emp
WHERE emp.employee_id = p_EMPLOYEE_ID;
END;
this is a good practice, to always know in your code whether you are handling an input parameter, a local variable, a column and so on
FYI: Oracle 12c
I have created a custom type called Payeezy_Error:
create or replace TYPE PAYEEZY_ERROR
AS
OBJECT (
CODE VARCHAR(30),
DESCRIPTION VARCHAR(200)
);
And then in turn created a Table type of Payeezy_Errors:
create or replace TYPE PAYEEZY_ERRORS AS TABLE OF PAYEEZY_ERROR;
I then have a Procedure that takes Payeezy_Errors as an IN parameter:
create or replace PROCEDURE SAVE_USER_PAYMENT_TRANSACTION
(
in_AccountID IN VARCHAR2,
in_SequenceID IN VARCHAR2,
in_CorrelationID IN VARCHAR2,
in_TransactionID IN VARCHAR2,
in_TransactionTag IN VARCHAR2,
in_Currency IN VARCHAR2,
in_TransactionType IN VARCHAR2,
in_BankResponse IN VARCHAR2,
in_GatewayResponse IN VARCHAR2,
in_ValidationStatus IN VARCHAR2,
in_TransactionStatus IN VARCHAR2,
in_Errors IN PAYEEZY_ERRORS
)
AS
var_uptID NUMBER;
var_ErrorCount NUMBER := 0;
EX_AUTHENTICATION EXCEPTION;
BEGIN
-- Insert the Payeezy Response values tied to the user
INSERT INTO
USER_PAYMENT_TRANSACTION (
ACCOUNT_ID, UP_PAYMENT_SEQ_ID, CORRELATION_ID, TRANSACTION_ID,
TRANSACTION_TAG, CURRENCY, TRANSACTION_TYPE, BANK_RESPONSE,
GATEWAY_RESPONSE, VALIDATION_STATUS, TRANSACTION_STATUS
) VALUES (
in_AccountID, in_SequenceID, in_CorrelationID, in_TransactionID,
in_TransactionTag, in_Currency, in_TransactionType, in_BankResponse,
in_GatewayResponse, in_ValidationStatus, in_TransactionStatus
)
RETURNING
ID
INTO
var_uptID;
-- Insert any errors that may be associated with a failure/unsuccessful transaction
SELECT
COUNT(*)
INTO
var_ErrorCount
FROM
in_Errors;
IF (var_ErrorCount > 0) THEN
INSERT INTO
USER_PAYMENT_TRANSACTION_ERROR (
UPT_ID, CODE, DESCRIPTION
)
SELECT
var_uptID, e.CODE, e.DESCRIPTION
FROM
in_Errors;
END IF;
-- Exception Handling
EXCEPTION
WHEN EX_AUTHENTICATION THEN
raise_application_error(-20001, 'Authentication Failed.');
END SAVE_USER_PAYMENT_TRANSACTION;
When I compile the procedure it yells at me at the SELECT COUNT(*) statement that:
ORA-00942: table or view does not exist.
And red-dashes are under SELECT and in_Errors.
Further down the procedure I get the same error and the second INSERT INTO and in_Errors lines are red-dashes too.
I have exited and reloaded Oracle SQL Developer just to see if it was a caching thing. I have searched around the web but have not found my particular case.
If you want to use the table in a query, you'd need to use the table operator
SELECT
COUNT(*)
INTO
var_ErrorCount
FROM
table( in_Errors );
That works. But it means that you're taking all of the data that you have in the PL/SQL collection, moving it to the SQL VM, doing the aggregation, and then returning the result to PL/SQL. It would likely be more efficient (and less code) in this case to just do
var_ErrorCount := in_Errors.count;
I'm trying to write a procedure that can take a column name as an input parameter and select that column from a table.
I know you can do this in a regular query by simply creating a string variable and referencing the column like such:
DEFINE mycol = 'column1'
SELECT a.&mycol FROM table1 a
This does however not work within a procedure. Variables in procedures don't appear to be able to be referenced by the '&' symbol, and as such when I attempt to pull a column using an input parameter it tells me that it's an invalid identifier.
Searching around on the internet, I can't find an example of someone doing this without dynamic SQL, when inside a proc. I would prefer not to use dynamic SQL if possible.
Does anyone know a workaround for this, or is dynamic SQL required in procs for this to occur?
Cheers,
Ollie
Dynamic SQL in named block is inevitable as ampersand construct are not compliant with SQL standard. It's only feature of SQL Plus engine.
I have tested the scenarios as described.
CREATE TABLE SCOTT.COLUMN_LIST
(
COLUMN_ID NUMBER,
COLUMN_NAME VARCHAR2(200),
TABLE_NAME VARCHAR2(50 )
);
Insert into SCOTT.COLUMN_LIST
(COLUMN_ID, COLUMN_NAME, TABLE_NAME)
Values
(1, 'DEPTNO', 'DEPT');
COMMIT;
CREATE TABLE SCOTT.TEST1
(
A VARCHAR2(300 BYTE)
);
CREATE OR REPLACE PROCEDURE PROC1
IS
v_Select_Column VARCHAR2(200);
v_Table_Name VARCHAR2(50 );
V_SQL VARCHAR2(300);
BEGIN
SELECT COLUMN_NAME,TABLE_NAME
INTO v_Select_Column,v_Table_Name
FROM COLUMN_LIST
WHERE COLUMN_ID=1;
V_SQL:= 'SELECT '||v_Select_Column||
' FROM '||v_Table_Name;
EXECUTE IMMEDIATE V_SQL;
INSERT INTO TEST1 values(V_SQL);
COMMIT;
END PROC1;
/
Please test at your end. You can see the output on test1 table.
I have got stuck in below and getting syntax error - Please help.
Basically I am using a collection to store few department ids and then would like to use these department ids as a filter condition while inserting data into emp table in FORALL statement.
Below is sample code:
while compiling this code i am getting error, my requirement is to use INSERT INTO table select * from table and cannot avoid it so please suggest.
create or replace Procedure abc(dblink VARCHAR2)
CURSOR dept_id is select dept_ids from dept;
TYPE nt_dept_detail IS TABLE OF VARCHAR2(25);
l_dept_array nt_dept_detail;
Begin
OPEN dept_id;
FETCH dept_id BULK COLLECT INTO l_dept_array;
IF l_dept_array.COUNT() > 0 THEN
FORALL i IN 1..l_dept_array.COUNT SAVE EXCEPTIONS
EXECUTE IMMEDIATE 'INSERT INTO stg_emp SELECT
Dept,''DEPT_10'' FROM dept_emp'||dblink||' WHERE
dept_id = '||l_dept_array(i)||'';
COMMIT;
END IF;
CLOSE dept_id;
end abc;
Why are you bothering to use cursors, arrays etc in the first place? Why can't you just do a simple insert as select?
Problems with your procedure as listed above:
You don't declare procedures like Procedure abc () - for a standalone procedure, you would do create or replace procedure abc as, or in a package: procedure abc is
You reference a variable called "dblink" that isn't declared anywhere.
You didn't put end abc; at the end of your procedure (I hope that was just a mis-c&p?)
You're effectively doing a simple insert as select, but you're way over-complicating it, plus you're making your code less performant.
You've not listed the column names that you're trying to insert into; if stg_emp has more than two columns or ends up having columns added, your code is going to fail.
Assuming your dblink name isn't known until runtime, then here's something that would do what you're after:
create Procedure abc (dblink in varchar2)
is
begin
execute immediate 'insert into stg_emp select dept, ''DEPT_10'' from dept_emp#'||dblink||
' where dept_id in (select dept_ids from dept)';
commit;
end abc;
/
If, however, you do know the dblink name, then you'd just get rid of the execute immediate and do:
create Procedure abc (dblink in varchar2)
is
begin
insert into stg_emp -- best to list the column names you're inserting into here
select dept, 'DEPT_10'
from dept_emp#dblink
where dept_id in (select dept_ids from dept);
commit;
end abc;
/
There appears te be a lot wrong with this code.
1) why the execute immediate? Is there any explicit requirement for that? No, than don't use it
2) where is the dblink variable declared?
3) as Boneist already stated, why not a simple subselect in the insert statement?
INSERT INTO stg_emp SELECT
Dept,'DEPT_10' FROM dept_emp#dblink WHERE
dept_id in (select dept_ids from dept );
For one, it would make the code actually readable ;)
This is the code i used in stored procedure;
CREATE OR REPLACE PROCEDURE MY_STORE_PROCEDURE (new_date in date)
IS
BEGIN
execute immediate 'INSERT INTO TEMP_1 ( ID CHAR(10),
A_CNT NUMBER,
JOIN_DT DATE,
)
SELECT
L1.ID,
L1.A_CNT,
L1.JOIN_DT,
FROM ACTVY_1 L1
WHERE L1.JOIN_DT = new_date';
END;
===========================================================
Below is the code i used to call store procedure with passing value. value is date which store procedure reciece and used to pull date from a table. but it is giving me error.
DECLARE
a_date DATE;
BEGIN
a_date :=to_DATE ('01-NOV-2013', 'DD-MON-YYYY');
MY_STORE_PROCEDURE(a_date);
END;
Please suggest is there any syntax error or what is issue.
Based on your example, there is no reason to use dynamic SQL. You also have a bunch of errors. Try this:
CREATE OR REPLACE PROCEDURE MY_STORE_PROCEDURE (new_date IN DATE)
IS
BEGIN
INSERT INTO TEMP_1 (ID, A_CNT, JOIN_DT)
SELECT L1.ID, L1.A_CNT, L1.JOIN_DT
FROM ACTVY_1 L1
WHERE L1.JOIN_DT = new_date;
END;