procedure problem - oracle

create or replace
PROCEDURE XXB_RJT_HEADER_PROCEURE
(
V_PROD_ID IN NUMBER,
V_WARE_ID IN XXB_RJT_HEADER.WAREHOUSE_ID% TYPE,
V_PAY_METH IN XXB_RJT_HEADER.PAYMENT_METHOD% TYPE,
V_PAY_STAT IN XXB_RJT_HEADER.PAYMENT_STATUS% TYPE,
V_ORD_ID IN XXB_RJT_HEADER.ORDER_ID% TYPE,
V_ORD_DT IN XXB_RJT_HEADER.ORDER_DATE% TYPE )
AS
V_PROD_NM VARCHAR2(50);
V_WAR_NM VARCHAR2(15);
BEGIN
SELECT PRODUCT_CAT
INTO V_PROD_NM
FROM xxb_rjt_inventory
WHERE XXB_RJT_INVENTORY.product_id= V_prod_id;
SELECT WAREHOUSE_NAME
INTO V_WAR_NM
FROM xxb_rjt_inventory
WHERE XXB_RJT_INVENTORY.product_id= V_prod_id;
INSERT
INTO XXB_RJT_HEADER
( /*second error*/
warehouse_id,
PAYMENT_METHOD,
payment_status,
product_name,
order_id,
wareshouse_name,
order_date
)
VALUES
(
V_warehouse_id,
v_pay_meth, /*First error*/
V_pay_stat,
V_prod_nm,
V_ord_id,
V_war_nm,
V_ord_dt
);
END XXB_RJT_HEADER_PROCEURE;
when i compile this i get the following errors
Error(37,7): PL/SQL: ORA-00984: column not allowed here
Error(24,65530): PL/SQL: SQL Statement ignored
thanks for the help in advance

"V_warehouse_id" is no declared anywhere.

Your ORA-00984 error means:
A column name was used in an
expression where it is not permitted,
such as in the VALUES clause of an
INSERT statement.
Check the VALUES part of the INSERT to be sure none of the arguments are columns.
Once you fix that, see if the other error goes away. "PL/SQL: SQL Statement ignored" seems to appear after there's already another error.

You can rewrite is in something like (untested):
create or replace
PROCEDURE XXB_RJT_HEADER_PROCEURE
(
V_PROD_ID IN xxb_rjt_inventory.product_id%type,
V_WARE_ID IN XXB_RJT_HEADER.WAREHOUSE_ID% TYPE,
V_PAY_METH IN XXB_RJT_HEADER.PAYMENT_METHOD% TYPE,
V_PAY_STAT IN XXB_RJT_HEADER.PAYMENT_STATUS% TYPE,
V_ORD_ID IN XXB_RJT_HEADER.ORDER_ID% TYPE,
V_ORD_DT IN XXB_RJT_HEADER.ORDER_DATE% TYPE )
AS
BEGIN
INSERT
INTO XXB_RJT_HEADER
(
warehouse_id,
PAYMENT_METHOD,
payment_status,
product_name,
order_id,
wareshouse_name,
order_date
)
select
V_ware_id,
v_pay_meth,
V_pay_stat,
product_cat,
V_ord_id,
warehouse_name,
V_ord_dt
from xxb_rjt_inventory
where product_id= V_prod_id;
END XXB_RJT_HEADER_PROCEURE;
This means two less sql statements and two less variables to declare. Also change the name of the procedure, you write proceure instead of procedure. I also changed the type of the first parameter of your procedure.

Related

create a random uuid function and use it to generate column value in oracle [duplicate]

I am trying to update a table in Oracle. The table is created using following DDL:
CREATE TABLE TEST (
ID_NUM INTEGER,
NAME INTEGER,
VALUE INTEGER,
ITEMS_NUM INTEGER,
)
And there were some data injected into this table. Now, I need to update the table to change the ID_NUM column as VARCHAR and add formatted UUID as default value.
I have followed the queries given below:
CREATE OR REPLACE FUNCTION RANDOM_UUID RETURN VARCHAR IS
V_UUID VARCHAR(255);
BEGIN
SELECT REGEXP_REPLACE(RAWTOHEX(SYS_GUID()), '([A-F0-9]{8})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{12})', '\1-\2-\3-\4-\5') INTO V_UUID FROM DUAL;
RETURN V_UUID;
END RANDOM_UUID;
ALTER TABLE TEST
DROP COLUMN ID_NUM;
ALTER TABLE TEST
ADD ID_NUM VARCHAR(255) DEFAULT random_uuid() NOT NULL;
It gives an error as SQL Error [4044] [42000]: ORA-04044: procedure, function, package, or type is not allowed here
I have executed and validated the function using following command and it gives a valid formatted UUID.
SELECT RANDOM_UUID() FROM DUAL;
What could be the issue in the ALTER table statement. Can't we use a function for setting default value in Oracle?
Thanks in advance.
I think you can achieve it using the default clause on the column but without function (just replace the function call with the content of the function in default clause) as following. (Please note that the User functions are not allowed in the default clause)
ALTER TABLE TEST
ADD ID_NUM VARCHAR(255)
DEFAULT REGEXP_REPLACE(RAWTOHEX(SYS_GUID()), '([A-F0-9]{8})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{12})', '\1-\2-\3-\4-\5')
NOT NULL;
I have prepared the db<>fiddle demo to show you the error with function and success without function.
Cheers!!
You cannot use PL/SQL functions in the default expression. But it can be a SQL function.Here's an extract from the 19c Doc:
Default column values are subject to the following restrictions:
A DEFAULT expression cannot contain references to PL/SQL functions or
to other columns, the pseudocolumns LEVEL, PRIOR, and ROWNUM, or date
constants that are not fully specified.
And here's an example using a sql function:
SQL> create table tc (c1 number default sqrt(2));
Table TC created.
The default value has to be an actual value, not a function.

Function results column names to be used in select statement

I have function which returns column names and i am trying to use the column name as part of my select statement, but my results are coming as column name instead of values
FUNCTION returning column name:
get_col_name(input1, input2)
Can И use this query to the results of the column from table -
SELECT GET_COL_NAME(input1,input2) FROM TABLE;
There are a few ways to run dynamic SQL directly inside a SQL statement. These techniques should be avoided since they are usually complicated, slow, and buggy. Before you do this try to find another way to solve the problem.
The below solution uses DBMS_XMLGEN.GETXML to produce XML from a dynamically created SQL statement, and then uses XML table processing to extract the value.
This is the simplest way to run dynamic SQL in SQL, and it only requires built-in packages. The main limitation is that the number and type of columns is still fixed. If you need a function that returns an unknown number of columns you'll need something more powerful, like the open source program Method4. But that level of dynamic code gets even more difficult and should only be used after careful consideration.
Sample schema
--drop table table1;
create table table1(a number, b number);
insert into table1 values(1, 2);
commit;
Function that returns column name
create or replace function get_col_name(input1 number, input2 number) return varchar2 is
begin
if input1 = 0 then
return 'a';
else
return 'b';
end if;
end;
/
Sample query and result
select dynamic_column
from
(
select xmltype(dbms_xmlgen.getxml('
select '||get_col_name(0,0)||' dynamic_column from table1'
)) xml_results
from dual
)
cross join
xmltable
(
'/ROWSET/ROW'
passing xml_results
columns dynamic_column varchar2(4000) path 'DYNAMIC_COLUMN'
);
DYNAMIC_COLUMN
--------------
1
If you change the inputs to the function the new value is 2 from column B. Use this SQL Fiddle to test the code.

Insert content of table variable into table

I have the following table, two types based on it, and a function that reads from this table:
CREATE TABLE myTable (
ID RAW(16) NULL,
NAME NVARCHAR2(200) NULL,
ENTITYID RAW(16) NOT NULL
);
CREATE TYPE myRowType AS OBJECT (
NAME NVARCHAR2(200),
ENTITYID RAW(16)
);
CREATE TYPE myTableType IS TABLE OF myRowType;
CREATE FUNCTION myFunction(...) RETURN myTableType ...
As you can see, the type myRowType is similar to myTable, but not exactly.
My goal is to insert rows into myTable based on the results of myFunction.
The naive approach would be to just write:
INSERT INTO myTable(ID, NAME, ENTITYID)
SELECT sys_guid(), NAME, ENTITYID
FROM TABLE(myFunction(...));
But since myFunction reads from myTable, this leads to the following error:
ORA-04091: table myTable is mutating, trigger/function may not see it
So I have to split the myFunction call from the insert statement. I tried it like this:
DECLARE
tbl myTableType;
BEGIN
SELECT myRowType(x.NAME, x.ENTITYID)
BULK COLLECT INTO tbl
FROM TABLE(myFunction(...)) x;
INSERT INTO myTable
(ID, NAME, ENTITYID)
SELECT sys_guid(), x.NAME, x.ENTITYID
FROM tbl x;
END;
But here, Oracle doesn't seem to understand the FROM tbl clause. It shows the error
ORA-00942: table or view does not exist
How can I insert the rows in tbl into myTable?
Since you can't use a locally defined nested table as an argument for TABLE function, maybe you would consider using the FORALL bulk insert? I see you are using Oracle 11g, so you will be able to access fields of myRowType. You would then replace your INSERT from your PL/SQL block with this:
FORALL v_i IN tbl.FIRST..tbl.LAST
INSERT INTO myTable VALUES (sys_guid(), tbl(v_i).name, tbl(v_i).entityid);
I recommend this great article by Tim Hall: BULK COLLECT & FORALL

Assign the output of a stored procedure to a Column

I'm executing a master stored procedure to load columns in to a target table.
I have a column called dptname - this column is handled by different project team so they have defined a child stored procedure all that will do is it will get an empno and output the Dptname. They requested us to call the below stored procedure to load my dptname column.
Could you please let me know how can I assign/call this child stored procedure and assign to the deptname column in my master stored procedure?
This is the skeleton of the child stored procedure:
get_dptname(in_emp_no, out_dptname)
My master stored procedure:
Create or Replace procedure InsertTargetTable
as
begin
for a in (
Select EMP.empno
EMP.NAME,
CL.Attendance,
DEPTNAME= "**ASSIGN THE VALUE FROM THE 3rd Party stored procedure**
from EMP, CL
on EMP.empno=CL.empno
) Loop
Insert Into Target Table ( empno, NAME,Attendance, DEPTNAME )
Values (a.empno, a.NAME, a.Attendance, a.DEPTNAME);
ENDLOOP;
COMMIT:
END
If the other group created a function GET_DEPT_NAME, then you could use it as follows:
CREATE OR REPLACE PROCEDURE InsertTargetTable
AS
BEGIN
INSERT INTO Target_Table ( empno, NAME, Attendance, DEPTNAME )
SELECT EMP.empno, EMP.NAME, CL.Attendance, GET_DEPT_NAME(EMP.empno)
FROM EMP, CL
WHERE EMP.empno = CL.empno;
COMMIT:
END;
A few notes:
The data is being de-normalizing: what if the employee changes departments? Your Target_Table won't be updated but will remain fixed at the department set during insert. Perhaps the department should be looked up when the table is actually queried in order to obtain the current department value.
Hopefully the stored proc is a function, then it can be used easily as shown in the example above. (If not, ask for a function).
Avoid looping if possible. A single "insert into ... select from" statement will be much more efficient.
You can use following query. Pass the DEPT_NO variable to stored procedure and since it is an OUT parameter you can access value from your master stored procedure.
GET_DPTNAME(IN_EMP_NO=>EMP_NO,OUT_DEPT_NO=>DEPT_NO);

PL/SQL procedure - too many values

I'm sure this is something simple, but I'm really new to PL/SQL and this has me stuck.
I've written a simple stored procedure to return a few values about a customer. Right off the bat, the %rowtype's are not coming up as reserved keywords but the compiler isn't flagging those as errors.
It is, however, ignoring the entire SQL statement flagging the line FROM demo_customers as too many values. Even if I try reducing it to only select one column it still gives me the same error.
create or replace
PROCEDURE GETCUSTOMER
(
arg_customerID demo_customers.customer_id%type,
returnRec OUT demo_customers%rowtype
)
AS
BEGIN
SELECT customer_id, cust_first_name, cust_last_name, cust_email
INTO returnRec
FROM demo_customers
WHERE customer_id = arg_customerID ;
END GETCUSTOMER;
If you want to select into a %ROWTYPE record, you'll want to do a SELECT * rather than selecting individual columns
create or replace
PROCEDURE GETCUSTOMER
(
arg_customerID demo_customers.customer_id%type,
returnRec OUT demo_customers%rowtype
)
AS
BEGIN
SELECT *
INTO returnRec
FROM demo_customers
WHERE customer_id = arg_customerID ;
END GETCUSTOMER;
If you select 4 columns explicitly, Oracle expects you to have 4 variables to select those values into.

Resources