Using variable from cursor for loop in where clause - sql

I was doing some SQL on Oracle and I found something weird.
I have that FOR loop that iterate over a list of date (Stored as VARCHAR2):
FOR current_date in (SELECT DISTINCT DATCRE as datcre
FROM EVE cdv
WHERE cdv.datcre BETWEEN p_datedeb AND p_datefin)
LOOP
[queries]
END LOOP;
I need to use current_date in the where clause of the following query:
SELECT COUNT(cdv.numeve)
INTO nb
FROM EVE cdv
WHERE cdv.datcre = current_date.datcre;
This query doesn't work, and I get a ORA-00933: SQL command not properly ended.
Now, if I declare a curDate VARCHAR2(10) variable, store current_date.datcre in it and use it in the query, it works fine:
curDate := (current_date.datcre);
SELECT COUNT(cdv.numeve)
INTO nb
FROM EVE cdv
WHERE cdv.datcre = curDate;
Am I missing something or is this just the way Oracle works ?

Related

SQL Is it possible to incorporate a SELECT with a REPLACE?

I'm using MS SQL Server 2019
I have a string in a table (tblJobCosts) that has its own ID like this:
TextID jobText
1 Total Cost for job is £[]. This includes VAT
How do I update the value stored in the brackets based on the value from another table?
The end result would look like this:
Total Cost for job is £500. This includes VAT
I thought I could incorporate a SELECT with a REPLACE but this does not seem possible:
DECLARE #JobNum INT = 123;
UPDATE dbo.JobCosts
SET jobText = REPLACE (jobText,'[]',
SELECT JH.jobCost
FROM dbo.JobHead AS JH
WHERE (JH.JobNo = #JobNum)
) AND TextID = 1
If I run the above I receive the error:
Incorrect syntax near the keyword 'SELECT'.
Is it possible to incorporate a SELECT with a REPLACE?
I think that you cannot call a select statement in the replace function.
I would try something like that:
UPDATE dbo.JobCosts
SET jobText = REPLACE (jobText,'[]',k.the_cost) from
( SELECT JH.jobCost as the_cost
FROM dbo.JobHead AS JH
WHERE (JH.JobNo = #JobNum)
)k
where TextID = 1

Cause a job failure with sql for data checks

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.

Creating a Procedure in Oracle to create View

I am trying to create a procedure in oracle, which upon calling from PL SQL block will create a view in database from which i will query data for a report. I am new to Oracle and need help with this code.
CREATE OR REPLACE PROCEDURE CREATE_VIEW
(
TO_DT IN Date
) AS
BEGIN
Create or Replace view BORR_DUR As
SELECT e."Deal_No", (Select "DeskName" From MM_S_DESK Where e."DeskCode" = MM_S_DESK."DeskCode") Facility, e."Remarks" Counterparty,
m."MaturityDate", m."PriRedem" Principal,
(select MAX("INTEREST_RATE") from MM_BOR_PLA_PAR d
WHERE e."Deal_No" = d."DEAL_NO" and "INTERESTINPUTDATE" <= to_dt)/100 yield, (m."MaturityDate" - To_date(to_dt,'dd/mm/yyyy')) Days_to_Mat,
Round(((m."MaturityDate" - To_date(to_dt,'dd/mm/yyyy'))/365)/ (1+((select MAX("INTEREST_RATE") from MM_BOR_PLA_PAR d
WHERE e."Deal_No" = d."DEAL_NO" and "INTERESTINPUTDATE" <= to_dt)/100)),4) MDURATION
FROM MM_T_BORROWING e, MM_T_BORROWING_PM_DETAIL m
Where e."DeskCode" in ('10','11','12','13') and e."Value_Date" <= to_dt and e."Maturity_Date" > to_dt and e."Status" not in ('C', 'D', 'Z', '0','X')
and e."Deal_No" = m."Deal_No" and "PriRedem" > '0' and m."MaturityDate" > to_dt;
END CREATE_VIEW;
On Compilation, i get PLS00103 error which says
encountered the symbol "Create" when expecting one of the
following....
Any help in solving this issue will be greatly appreciated.
When you want execute SQL statement which is dynamic you have to use EXECUTE IMMEDIATE statement
First , you don't need double quotes in fields name , after that you can try the query of the view and check if it runs without errors .
Put the create replace view... statement in an variable and in your procedure call :
BEGIN
EXECUTE IMMEDIATE view_string_variable ;
END;
/

How to call Oracle MD5 hash function?

I have below code. I am using Oracle 11g.
SELECT DBMS_OBFUSCATION_TOOLKIT.md5 (input => UTL_RAW.cast_to_raw(
FIRST_NAME
||LAST_NAME
)) md5_key ,
FIRST_NAME ,
LAST_NAME
FROM C_NAME_TAB
WHERE PKEY='1234'
How can i call this code? Can i directly execute this code in sqldeveloper?
In Oracle 12c you can use the function STANDARD_HASH. It does not require any additional privileges.
select standard_hash('foo', 'MD5') from dual;
The dbms_obfuscation_toolkit is deprecated (see Note here). You can use DBMS_CRYPTO directly:
select rawtohex(
DBMS_CRYPTO.Hash (
UTL_I18N.STRING_TO_RAW ('foo', 'AL32UTF8'),
2)
) from dual;
Output:
ACBD18DB4CC2F85CEDEF654FCCC4A4D8
Add a lower function call if needed. More on DBMS_CRYPTO.
I would do:
select DBMS_CRYPTO.HASH(rawtohex('foo') ,2) from dual;
output:
DBMS_CRYPTO.HASH(RAWTOHEX('FOO'),2)
--------------------------------------------------------------------------------
ACBD18DB4CC2F85CEDEF654FCCC4A4D8
#user755806 I do not believe that your question was answered. I took your code but used the 'foo' example string, added a lower function and also found the length of the hash returned. In sqlplus or Oracle's sql developer Java database client you can use this to call the md5sum of a value. The column formats clean up the presentation.
column hash_key format a34;
column hash_key_len format 999999;
select dbms_obfuscation_toolkit.md5(
input => UTL_RAW.cast_to_raw('foo')) as hash_key,
length(dbms_obfuscation_toolkit.md5(
input => UTL_RAW.cast_to_raw('foo'))) as hash_key_len
from dual;
The result set
HASH_KEY HASH_KEY_LEN
---------------------------------- ------------
acbd18db4cc2f85cedef654fccc4a4d8 32
is the same value that is returned from a Linux md5sum command.
echo -n foo | md5sum
acbd18db4cc2f85cedef654fccc4a4d8 -
Yes you can call or execute the sql statement directly in sqlplus or sql developer. I tested the sql statement in both clients against 11g.
You can use any C, C#, Java or other programming language that can send a statement to the database. It is the database on the other end of the call that needs to be able to understand the sql statement. In the case of 11 g, the code will work.
#tbone provides an excellent warning about the deprecation of the dbms_obfuscation_toolkit. However, that does not mean your code is unusable in 12c. It will work but you will want to eventually switch to dbms_crypto package. dbms_crypto is not available in my version of 11g.
To calculate MD5 hash of CLOB content field with my desired encoding without implicitly recoding content to AL32UTF8, I've used this code:
create or replace function clob2blob(AClob CLOB) return BLOB is
Result BLOB;
o1 integer;
o2 integer;
c integer;
w integer;
begin
o1 := 1;
o2 := 1;
c := 0;
w := 0;
DBMS_LOB.CreateTemporary(Result, true);
DBMS_LOB.ConvertToBlob(Result, AClob, length(AClob), o1, o2, 0, c, w);
return(Result);
end clob2blob;
/
update my_table t set t.hash = (rawtohex(DBMS_CRYPTO.Hash(clob2blob(t.content),2)));

Oracle - Comparing dates

I have this Oracle procedure:
CREATE OR REPLACE PROCEDURE xmas
IS
CURSOR curUser IS SELECT userID, coins FROM Users;
thisUser curUser%ROWTYPE;
d VARCHAR(7);
CURSOR curDate IS SELECT TO_CHAR(sysdate, 'DD-MON') FROM DUAL;
BEGIN
OPEN curDate;
FETCH curDate INTO d;
CLOSE curDate;
IF ((TO_DATE(d)) = (TO_DATE('25-DEC'))) THEN
OPEN curUser;
LOOP
FETCH curUser INTO thisUser;
EXIT WHEN (curUser%NOTFOUND);
thisUser.coins := thisUser.coins + 5.00;
UPDATE Users SET coins = thisUser.coins WHERE userID = thisUser.userID;
END LOOP;
CLOSE curUser;
END IF;
END xmas;
and when I call it, I get this error:
ORA-01840: input value not long enough for date format.
Tried different comparison methods for hours and nothing else has worked.
What's the problem??
You need to specify a date format for Oracle to know what actually '25-DEC' means.
select TO_DATE('25-DEC', 'DD-MON') from dual;
The problem should be on this line:
IF ((TO_DATE(d)) = (TO_DATE('25-DEC'))) THEN
As a note, it seems to me that you are also making a lot of unnecessary conversions. I don't know if this is an educational attempt, but why not just run the update below:
update USERS
set
coins = coins + 5
where
to_char(sysdate, 'DD-MON') = '25-DEC';