Using Dates in PL/SQL [duplicate] - oracle

This question already has answers here:
Working with dates in Oracle SQL
(3 answers)
Closed 6 years ago.
I am very new to using PL/SQL and I have created a procedure but I cannot figure out the correct syntax in order to get the current month and year's data and another cursor to get the data from exactly 1 year prior:
create or replace procedure data(acc integer, month integer, year integer)
as
Cursor c1 is
select usage
from bill
where account =acc_num and to_char(BILL_DATE, 'MM-YYYY') = 'month-year';
Cursor c3 is
select usage
from bill
where account =acc_num and
to_char(BILL_DATE, 'MM-YYYY') = 'month-year' - 1;
** I do understand this is only part of the code, but I believe my logic is almost complete for finding the data I want. Using PLSQL

I think you are looking for something like this:
select usage
from bill
where account = in_account and
extract(year from bill_date) = in_year and
extract(month from bill_date) = in_month;
If you want to compare the year and month (which are passed in as integers), just extract those attributes from the date.
If you are learning PL/SQL, learn to name your parameters and arguments so you can distinguish them from columns:
create or replace procedure data (
in_account integer,
in_month integer,
in_year integer
) as
begin
. . .
(And "data" is a very curious name for a stored procedure. I would expect a verb in the name.)

Related

comparar fechas de diferentes tablas al detalle de los segundos

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;

OUT parameter with multiples values

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

Parameter for IN query oracle [duplicate]

This question already has an answer here:
Oracle: Dynamic query with IN clause using cursor
(1 answer)
Closed 8 years ago.
SELECT * FROM EMPLOYEE
WHERE EMP_NAME IN (:EMP_NAME);
This is my query and now the EMP_NAME parameter I would like to send it as a list of strings.
When I run this query in SQL developer it is asked to send the EMP_NAME as a parameter, Now I want to send 'Kiran','Joshi' (Basically, I want to fetch the details of the employee with employee name either Kiran or Joshi. How should I pass the value during the execution of the query?
It works when I use the value Kiran alone, but when I concatenate with any other string it won't work. Any pointers in this?
I tried the one below
'Kiran','Joshi'
The above way doesn't work as understood this is a single parameter it tries the employee with the name as 'Kiran',Joshi' which won't come. Understandable, but in order to achieve this thing, how can I go ahead?
Any help would be really appreciated.
Thanks to the people who helped me in solving this problem.
I could get the solution using the way proposed, below is the approach
SELECT * FROM EMPLOYEE WHERE EMP_NAME IN (&EMP_NAME)
I have tried in this way and following are the scenarios which I have tested and they are working fine.
Scenario 1:
To fetch details of only "Kiran", then in this case the value of EMP_NAME when sql developer prompts is given as Kiran. It worked.
Scenario 2:
To fetch details of either "Kiran" or "Joshi", then the value of EMP_NAME is sent as
Kiran','Joshi
It worked in this case also.
Thanks Kedarnath for helping me in achieving the solution :)
IN clause would be implicitly converted into multiple OR conditions.. and the limit is 1000.. Also query with bind variable means, the execution plan will be reused.. Supporting bind variables for IN clause will hence affect the bind variable's basic usage, and hence oracle limits it at syntax level itself.
Only way is like name in (:1,:2) and bind the other values..
for this, you might dynamic SQL constructing the in clause bind variables in a loop.
Other way is, calling a procedure or function(pl/sql)
DECLARE
v_mystring VARCHAR(50);
v_my_ref_cursor sys_refcursor;
in_string varchar2='''Kiran'',''Joshi''';
id2 varchar2(10):='123'; --- if some other value you have to compare
myrecord tablename%rowtype;
BEGIN
v_mystring := 'SELECT a.*... from tablename a where name= :id2 and
id in('||in_string||')';
OPEN v_my_ref_cursor FOR v_mystring USING id2;
LOOP
FETCH v_my_ref_cursor INTO myrecord;
EXIT WHEN v_my_ref_cursor%NOTFOUND;
..
-- your processing
END LOOP;
CLOSE v_my_ref_cursor;
END;
IN clause supports maximum of 1000 items. You can always use a table to join instead. That table might be a Global Temporary Table(GTT) whose data is visible to thats particular session.
Still you can use a nested table also for it(like PL/SQL table)
TABLE() will convert a PL/Sql table as a SQL understandable table object(an object actually)
A simple example of it below.
CREATE TYPE pr AS OBJECT
(pr NUMBER);
/
CREATE TYPE prList AS TABLE OF pr;
/
declare
myPrList prList := prList ();
cursor lc is
select *
from (select a.*
from yourtable a
TABLE(CAST(myPrList as prList)) my_list
where
a.pr = my_list.pr
order by a.pr desc) ;
rec lc%ROWTYPE;
BEGIN
/*Populate the Nested Table, with whatever collection you have */
myPrList := prList ( pr(91),
pr(80));
/*
Sample code: for populating from your TABLE OF NUMBER type
FOR I IN 1..your_input_array.COUNT
LOOP
myPrList.EXTEND;
myPrList(I) := pr(your_input_array(I));
END LOOP;
*/
open lc;
loop
FETCH lc into rec;
exit when lc%NOTFOUND; -- Your Exit WHEN condition should be checked afte FETCH iyself!
dbms_output.put_line(rec.pr);
end loop;
close lc;
END;
/

How set a variable as the differance of 2 other variables in oracle?

I am new to Oracle, and I have a class registration type database, and I am using a Stored Procedure to print the Available Courses for a certain semseter. I am currently trying to set the "Remaining open Spots" of a class as the difference between the Capacity - Registered. But I am not sure how / where to create this variable as the difference between 2 other variables,So that I may use it in my table.
Can anyone help? Everything I have now works fine, I just need help with this variable. I am thinking I create and set the variable in the Select statement, then I can just use the variable in my Table. I just dont know how.
for i in (select Course_Id, Capacity, Registered, Semester, City from Schedule)
loop
if(i.Semester = Semcode AND i.City = City) then
htp.print(' <tr>');
htp.print(' <td>'||i.Semester||'</td>');
htp.print(' <td>'||i.Course_Id||'</td>');
htp.print(' <td>'||i.Capacity||'</td>');
htp.print(' <td>'||i.Registered||'</td>');
/*htp.print(' <td>'||********* "Remaing Spots Variable"******* ||'</td>');*/
htp.print(' </tr>');
end if;
end loop;
That's fairly easy:
SQL> select 'hello'||(5-3)||'goodbye' from dual;
'HELLO'||(5-3
-------------
hello2goodbye
-> in your case it would just be (i.Capacity - i.Registered) ... though it's important those fields are number / integer / somethinglikethis (it won't work with varchar2)

How to extract only date value from date field in Oracle? [duplicate]

This question already has answers here:
How to correctly handle dates in queries constraints
(4 answers)
Closed 8 years ago.
I am new to Oracle database.I dont have much knowledge about date-time concepts in Oracle.
The problem i am facing is to retrieve records which are entered on a particular date.But when i am executing SQL query on database it returns zero records.
Database has date field which contains records with both datetime value.
SQL Query: SELECT * FROM table WHERE table.daterecord = to_date(03-Mar-2010)
It is not returning any record but if i change my query to
SELECT * FROM table WHERE table.daterecord > to_date(04-Mar-2010)
It will return some records.
The above difference is because of time.How can i extract time value from date. Can I use trunc function for this? Thanks in advance for your valuable suggestions.
Yes you can use TRUNC function.
SELECT *
FROM table
WHERE TRUNC(table.daterecord) = TO_DATE('03-Mar-2010', 'DD-MON-RRRR')
see this SO for suggestions of "How to correctly handle dates in queries constraints"?
In addition to the answers already provided, I would suggest using a range since this is more easily indexable:
SELECT *
FROM table
WHERE table.daterecord >= TO_DATE('03-Mar-2010', 'DD-MON-RRRR')
AND table.daterecord < TO_DATE('04-Mar-2010', 'DD-MON-RRRR')
you can use TRUNC
For example :
SELECT *
FROM table
WHERE TRUNC(table.daterecord) = TO_DATE('03-Mar-2010', 'DD-MON-RRRR')

Resources