I have a Procedure like this,
create or replace
PROCEDURE SP_PROOF
( proof_id IN NUMBER
, Type1 IN VARCHAR2
, StatementType IN NUMBER
, Resultset OUT NUMBER
) AS
BEGIN
IF StatementType = 1 Then
INSERT INTO ID_Proof (proofid,Id_type)
VALUES (proof_id, Type1);
ELSIF StatementType=2 THEN
SELECT proofid,Id_type Into Resultset FROM ID_Proof;
ELSIF StatementType=3 THEN
UPDATE ID_Proof SET Id_type = Type1 WHERE proofid = proof_id;
ELSIF StatementType=4 THEN
DELETE FROM ID_Proof WHERE proofid = proof_id;
end if;
end;
Im getting an error like this,
Error(14,1): PL/SQL: SQL Statement ignored
Error(14,64): PL/SQL: ORA-00947: not enough values
Please help me to correct the error.
Line 14 is:
SELECT proofid,Id_type Into Resultset FROM ID_Proof;
You are selecting two values, proofid and Id_type, into a single scalar variable Resultset. But you also have no filter, so even if you changed that to select a single value then you'd get a too-many-rows error if there was more than one row in the table (and no-data-found if the table is empty).
It isn't clear what you want to happen; perhaps you want select id_type into resultset from id_proof, but from the parameters id_type is a string - so selecting that into a number variable is likely to fail too. Or perhaps you want all IDs for the specified type, in which case the type of result set would need to be a table type or a ref cursor.
Having separate procedures and functions would be probably be clearer, too.
Related
I am trying to write a MariaDB stored procedure.
Due to SQL_SAFE_UPDATES, it is required to use the ID column to use in the WHERE clause for updates. Due to this, what is the normal approach to also select a value from one of the other columns? I do not want to have multiple SELECT statements as it seems inefficient and room for error because they could return values from different rows.
I would like to store my first select statement
SELECT id, sequence FROM RECORDSEQUENCE WHERE SEQTABLE = SeqTable;
In the following two parameters #id, #seq from two seperate columns in the above query and use them in the UPDATE statement as well as the IF statement.
CREATE DEFINER=`sd`#`%` PROCEDURE `SD_GenerateNextRecordSequence`(IN SeqTable int)
BEGIN
SELECT id, sequence FROM RECORDSEQUENCE WHERE SEQTABLE = SeqTable;
IF (#seq IS NOT NULL) THEN
SET #NEXTSEQ := #seq+1;
UPDATE RECORDSEQUENCE SET RECORDSEQUENCE = #NEXTSEQ WHERE id = #id;
ELSE
SET #NEXTSEQ := 100;
INSERT INTO RECORDSEQUENCE (RECORDSEQUENCE,SEQTABLE) VALUES (#NEXTSEQ,SeqTable);
END IF;
SELECT #NEXTSEQ as SEQUENCE;
END
I would like to know if there's any option to iterate a table while performing SELECT values into a CURSOR.
For example:
I have a table TEMP_NUMBERS which contains only numbers (single column).
I have to perform a SELECT from each number in the table (I do not know the amount of rows in the table in advance).
Here is basically what I'm attempting to do. Obviously this does not work, but can I do some kind of a workaround?
I need to SELECT the data into the p_cv_PermsNotifs which is a RETURN REF CURSOR.
IF NOT p_cv_PermsNotifs%ISOPEN THEN OPEN p_cv_PermsNotifs FOR
FOR i IN 1..TEMP_NUMBERS.NUMBER.COUNT LOOP
SELECT DISTINCT
SEC_USER_ROLE.ENTITY_TYP_CODE,
SEC_USER_ROLE.ENTITY_ID
FROM
SEC_USER_ROLE
WHERE
SEC_USER_ROLE.ENTITY_ID = i
END LOOP;
END IF;
Also tried this:
IF NOT p_cv_PermsNotifs%ISOPEN THEN OPEN p_cv_PermsNotifs FOR
SELECT DISTINCT
SEC_USER_ROLE.ENTITY_TYP_CODE,
SEC_USER_ROLE.ENTITY_ID
FROM
SEC_USER_ROLE
WHERE
SEC_USER_ROLE.ENTITY_ID IN
(SELECT * FROM TABLE (lv_ListOfEntities))
END IF;
Where lv_ListOfEntities is table of NUMBER indexed by BINARY INTEGER.
But I'm getting "ORA-22905: cannot access rows from a non-nested table item"
Thanks in advance.
In> Hey if you pass a single number at a time, everytime the refcursor
will be overwritten by the next value. So at the end you will only get
the value for last number in the refcursor. A better way is to use
some basic PL/SQL Bulk COLLECT logic which will give you the desired
output.
Hope this helps
--Creating sql type
CREATE OR REPLACE TYPE lv_num_tab IS TABLE OF NUMBER;
--plsql block
var p_lst refcursor;
DECLARE
lv_num lv_num_tab;
BEGIN
SELECT COL1 BULK COLLECT INTO lv_num FROM TEMP_NUMBERS;
OPEN p_lst FOR
SELECT DISTINCT SEC_USER_ROLE.ENTITY_TYP_CODE,
SEC_USER_ROLE.ENTITY_ID
FROM SEC_USER_ROLE
WHERE SEC_USER_ROLE.ENTITY_ID IN
(SELECT * FROM TABLE(cast(lv_num as lv_num_tab))
);
END;
I need to write a procedure with input parameters like groupid and item ids(array)
I need to insert into a table with values(groupid,itemid[0]) all items like (1,11),(1,12),(1,13),etc. I have table with two columns (groupid,itemid). please help me to sort out this problem. I am trying to write merge but getting error
CREATE OR REPLACE PROCEDURE update_product_group_prc
(
in_product_group_key IN INT,
in_product_key_array IN dbms_utility.maxname_array
)
AS
indx pls_integer := in_product_key_array.FIRST;
BEGIN
WHILE(INDX IS NOT NULL)
LOOP
MERGE INTO DIM_PRODUCT_X_GROUP PXG
USING(SELECT IN_PRODUCT_GROUP_KEY ,
IN_PRODUCT_KEY_ARRAY(INDX) IN_PRODUCT_KEY_ARRAY
FROM DUAL) IN_TBL
ON(IN_TBL.IN_PRODUCT_GROUP_KEY=PXG.PRODUCT_GROUP_KEY)
WHEN MATCHED THEN
-- DELETE --need to delete source records which r not here in array.
-- WHERE
WHEN NOT MATCHED THEN
INSERT (PRODUCT_GROUP_KEY,PRODUCT_KEY)
VALUES (IN_TBL.IN_PRODUCT_GROUP_KEY,IN_TBL.IN_PRODUCT_KEY_ARRAY);`
INDX := IN_PRODUCT_KEY_ARRAY.NEXT(INDX);
END LOOP;
END update_product_group_prc;
Error(16,41): PL/SQL: ORA-00936: missing expression
You have a syntax error. Comment the "WHEN MATCHED THEN" fragment.
http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016.htm#SQLRF55028
DECLARE
v_name A.TRANSACTION_TYPE%TYPE :='SALARY';
v_salary A.SALARY%TYPE := 1000;
BEGIN
update A set v_name= v_salary where EMPID = 517;
-- PL/SQL: ORA-00904: "v_name": invalid identifier
--update A set SALARY = 1000 where EMPID = 517;
END;
/
My idea is to update table columns , but these column names are stored in variable. Is there any way to pass column names from variable ? Is there any options apart from Execute Immediate
Not sure if this will work in your situation, but I've written solutions where I wrote a script in SQLPlus and it "wrote" (using dbms_output.put_line or even just prompt) another script that did queries, and the columns/tables in those queries was determined by the logic in the SQLPlus script. Then I would execute as a script the output from my first script, and it would execute dynamically generated queries without ever needing execute immediate.
The following idea may work for multiple columns that are typed the same... As written, it will update all columns every time for a given record, but only the column specified by v_name will be changed to the value set in v_value; the other columns are simply updated to their existing value. The idea can be played with using DECODE, NVL or other similar conditional operators.
declare
v_name varchar2(20):= 'SAL';
v_value emptest.sal%TYPE := 5000;
begin
update emptest
set sal = ( select case when v_name = 'SAL' then v_value else sal end from dual),
comm = ( select case when v_name = 'COMM' then v_value else comm end from dual)
where empno = 7369;
commit;
end;
I am doing an school assigment where I need to get the last value of "code" so I can then insert next row with this code incremented. I tried to pull it out this way.
DECLARE
v_last_code f_shifts.code%TYPE;
BEGIN
SELECT LAST_VALUE(code) OVER (ORDER BY code)
INTO v_last_code
FROM f_shifts;
DBMS_OUTPUT.PUT_LINE('Last value is: ' || v_last_code);
END;
However I get ORA-01422: exact fetch returns more than one requested number of rows
and I have no idea why and how can a last_value be more than one row
Thanks !
You can use a nested table like this.
DECLARE
v_last_code f_shifts.code%TYPE;
TYPE t_tbl IS TABLE OF f_shifts.code%TYPE;
-- Above line creates the nested table type of the required type.
v_tbl T_TBL;
-- Above line creates the nested table variable.
BEGIN
SELECT code
BULK COLLECT INTO v_tbl -- collects all the values, ordered, into the nested table
FROM f_shifts
ORDER BY code;
v_last_code = v_tbl(v_tbl.LAST); -- gets the last values and puts into the variable
DBMS_OUTPUT.PUT_LINE('Last value is: ' || v_last_code);
END;
/