create or replace PROCEDURE Show_R(A IN VARCHAR2, B OUT VARCHAR2)
IS
BEGIN
select func_w(day),TO_CHAR(hour, 'HH24:MI')INTO B
from task t
inner join mat m
on t.id_p = m.id_a
where m.cod_mod = A;
END;
I have a issue with this code, this select gets two types of columns data that are not the same type of data, i don't know how to add into B two types of data in only one "out parameter"
You can't put 2 values into 1 OUT parameter. So, use 2 OUT parameters.
Firstly don't store day and hour in separate columns. Just use a single DATE column as, in Oracle, the DATE data type has year, month, day, hour, minute and second components and so can store both the date and time.
Secondly, don't use A, B, show_R or func_w identifiers; use meaningful names as it will be far easier to debug your code in 6-months if you can tell what it is intended to do.
Third, your SELECT ... INTO statement will fail as you have two columns but only one variable to select into; you need 2 variables in INTO clause and this means (unless you are going to concatenate the two values) that you need 2 OUT parameters.
CREATE PROCEDURE Show_w_day_and_hour(
i_cod_mod IN mat.cod_mod%TYPE,
o_w_day OUT VARCHAR2,
o_hour OUT VARCHAR2
)
IS
BEGIN
SELECT func_w(day),
TO_CHAR(hour, 'HH24:MI')
INTO o_w_day,
o_hour
FROM task t
INNER JOIN mat m
ON ( t.id_p = m.id_a )
WHERE m.cod_mod = i_cod_mod;
END;
/
db<>fiddle
Related
Good evening,
I have a SP and I want to compare 2 dates from different tables, but in the form 'dd/mm/yyyy hh:mi:ss'
I am using to_char(date01,'dd/mm/yyyy hh:mi:ss')> to_char(date02,'dd/mm/yyyy hh:mi:ss')
but it throws me errors.
For example: if the date is 02/12/2016 07:40:12>02/02/2022 06:40:46
it indicates that it is true, and it is not, it is considering the day and not the entire date.
when I only use date01>date02, I have the problem you consider for example.
'02/15/2022 07:48:50'='02/15/2022 07:50:22' (only considers the date)
How can I compare date, minutes and seconds regardless of the server configuration.
Thank you,
PROCEDURE SPU_CUENTA
(
p_nro in varchar2,
pr_Ret OUT number
) is
vfecha varchar(100);
vcount int;
begin
select COUNT(DFEC_SISTEMA) into vcount from TAB Where c=1;
IF vcount>0 THEN
select to_char(DFEC_SISTEMA,'dd/mm/yyyy hh:mi:ss') into vfecha from TAB Where c=1;
EXECUTE IMMEDIATE 'SELECT COUNT(DFEC_ANULA) FROM tablab WHERE to_char(DFEC_ANULA,'dd/mm/yyyy hh:mi:ss')>'''||vfecha||'''' into pr_Ret;
END IF;
end;
Code you suggest would make sense if columns involved were VARCHAR2 (which is a bad idea; store dates into DATE datatype columns).
If those columns really are DATEs, then part of your question (which suggests format) is meaningless - we compare dates as they are, simply by e.g. date1 > date2. Converting them to characters - in a format you specified - is plain wrong.
If those columns are strings, then you'll have to convert them TO_DATE, not TO_CHAR
Procedure you wrote should be a function; they are designed to return a value. Yes, you can use a procedure, but - why would you? You can't use it in SQL (only in PL/SQL).
Besides, code can be heavily shortened/optimized, as you need just one select statement. You don't have to first check whether there any rows in tab that satisfy the condition, and then select some other info - use a subquery instead.
Finally, why are you using dynamic SQL? There's nothing dynamic in your code.
I'd suggest something like this, see if it makes sense.
FUNCTION spu_cuenta (p_nro IN VARCHAR2)
RETURN NUMBER
IS
pr_ret NUMBER;
BEGIN
SELECT COUNT (dfec_anula)
INTO pr_ret
FROM tablab
WHERE dfec_anula > (SELECT dfec_sistema
FROM tab
WHERE c = 1);
RETURN pr_ret;
END;
I have task where I need to change passwords for current EBS 189 schemas (Oracle 12.1). I have created query how to manage this in one go:
select 'FNDCPASS APPS/atesta 0 Y SYSTEM/test ORACLE '||oracle_username||' '||password||'' oracle_username from FND_ORACLE_USERID
where READ_ONLY_FLAG='A'
So my question is how to replace password word in my query with random generated password?
Password needs to have at least 15 characters, 1 special character, one number and one Upper letter.
Any ideas?
Thanks
You can create a function to return such random passwords and use it in your queries:
-- function:
with
function get_rand_pass(n in number) return varchar2 as
res varchar2(15);
begin
loop
res:=DBMS_RANDOM.STRING('p',15);
exit when
regexp_like(res,'[^a-zA-Z0-9]') -- special char
and regexp_like(res,'\d') -- at least one number
and regexp_like(res,'[A-Z]') -- at least one UPPER letter
;
end loop;
return res;
end;
-- end of function
-- test query:
select
get_rand_pass(dbms_random.value()) pass
from dual;
Full example:
with
function get_rand_pass(n in number) return varchar2 as
res varchar2(15);
begin
loop
res:=DBMS_RANDOM.STRING('p',15);
exit when
regexp_like(res,'[^a-zA-Z0-9]') -- special char
and regexp_like(res,'\d') -- at least one number
and regexp_like(res,'[A-Z]') -- at least one UPPER letter
;
end loop;
return res;
end;
select
get_rand_pass(dbms_random.value()) pass
from dual
connect by level<=10
/
PASS
---------------
C7Bncs'bH9+Hx&p
kHG<&4Aw36VS3W
np xvyvM]3In #{
%A1&+}XVNyBvL'%
+,Bp hII\q,&7>V
h#l` kE(b4=-C</
(c{7"`~UvN44#e/
<_s+4G!nlujcytJ
{[a2{*sXW;;$#<.
7)^>Qj4!1MTm?};
10 rows selected.
or use the following subquery in your queries:
(
select pass
from
(select DBMS_RANDOM.STRING('p',15) pass from dual connect by level<=1e5)
where
rownum=1 -- first pass
and regexp_like(pass,'[^a-zA-Z0-9]') -- special char
and regexp_like(pass,'\d') -- at least one number
and regexp_like(pass,'[A-Z]') -- at least one UPPER letter
) pass
But it may be cached (scalar subquery caching) and if you use cross join with such generator, it may be executed just once in hash join, so it needs a workaround, for example:
select--+ use_nl(pass_gen)
*
from FND_ORACLE_USERID,
lateral(
select--+ no_merge no_unnest
pass
from
(select DBMS_RANDOM.STRING('p',15) pass from dual connect by level<=1e5)
where
rownum=1 -- first pass
and regexp_like(pass,'[^a-zA-Z0-9]') -- special char
and regexp_like(pass,'\d') -- at least one number
and regexp_like(pass,'[A-Z]') -- at least one UPPER letter
) pass_gen;
As you can see here I forced nested loops and disable merge and unnest transformations.
I m getting an error as when I compiled the below code as alias required in select list of the cursor.
Create Or Replace PROCEDURE pr_no_debit is
Cursor c_Today(From_date date, To_Date date) is
Select Today from sttm_dates where today between From_Date and To_Date;
cursor c_no_debit is
Select a.* , b.* from STTM_NO_DEBIT_customer a , STTM_FIN_CYCLE b where a.Fin_Cycle = b.Fin_Cycle ;
l_No_Debit_List STTM_NO_DEBIT_CUSTOMER%ROWTYPE;
begin
For i_indx in c_Today(l_No_Debit_List.From_Date,l_No_Debit_List.To_Date)
Loop
for j_indx in c_no_debit
loop
update sttm_cust_account set ac_stat_no_Dr='Y' where account_class=j_index.account_class;
end loop;
End Loop;
-- At the end of the period Change No_Debit to 'N'
End pr_no_debit;
Another solution could be to split the cursor into two parts, though giving alias to respective columns shall be sufficient under the case:
Cursor c_no_debit :
c_no_debit_1: Based on table STTM_NO_DEBIT_customer a
c_no_debit_2: Based on table STTM_FIN_CYCLE b
Through parameterized cursor pass value of of cursor_1 into cursor_2.
Tables STTM_NO_DEBIT_CUSTOMER and STTM_FIN_CYCLE both have a column named FIN_CYCLE, so when the PL/SQL compiler tries to construct the record j_indx from c_no_debit, it gets something like this:
( fin_cycle number
, from_date date
, to_date date
, account_class varchar2(20)
, fin_cycle number
, ...
which is invalid because a record can't have two fields with the same name.
Change c_no_debit to specify only the columns you need, for example:
cursor c_no_debit is
select a.account_class
from sttm_no_debit_customer a
join sttm_fin_cycle b on b.fin_cycle = a.fin_cycle;
(and maybe other columns - I don't have your schema and I don't know what it needs to do)
I have a function that returns a value and displays a similarity between tracks, i want the returned result to be ordered by this returned value, but i cannot figure out a way on how to do it, here is what i have already tried:
CREATE OR REPLACE PROCEDURE proc_list_similar_tracks(frstTrack IN tracks.track_id%TYPE)
AS
sim number;
res tracks%rowtype;
chosenTrack tracks%rowtype;
BEGIN
select * into chosenTrack from tracks where track_id = frstTrack;
dbms_output.put_line('similarity between');
FOR res IN (select * from tracks WHERE ROWNUM <= 10)LOOP
SELECT * INTO sim FROM ( SELECT func_similarity(frstTrack, res.track_id)from dual order by sim) order by sim; //that's where i am getting the value and where i am trying to order
dbms_output.put_line( chosenTrack.track_name || '(' ||frstTrack|| ') and ' || res.track_name || '(' ||res.track_id|| ') ---->' || sim);
END LOOP;
END proc_list_similar_tracks;
/
declare
begin
proc_list_similar_tracks(437830);
end;
/
no errors are given, the list is just presented unsorted, is it not possible to order by a value that was returned by a function? if so, how do i accomplish something like this? or am i just doing something horribly wrong?
Any help will be appreciated
In the interests of (over-)optimisation I would avoid ordering by a function if I could possibly avoid it; especially one that queries other tables. If you're querying a table you should be able to add that part to your current query, which enables you to use it normally.
However, let's look at your function:
There's no point using DBMS_OUTPUT for anything but debugging unless you're going to be there looking at exactly what is output every time the function is run; you could remove these lines.
The following is used only for a DBMS_OUTPUT and is therefore an unnecessary SELECT and can be removed:
select * into chosenTrack from tracks where track_id = frstTrack;
You're selecting a random 10 rows from the table TRACKS; why?
FOR res IN (select * from tracks WHERE ROWNUM <= 10)LOOP
Your ORDER BY, order by sim, is ordering by a non-existent column as the column SIM hasn't been declared within the scope of the SELECT
Your ORDER BY is asking for the least similar as the default sort order is ascending (this may be correct but it seems wrong?)
Your function is not a function, it's a procedure (one without an OUT parameter).
Your SELECT INTO is attempting to place multiple rows into a single-row variable.
Assuming your "function" is altered to provide the maximum similarity between the parameter and a random 10 TRACK_IDs it might look as follows:
create or replace function list_similar_tracks (
frstTrack in tracks.track_id%type
) return number is
sim number;
begin
select max(func_similarity(frstTrack, track_id)) into sim
from tracks
where rownum <= 10
;
return sim;
end list_similar_tracks;
/
However, the name of the function seems to preclude that this is what you're actually attempting to do.
From your comments, your question is actually:
I have the following code; how do I print the top 10 function results? The current results are returned unsorted.
declare
sim number;
begin
for res in ( select * from tracks ) loop
select * into sim
from ( select func_similarity(var1, var2)
from dual
order by sim
)
order by sim;
end loop;
end;
/
The problem with the above is firstly that you're ordering by the variable sim, which is NULL in the first instance but changes thereafter. However, the select from DUAL is only a single row, which means you're randomly ordering by a single row. This brings us back to my point at the top - use SQL where possible.
In this case you can simply SELECT from the table TRACKS and order by the function result. To do this you need to give the column created by your function result an alias (or order by the positional argument as already described in Emmanuel's answer).
For instance:
select func_similarity(var1, var2) as function_result
from dual
Putting this together the code becomes:
begin
for res in ( select *
from ( select func_similarity(variable, track_id) as f
from tracks
order by f desc
)
where rownum <= 10 ) loop
-- do something
end loop;
end;
/
You have a query using a function, let's say something like:
select t.field1, t.field2, ..., function1(t.field1), ...
from table1 t
where ...
Oracle supports order by clause with column indexes, i.e. if the field returned by the function is the nth one in the select (here, field1 is in position 1, field2 in position 2), you just have to add:
order by n
For instance:
select t.field1, function1(t.field1) c2
from table1 t
where ...
order by 2 /* 2 being the index of the column computed by the function */
I am trying to write a small pl/sql script and need some help.
first, I have 2 tables called project1 , project2. both tables have a column called cust_code.
cust_code values are varchar2 type. values always begin with 1. (number 1, decimal point) and 8 digits. for example 1.10002332
when I import data into project1 table, if the last digit is 0, for example 1.22321630, the last zero is dropped and then theres only seven digits beyond the decimal point. in that case it will be 1.2232163
the script I want to write will check whether there are only 7 digits beyond the decimal point and will insert that record into the project2 table.
this is what I came up with
DECLARE
CURSOR dif IS
SELECT CUST_CODE, CUST_ID, CONTRACT_NUM, MSISDN
FROM project1
WHERE CUST_CODE IN (SELECT CUST_CODE FROM CUST_ALL);
BEGIN
FOR a in dif LOOP
IF SUBSTR(a.CUST_CODE, 10)=null
THEN
INSERT INTO project2 (cust_code)
VALUES(a.CUST_CODE);
END IF;
END LOOP;
commit;
END;
the script runs with no errors but nothing happens. on the substr function, when I chose different value than NULL, then it works. I cant figure out how to check if the 8th digit is missing.
Assaf.
Your script doesn't work because of the line:
IF SUBSTR(a.CUST_CODE, 10)=null
In plsql <something> = null will always be FALSE.
You should write:
IF SUBSTR(a.CUST_CODE, 10) IS null
But actually you don't really nead plsql, you can do it with one sql command:
INSERT INTO project2 (cust_code)
SELECT CUST_CODE, CUST_ID, CONTRACT_NUM, MSISDN
FROM project1
WHERE CUST_CODE IN (SELECT CUST_CODE FROM CUST_ALL)
AND SUBSTR(a.CUST_CODE, 10) IS null;
Try this for your condition:
IF LENGTH(a.CUST_CODE) = 10 AND SUBSTR(a.CUST_CODE,-1,10) = '0'
(check if length is 10 and also last character is 0)