I would like to action some data checks following data imports into my system, im checking that all of my key locations have inventory imported for them and if they dont i would like the job to fail (I then have reporting/alerts set up when any jobs fail)
Ive had a search around and tried a number of options - The lines commented out are what i have tried but when i set INV_CHECK variable above the count level of one of my locations the job still completed succesfully. If i run in TOAD then it will fail and present an error which is what i had wanted the job to do.
Declare valid_loc NUMBER;
Inv_check NUMBER;
no_inv number;
BEGIN
select param_value into Inv_check from
scpomgr.udt_systemparam where param_name = 'INV_CHECK';
select count (*) into valid_loc from
(select distinct loc
from scpomgr.inventory
where loc in ('GB01', 'FR01', 'DE01', 'IT01', 'ES01', 'IE01', 'CN01', 'JP01', 'AU01', 'US01')
having count (*) > Inv_check
group by loc);
if valid_loc
<10 THEN
--raise_application_error(-20001,'Likely Missing Inv Records');
--raiseerror('fail',16,1);
--select 1/0 into no_inv from dual;
--THROW (51000, 'Process Is Not Finished', 1);
END IF;
END;
EXIT
Can anyone point me in the right direction of what ive missed / misunderstood?
Ive added an action into the If statement so i know its running the part after the 'Then' and if i run in TOAD it gives me an error, if i do it via 'PUTTY' which is what i use to run batch processes then it comes out as 'COMPLETE' and doesnt show any sort of failure.
So after a number of trial and error i found the below code gives me the desired result, to cause my process table / putty runs to display failed i needed to use pkg_job.fatel_error and with that i could pass an error message/code.
Declare
valid_loc NUMBER;
Inv_check NUMBER;
BEGIN
select param_value into Inv_check from
scpomgr.udt_systemparam where param_name = 'INV_CHECK';
select count (*) into valid_loc from
(select distinct loc
from scpomgr.inventory
where loc in ('GB01', 'FR01', 'DE01', 'IT01', 'ES01', 'IE01', 'CN01', 'JP01', 'AU01', 'US01')
group by loc
having count (*) > Inv_check
);
if valid_loc < 10 THEN
pkg_job.fatal_error('Likely Missing Inv Records',-20001);
END IF;
END;
/
EXIT
Hope this helps others or gives ideas of what to try.
Related
I have this anonymous PL/SQL block which calculates and prints a value return from a table.
DECLARE
U_ID NUMBER :=39;
RETAIL BINARY_FLOAT:=1;
FLAG NUMBER;
BEGIN
SELECT NVL(RETAIL_AMOUNT,1),UNIT_ID INTO RETAIL, FLAG FROM UNITS WHERE UNIT_ID=U_ID;
LOOP
SELECT NVL(MAX(UNIT_ID),U_ID) INTO FLAG FROM UNITS WHERE FATHER_ID=FLAG;
IF FLAG=U_ID THEN EXIT; END IF;
SELECT RETAIL* RETAIL_AMOUNT INTO RETAIL FROM UNITS WHERE UNIT_ID=FLAG;
EXIT WHEN FLAG=U_ID;
END LOOP;
DBMS_OUTPUT.PUT_LINE( RETAIL);
END;
This block work correctly, but I wanted to do the same thing using a PL/SQL Function
I wrote the function as follow:
CREATE OR REPLACE FUNCTION GET_UNIT_RETAIL(U_ID NUMBER)
RETURN NUMBER
IS
RETAIL BINARY_FLOAT:=1;
FLAG NUMBER;
BEGIN
SELECT NVL(RETAIL_AMOUNT,1),UNIT_ID
INTO RETAIL, FLAG
FROM UNITS
WHERE UNIT_ID=U_ID;
LOOP
SELECT NVL(MAX(UNIT_ID),U_ID)
INTO FLAG
FROM UNITS
WHERE FATHER_ID=FLAG;
IF FLAG=U_ID THEN
EXIT;
END IF;
SELECT RETAIL* RETAIL_AMOUNT
INTO RETAIL
FROM UNITS
WHERE UNIT_ID=FLAG;
EXIT WHEN FLAG=U_ID;
END LOOP;
RETURN NUMBER;
END;
/
When I try to execute the above code to save the function to the database, the environment (SQL*PLUS) hangs for a long time and at the end returns this error:
ERROR at line 1:
ORA-04021: timeout occurred while waiting to lock object
What is the problem ??? Please !
Sounds like ddl_lock problem
Take a look at
dba_ddl_locks to see who is "blocking" a create or replace.
Also try to create under different name - and see what happens.
The problem was because the Object GET_UNIT_RETAIL was busy by other environment
Here is the answer:
https://community.oracle.com/thread/2321256
I am executing a query in PL / SQL in version 7 and version 14, with a function created by me, and both bring me some results, the rest bring 0.
However, when executing the same query in Oracle SQL Developer, the query brings all the results correctly.
I executed the procedure through PL / SQL and Oracle SQL Developer as well, but then none brought me the right result, all the lines were left as "0".
I can't find the problem at all, even on Google.
Basically, the function multiplies the number of rows by columns that start with "ID_", as shown below.
Function:
CREATE OR REPLACE FUNCTION DS_FUNCESP.FNBIGB_CheckDataCells
(pOwn IN VARCHAR2,
pTab IN VARCHAR2)
RETURN NUMBER
IS
v_Qtd NUMBER;
v_str VARCHAR2(2000);
BEGIN
v_Qtd := 1;
v_str := ' SELECT
SUM((SELECT COUNT(1) AS QTY_ROWS FROM ' || pOwn || '.' || pTab || ' d WHERE d.LINORIGEM <> ''CARGA MANUAL'')) AS QTY_DATA
FROM DW_FUNCESP.D_BI_COLUMNS a
LEFT JOIN
DW_FUNCESP.D_BI_TABLES b
ON a.ID_TABLE = b.ID_TABLE
AND a.ID_OWNER = b.ID_OWNER
LEFT JOIN DW_FUNCESP.D_BI_OWNERS c
ON a.ID_OWNER = c.ID_OWNER
WHERE b.NM_TABLE = ''' || pTab || '''
AND a.IN_PRIMARYKEY = ''NAO''
AND SUBSTR(a.NM_COLUMN,1,3) = ''ID_'' ';
DBMS_OUTPUT.put_line(v_str);
EXECUTE IMMEDIATE v_str into v_Qtd ;
return (v_Qtd);
EXCEPTION WHEN OTHERS THEN
RETURN 0;
END FNBIGB_CheckDataCells;
Select statement:
SELECT
c.NM_OWNER ,
b.NM_TABLE ,
DS_FUNCESP.FNBIGB_CHECKDATACELLS(c.NM_OWNER, b.NM_TABLE) AS QTY_DATA
FROM DW_FUNCESP.D_BI_TABLES b
LEFT JOIN DW_FUNCESP.D_BI_OWNERS c
ON b.ID_OWNER = c.ID_OWNER;
Results from PL/SQL:
Results from Oracle SQL Developer:
Clearly we can see the difference from any row, the right one is the Oracle SQL Developer. So I'd like to know what is the problem, how to fix, because the procedure is adding "0" to all the rows, no matter where I run.
Reading those examples from WHEN OTHERS - A Bug, thanks to #Lalit Kumar B for that, I changed:
EXCEPTION WHEN OTHERS THEN
RETURN 0;
To:
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLCODE: '||SQLCODE);
DBMS_OUTPUT.PUT_LINE('Message: '||SQLERRM);
RAISE;
To find out the problem, and thanks for that I found that it was trying to count from a table where it doesn't exist anymore.
So I using an error handling as below, from #Jeffrey Kemp
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
Also, thanks for #Belayer, my code was the problem, agreed on that. Also, executing on both softwares, made me even more confused. I'll read also that documentation for sure.
I am trying to create a script that will allow the user to select which CASE population to use from an ACCEPT when gathering student contact info.
PROMPT 'Select a popluation for emails'
PROMPT '1. Currently registered'
PROMPT '2. New Applicants'
PROMPT
ACCEPT cnt number PROMPT 'Selection: ';
...
CURSOR stu_lst IS
CASE &cnt
WHEN 1 THEN -- Current registered students.
select distinct SFRSTCA_PIDM pidm
from SFRSTCA
where SFRSTCA_TERM_CODE = '201403' and
SFRSTCA_LEVL_CODE = '01' and
SFRSTCA_RSTS_CODE = 'RE';
WHEN 2 THEN -- New applicants
select app_pidm pidm
from app
where app_term = 'Fall 2014';
ELSE
-- Incorrect selection.
DBMS_OUTPUT.PUT_LINE('Incorrect selection made.');
exit;
END;
END;
Assuming the two queries return the same data type, you could use a union with a filter that checks the variable in each part; something like:
DECLARE
CURSOR stu_lst IS
-- Current registered students.
select distinct SFRSTCA_PIDM pidm
from SFRSTCA
where &cnt = 1 and
SFRSTCA_TERM_CODE = '201403' and
SFRSTCA_LEVL_CODE = '01' and
SFRSTCA_RSTS_CODE = 'RE';
UNION ALL
-- New applicants
select app_pidm
from app
where &cnt = 2 and
app_term = 'Fall 2014';
invalid_argument EXCEPTION;
...
BEGIN
IF &cnt NOT IN (1, 2) THEN
RAISE invalid_argument;
END IF
FOR rec IN stu_lst LOOP
h_pidm := rec.pidm;
...
END LOOP;
EXCEPTION
WHEN invalid_argument THEN
dbms_output.put_line('Incorrect selection made.');
END;
/
You could also declare a cursor variable and open that with the appropriate query, inside a case statement within the main body of the block. This sticks with your explicit cursor syntax though.
I've been tweaking and trying to debug this PL/SQL code for like 4 hours now. I have also tried to search on here but it is so specific that I really need help. Here is my code, When I try to run it, the two prompt questions pop up. After I answer the second one, oracle just stops running.
---- File PLh20.sql
-- Author: <<< NAME >>>
-------------------------------------------------------------------
SET SERVEROUTPUT ON
SET VERIFY OFF
------------------------------------
ACCEPT rateDecrement NUMBER PROMPT 'Enter the rate decrement: '
ACCEPT allowedMinRate NUMBER PROMPT 'Enter the allowed min. rate: '
DECLARE
sr boats%ROWTYPE;
CURSOR sCursor IS
SELECT B.bid, B.bname, B.color, B.rate, B.length, B.logKeeper
FROM Boats B
WHERE B.bid NOT IN (SELECT bid FROM Reservations);
BEGIN
OPEN sCursor;
LOOP
-- Fetch the qualifying rows one by one
FETCH sCursor INTO sr;
EXIT WHEN sCursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE ('+++++ old rate: '||sr.rate||' '
||sr.rate||);
sr.rate := sr.rate - &rateDecrement;
-- A nested block
DECLARE
belowAllowedMin EXCEPTION;
BEGIN
IF sr.rate < &allowedMinRate
THEN RAISE belowAllowedMin;
ELSE UPDATE Boats
SET rate = sr.rate
WHERE Boats.bid = sr.bid;
-- Print the boat new record
DBMS_OUTPUT.PUT_LINE ('+++++ new row: '||sr.bid||' '
||sr.rate||);
END IF;
EXCEPTION
WHEN belowAllowedMin THEN
DBMS_OUTPUT.PUT_LINE('+++++ Update rejected: '||
'The new rate would have been: '|| sr.rate);
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('+++++ update rejected: ' ||
SQLCODE||'...'||SQLERRM);
END;
-- end of the nested block
END LOOP;
COMMIT;
CLOSE sCursor;
END;
SELECT S.sid, S.rating
FROM sailors S, reservations R, boats B
WHERE S.sid = R.sid AND
R.bid = B.bid;
UNDEFINE rateDecrement
UNDEFINE allowedMinRate
DBMS_OUTPUT.PUT_LINE ('+++++ new row: '||sr.bid||' '||sr.rate||);
DBMS_OUTPUT.PUT_LINE ('+++++ old rate: '||sr.rate||' '||sr.rate||);
Looks like these 2 are the problem. There should not be '||' at the end.
i've created an procedure which increases salaries of peoples working in a department by a certain rate. the department number and the rate are assed as parameters for the procedure.
Now, the procedure works great when i specify the good departement number, but once i specify a false one, and i'm waiting for the NO_DATA_FOUND Exception to raise, it never happen. I searched tried many thing but didn't found the answer, so if you can help me i woul be really greatfull. Thank you !
Here is my code :
create or replace PROCEDURE AugmenteSalaire(numDepartement in departements.numerodepartement%TYPE, taux IN number) IS
p_nbreTotalSalaire employes.salaireemploye%type;
begin
SELECT sum(salaireemploye)
INTO p_nbreTotalSalaire
FROM employes
WHERE numerodepartement = numDepartement;
if taux > 0 AND taux <= 100 THEN
if p_nbreTotalSalaire < 150000 THEN
Update employes e
SET e.salaireemploye = e.salaireemploye + (e.salaireemploye * (taux * 0.01))
WHERE e.numerodepartement = numDepartement
AND NOT numeroemploye = (SELECT departements.chefdepartement from departements
WHERE departements.numerodepartement = numDepartement);
ELSE
DBMS_OUTPUT.PUT_LINE('Transaction refused : The salary sum cannot be above 150000');
END IF;
ELSE
DBMS_OUTPUT.PUT_LINE('The rate cannot be under 0 or aboce 100');
END IF;
Exception
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('The department number provided is invalid, '||
'please enter a valid department number(DEP001 for example)');
end;
SELECT sum(salaireemploye)
INTO p_nbreTotalSalaire
FROM employes
WHERE numerodepartement = numDepartement;
In this query you are using SUM(). Now if there is no matching department, i.e. input "numDepartement" is a false department, sum(salaireemploye) is 0 (no such department, so nothing to add, so 0).
sum(salaireemploye) thus has a valid value, which is 0 here. Hence this will never raise a NO_DATA_FOUND exception