SQL Developer - Using start and end date variables in where clause of my query - oracle

I have a query that I run everyday that requires a StartDate and EndDate value. The StartDate and EndDate used to be a manual input but I am trying to get away from that and calculate the StartDate and EndDate to be used in the query. I've developed code to capture the StartDate and EndDate in variables:
DECLARE
c_DateMask VARCHAR2(20) := 'DD-Mon-YYYY';
c_TimeMask VARCHAR2(20) := 'HH24:MI';
v_Month char(4) := 'Prev';
v_StartDate date;
v_EndDate date;
v_Environment char(7) := 'Prod';
BEGIN
if v_MONTH = 'Prev'
THEN
select TO_DATE ('01-' || TO_CHAR (ADD_MONTHS (SYSDATE, -1),'mon-yyyy')) into v_StartDate from dual;
select Last_day(TO_DATE('01-' || TO_CHAR (ADD_MONTHS (SYSDATE, -1),'mon-yyyy'))) into v_EndDate from dual;
ELSE
select TO_DATE ('01-' || TO_CHAR (ADD_MONTHS (SYSDATE, 0),'mon-yyyy')) into v_StartDate from dual;
CASE
WHEN v_Environment = 'Prod'
THEN
-- Production Environment --
select
to_char(sysdate, 'dd-Mon-yyyy ') ||
case
when to_char(sysdate, 'mi') between 00 and 20
then to_char(sysdate, 'hh24')-1||':58'||':00'
when to_char(sysdate, 'mi') between 21 and 40
then to_char(sysdate, ' hh24')||':18'||':00'
when to_char(sysdate, 'mi') between 41 and 60
then to_char(sysdate, ' hh24')||':38'||':00'
END
into v_EndDate from dual;
WHEN v_Environment = 'OldTest'
THEN
-- Test Environment --
select
to_char(sysdate, 'dd-Mon-yyyy ') ||
case
when to_char(sysdate, 'mi') between 10 and 30
then to_char(sysdate, 'hh24')||':08'||':00'
when to_char(sysdate, 'mi') between 31 and 50
then to_char(sysdate, ' hh24')||':28'||':00'
when to_char(sysdate, 'mi') between 51 and 60
then to_char(sysdate, ' hh24')||':48'||':00'
END
into v_EndDate from dual;
end case;
end if;
I then want to use the variables in my select statement below:
-----------------
/* KPI Figures */
-----------------
SELECT
SysDate as RunTime
, v_StartDate
, v_EndDate
, TTM_OFF_CONTRIBUTOR
, SUM(NVL(TTM_PER_OFF_FEE,0)) Fees
FROM [Table]
Where
TTM_PROCESSED_DATE >= v_StartDate
AND TTM_PROCESSED_DATE <= v_EndDate
group by SysDate, v_StartDate, v_EndDate, TTM_OFF_CONTRIBUTOR
END;
It all works up until when I try to use the variable values in the KPI Figures query. What am I missing?
Update:
Regarding Phil's answer: I tried but it didn't work and I get the following error:
PLS-00428: an INTO clause is expected in this SELECT statement.
I am sure I saw another response yesterday which is now gone relating to being able to assign multiple values to variables or something.
Is that what I need and how would I do that?

The variables v_StartDate and v_EndDate are only in scope within the PL/SQL block where they are declared. It looks like you are then trying to use them outside the block in a separate query. To do that you will need to create SQL Developer bind variables outside the PL/SQL block like this:
var v_start_date varchar2(11)
var v_end_date varchar2(11)
Then reference these as bind variables in both the PL/SQL block and the SQL query:
declare
...
begin
....
:v_start_date := '01-' || TO_CHAR (ADD_MONTHS (SYSDATE, -1), 'mon-yyyy');
:v_end_date := TO_CHAR(Last_day(TO_DATE('01-'
|| TO_CHAR (ADD_MONTHS (SYSDATE, -1),'mon-yyyy'))));
-- (NB No need to select from dual)
...
end;
SQL:
...
Where
TTM_PROCESSED_DATE >= TO_DATE(:v_StartDate)
AND TTM_PROCESSED_DATE <= TO_DATE(:v_EndDate)
Note that these variables cannot be declared with a type of DATE, so they need to be converted back to dates in the query (using the correct format mask).

I suggest you wrap the startdate/enddate in two functions (stored procedures)
create or replace function get_startdate(p_month in varchar2, p_env in varchar2)
return date
is
l_return date;
begin
... logic goes here ...
return l_return;
end;
Similar for enddate.
Then use those functions in your query:
SELECT
SysDate as RunTime
, get_startdate('Prev', 'Prod')
, get_enddate('Prev', 'Prod')
, TTM_OFF_CONTRIBUTOR
, SUM(NVL(TTM_PER_OFF_FEE,0)) Fees
FROM [Table]
Where
TTM_PROCESSED_DATE >= get_startdate('Prev', 'Prod')
AND TTM_PROCESSED_DATE <= get_enddate('Prev', 'Prod')
group by SysDate, get_startdate('Prev', 'Prod'), get_enddate('Prev', 'Prod'), TTM_OFF_CONTRIBUTOR
Sidenote: please consider a more concise version to determine first and last day of a month. You also can just assign a value to a variable without using SELECT INTO, e.g.
startdate := trunc(sysdate, 'MM'); -- first day of current month
enddate := last_day(trunc(sysdate, 'MM')); -- last day of current month
To calculate with hours, you could add/subtract a number of minutes, that's more readable than all the to_date/to_char conversions you do, e.g.
enddate := trunc(sysdate, 'HH24');
case
when to_char(sysdate, 'mi') between 00 and 20 then enddate := enddate - 2/(24*60);
when to_char(sysdate, 'mi') between 21 and 40 then enddate := enddate + 18/(24*60);
when to_char(sysdate, 'mi') between 41 and 60 then enddate := enddate + 38/(24*60);
end;
Good luck, Martin

I think the issue is with your query and aliases. Try
SELECT
SysDate as RunTime
, v_StartDate AS StartDate
, v_EndDate AS EndDate
, TTM_OFF_CONTRIBUTOR
, SUM(NVL(TTM_PER_OFF_FEE,0)) Fees
FROM [Table]
Where
TTM_PROCESSED_DATE >= v_StartDate
AND TTM_PROCESSED_DATE <= v_EndDate
group by RunTime, StartDate, EndDate, TTM_OFF_CONTRIBUTOR

Related

How to get the first and last date of previous month without using to_date, trunc and predefined add_months function

I wrote the below code but I did not get the expected output:
SQL> select TO_CHAR(TO_CHAR(sysdate,'MM')-1,'DD-MM-YYYY') AS PREV_MON_FIRST,
TO_CHAR(TO_CHAR(sysdate,'MM'),'DD-MM-YYYY')-1 AS PREV_MON_LAST from dual;
select TO_CHAR(TO_CHAR(sysdate,'MM')-1,'DD-MM-YYYY') AS PREV_MON from dual
*
ERROR at line 1:
ORA-01481: invalid number format model
It's correct that 'DD' and 'YYYY' values are missing but when I tried to retrieve only month also it shows the same error
You can use the following solution:
SELECT
TRUNC(LAST_DAY(ADD_MONTHS(sysdate, -2))) + 1 AS first_date,
TRUNC(LAST_DAY(ADD_MONTHS(sysdate, -1))) AS last_date
FROM dual
Selecting the first day of the previous month using TO_CHAR only is easy, if YYYYMMDD format suits your needs:
SQL> select (to_char(sysdate, 'yyyymm') - 1) || '01' first_day
2 from dual;
FIRST_DAY
------------------------------------------
20180701
SQL>
But, for the last day - I have no idea.
Usual way to do it works, but involves other functions:
SQL> select trunc(add_months(sysdate, -1), 'mm') first_day,
2 trunc(sysdate, 'mm') - 1 last_day
3 from dual;
FIRST_DAY LAST_DAY
---------- ----------
2018-07-01 2018-07-31
SQL>
For LAST_DAY here is the query with hard_code of values of month without using add_months,trunc,to_date
select to_char(sysdate,'yyyy')||
to_char(sysdate,'mm')-1||
case when to_char(sysdate,'mm')-1 in (1,3,5,7,8,10,12) THEN 31
when to_char(sysdate,'mm')-1 in (4,6,9,11) THEN 30
when mod(to_char(sysdate,'yyyy'),4)=0 and to_char(sysdate,'mm')-1=2 THEN 29
when mod(to_char(sysdate,'yyyy'),4)!=0 and to_char(sysdate,'mm')-1=2 THEN 28
end
from dual
If I take your question literally one solution is
CREATE OR REPLACE FUNCTION MY_LAST_DAY RETURN TIMESTAMP AS
next_run_date TIMESTAMP;
return_date_after TIMESTAMP := SYSTIMESTAMP - INTERVAL '100' DAY;
BEGIN
LOOP
DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING('FREQ=DAILY;INTERVAL=1;BYMONTHDAY=-1', NULL, return_date_after, next_run_date);
EXIT WHEN EXTRACT(MONTH FROM next_run_date) = EXTRACT(MONTH FROM SYSTIMESTAMP);
return_date_after := next_run_date;
END LOOP;
RETURN return_date_after;
END;
/
CREATE OR REPLACE FUNCTION MY_FIRST_DAY RETURN TIMESTAMP AS
next_run_date TIMESTAMP;
return_date_after TIMESTAMP := SYSTIMESTAMP - INTERVAL '100' DAY;
BEGIN
LOOP
DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING('FREQ=DAILY;INTERVAL=1;BYMONTHDAY=1', NULL, return_date_after, next_run_date);
EXIT WHEN EXTRACT(MONTH FROM next_run_date) = EXTRACT(MONTH FROM SYSTIMESTAMP);
return_date_after := next_run_date;
END LOOP;
RETURN return_date_after;
END;
/
It returns the first and last date of previous month without using TO_DATE (or TO_TIMESTAMP), TRUNC or ADD_MONTHS
But I hope you agree that your question is rather stupid.
For LAST_DAY here is the query with hard_code of values of month without using add_months,trunc,to_date
select to_char(sysdate,'yyyy')||
to_char(sysdate,'mm')-1||
case when to_char(sysdate,'mm')-1 in (1,3,5,7,8,10,12) THEN 31
when to_char(sysdate,'mm')-1 in (4,6,9,11) THEN 30
when mod(to_char(sysdate,'yyyy'),4)=0 and to_char(sysdate,'mm')-1=2 THEN 29
when mod(to_char(sysdate,'yyyy'),4)!=0 and to_char(sysdate,'mm')-1=2 THEN 28
end
from dual
New Query to handle Janurary and Leap year :
select decode(to_char(sysdate,'mm'),1,to_char(sysdate,'yyyy')-1 ,to_char(sysdate,'yyyy'))||
decode(to_char(sysdate,'mm'),1,12, to_char(sysdate,'mm')-1)||
CASE WHEN to_char(sysdate,'mm')-1 in (1,3,5,7,8,10,0) THEN 31
WHEN to_char(sysdate,'mm')-1 in (4,6,9,11) THEN 30
WHEN to_char(sysdate,'mm')-1=2 AND mod(to_char(sysdate,'yyyy'),4)!=0 AND mod(to_char(sysdate,'yyyy'),400)!=0 THEN 29
ELSE 28
END
FROM dual

PL SQL 'IF or CASE' using variable date

I am stuck with this and could use advice/help:
Basically, trying to set the date as a variable and then run select statements, using that date variable in the 'WHERE' section of the query. Not sure if I should be using IF or CASE, or neither? If its monday, i want to run 1 set of dates (prev thur and fri) any other day (just sysdate-2 and sysdate-1) Any help is much appreciated!
Code is below:
DECLARE
today_date number;
start_date date;
end_date date;
BEGIN
today_date := to_char(sysdate, 'D');
start_date := case when today_date ='2' then 'sysdate-4' else 'sysdate-2'
end;
end_date := case when today_date ='2' then 'sysdate-3' else 'sysdate-1' end;
SELECT COLUMN A, COLUMN B, COLUMN C, COLUMN D
FROM /*csv*/REPORT_NAME
WHERE COLUMN B between trunc(start_date)+21/24 and trunc(end_date)+21/24 and
BOOK_NAME = 'xxxxxx' and SERVER = 'xxxxxx' and EX_ACTION = 'xxxxx';
end;
You're mixing variables/functions and strings. This should work.
DECLARE
today_date number;
start_date date;
end_date date;
BEGIN
today_date := to_char(sysdate, 'D');
start_date := case when today_date ='2' then sysdate-4 else sysdate-2
end;
end_date := case when today_date ='2' then sysdate-3 else sysdate-1 end;
/* this won't work without declaring a cursor, and returning it to the client
SELECT COLUMN A, COLUMN B, COLUMN C, COLUMN D
FROM REPORT_NAME
WHERE COLUMN B between trunc(start_date)+21/24 and trunc(end_date)+21/24 and
BOOK_NAME = 'xxxxxx' and SERVER = 'xxxxxx' and EX_ACTION = 'xxxxx';
*/
end;
Note you also have some implicit type conversion happening. today_date should probably be char(1) instead.
You don't really need variables for this, and you don't need PL/SQL; you can calculate the dates as part of the where clause using case expressions in that instead:
SELECT /*csv*/ COLUMN_A, COLUMN_B, COLUMN_C, COLUMN_D
FROM REPORT_NAME
WHERE COLUMN_B >= trunc(sysdate) - case to_char(sysdate, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH')
when 'Mon' then 4 else 2 end + 21/24
AND COLUMN_B < trunc(sysdate) - case to_char(sysdate, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH')
when 'Mon' then 3 else 1 end + 21/24
AND BOOK_NAME = 'xxxxxx'
AND SERVER = 'xxxxxx'
AND EX_ACTION = 'xxxxx';
I've taken the liberty of changing the logic from being based on the day number being 2 to it having a specific day abbreviation, because the value D returns is based on your NLS settings so it could vary (and give unexpected results) for someone else running your code. As day names and abbreviations are also NLS-dependent I've specified the language to use. (You can't specify how D is used in the same way, unfortunately).
I've changed the time window slightly, so it goes from 9pm on one day to up to but not including 9pm the next day. If you use between then it's inclusive at both ends, so runs on consecutive days you both pick up any data at exactly 21:00:00 from the overlapping day. That probably isn't what you want (but if it really is, just change < to <=, or revert to between if you prefer...).
If you want a PL/SQL wrapper you can do the same thing, but you either have to select the results into something like a collection, or use a ref cursor to return the result set to the caller. It isn't clear if you actually need or want to do that though.
have you tried selecting into your variables?
DECLARE
TODAY_DATE NUMBER;
START_DATE DATE;
END_DATE DATE;
BEGIN
TODAY_DATE := TO_CHAR (SYSDATE, 'D');
SELECT CASE WHEN TODAY_DATE = '2' THEN SYSDATE - 4 ELSE SYSDATE - 2 END,
CASE WHEN TODAY_DATE = '2' THEN SYSDATE - 3 ELSE SYSDATE - 1 END
INTO START_DATE, END_DATE
FROM DUAL;
SELECT COLUMN_A, COLUMN_B, COLUMN_C, COLUMN_D
FROM REPORT_NAME /*csv*/
WHERE COLUMN_B BETWEEN TRUNC (START_DATE) + 21 / 24
AND TRUNC (END_DATE) + 21 / 24
AND BOOK_NAME = 'xxxxxx'
AND SERVER = 'xxxxxx'
AND EX_ACTION = 'xxxxx';
END;

ORA-01027: bind variables not allowed for data definition when trying to use if elseif

I am getting 'ORA-01027: bind variables not allowed for data definition'
procedure create_dates_testing (dummy_variable varchar2 default
to_char(sysdate,'YYYYMMDD')) is
begin
DECLARE
day_of_month varchar2(255) := extract(day from sysdate);
today varchar2(255) := to_char(sysdate, 'DAY');
start_date date;
next_start_date date;
BEGIN
IF today='SUNDAY' THEN
-- Select yesterday
start_date := trunc(sysdate) - interval '1' day;
next_start_date := trunc(sysdate);
ELSE IF day_of_month=3 then
-- Select the whole of last month
start_date := runc(sysdate, 'MM') - interval '1' month;
next_start_date := runc(sysdate, 'MM') - interval '1' month
END IF;
END;
execute immediate 'drop table new_customers';
execute immediate 'create table new_customers as
select id, client_name, invoice_date
from clients table
where transactiondate >= :start_date
and transactiondate < :next_start_date;';
end;
How can I resolve this error? Where am I going wrong? I need to put this procedure in a pl/sql package.
As the error says, you can't use bind variables here, so you have to concatenate:
create or replace procedure create_dates_testing
( dummy_variable varchar2 default to_char(sysdate,'YYYYMMDD') )
as
day_of_month varchar2(255) := extract(day from sysdate);
today varchar2(255) := to_char(sysdate +1, 'fmDAY', 'nls_date_language = English');
start_date date;
next_start_date date;
begin
if today = 'SUNDAY' then
-- select yesterday
start_date := trunc(sysdate) - interval '1' day;
next_start_date := trunc(sysdate);
elsif day_of_month = 3 then
-- select the whole of last month
start_date := trunc(sysdate, 'MM') - interval '1' month;
next_start_date := trunc(sysdate, 'MM') - interval '1' month;
else
return;
end if;
execute immediate 'drop table new_customers';
execute immediate 'create table new_customers as
select id, client_name, invoice_date
from clients table
where transactiondate >= date ''' || to_char(start_date,'YYYY-MM-DD') ||
''' and transactiondate < date ''' || to_char(next_start_date,'YYYY-MM-DD') ||'''';
end create_dates_testing;
Presumably there will be some more code to handle the case where it is neither Sunday nor the third of the month, or the new_customers table does not exist.
Edit: added else condition to end processing if neither of the date conditions are met.

Pl sql date initialization comparsion ++

I have requirement where i have to get data of particular day. So my ideal startdate should be 2013-06-07 00:00:01 AM and end date 2013-06-07 23:59:59 AM
Hence i have written this code.
create or replace
PROCEDURE checkChanges
IS
vc_startDate timestamp;
vc_endDate timestamp;
begin
vc_startDate :=to_timestamp(TO_CHAR(trunc(systimestamp)-40+((24*60*60)-1)/(24*60*60),'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss');
vc_endDate :=to_timestamp(TO_CHAR(trunc(systimestamp)+1/(24*60*60),'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss');
Dbms_Output.Put_Line('vc_startDate ' ||vc_startDate);
Dbms_Output.Put_Line('vc_endDate ' ||vc_endDate);
SELECT EMAIL_ADRESS FROM SOMETABLE A,B
AND A.CREATE_TS BETWEEN vc_startDate AND vc_endDate ORDER BY B.START_DT;
end checkChanges;
But the start date and end date i am getting is quite different.
start date:07-JUN-13 12.00.01.000000 AM
end date: 07-JUN-13 11.59.59.000000 PM
Here's a simple way to do this.
DECLARE
v_start TIMESTAMP;
v_end TIMESTAMP;
BEGIN
v_start := TRUNC (SYSTIMESTAMP) + NUMTODSINTERVAL (1, 'second'); --truncate the timestamp and add one second
DBMS_OUTPUT.PUT_LINE (TO_CHAR (v_start, 'yyyy-mm-dd hh24:mi:ss'));
/*alternate way
v_start := TRUNC (SYSTIMESTAMP) + INTERVAL '0 0:0:1' DAY TO SECOND; --truncate the timestamp and add one second
DBMS_OUTPUT.PUT_LINE (TO_CHAR (v_start, 'yyyy-mm-dd hh24:mi:ss AM'));*/
v_end :=
TRUNC (SYSTIMESTAMP) --trunacate the timestamp
+ INTERVAL '1 0:0:0.0' DAY TO SECOND --add a day
- NUMTODSINTERVAL (1, 'second'); --substract a second
DBMS_OUTPUT.PUT_LINE (TO_CHAR (v_end, 'yyyy-mm-dd hh24:mi:ss'));
/*alternate way
v_end := TRUNC (SYSTIMESTAMP) --trunacate the timestamp
+ INTERVAL '0 23:59:59' DAY TO SECOND; --add hours, mins, s
DBMS_OUTPUT.PUT_LINE (TO_CHAR (v_end, 'yyyy-mm-dd hh24:mi:ss AM'));*/
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE (SQLERRM);
END;
Output:
2013-06-07 00:00:01 AM
2013-06-07 23:59:59 PM
UPDATE
I also printed the values without converting to to_char and it displayed similar to what u got.
DBMS_OUTPUT.PUT_LINE (v_start);
DBMS_OUTPUT.PUT_LINE (v_end);
Output:
07-JUN-13 12.00.01.000000 AM
07-JUN-13 11.59.59.000000 PM
So, it seems what you are doing is correct(but, little complicated). When displaying the timestamp it is getting displayed according to the NLS parameters. Check that using
SELECT *
FROM nls_session_parameters
WHERE parameter = 'NLS_TIMESTAMP_FORMAT';
I guess it will return this DD-MON-RR HH.MI.SSXFF AM
Do not worry about how it is being displayed. A date/timestamp variable has no format. It matters only when you want to print it. If don't use to_char function, it'll take the format mask as defined in NLS parameters. If you want to override it, use to_char function and specify the mask.But when used in the query, it'll have the correct value.

Problem retrieving time from date field in oracle stored procedure

I'm having problems retrieving the time from a date field in a SP. If I run the query:
select TO_CHAR(HOR_HST_ATN,'YYYY/MM/DD HH24:MI:SS') AS HOR_HST_ATN FROM AAM0_DT_RSTCN ;
It returns the date and time ok.
But in the SP, the code:
SELECT FEC_DSD_ATN, FEC_HST_ATN, NOM_SEM_DSD_ATN, NOM_SEM_HST_ATN,
TO_DATE(HOR_DSD_ATN ,'DD/MM/YYYY HH24:MI:SS') as HOR_DSD_ATN,
TO_DATE(HOR_HST_ATN,'DD/MM/YYYY HH24:MI:SS') as HOR_HST_ATN
returns just the date ok but the time is 00:00
If I try the select in the SP with TO_CHAR as in:
SELECT FEC_DSD_ATN, FEC_HST_ATN, NOM_SEM_DSD_ATN, NOM_SEM_HST_ATN,
TO_CHAR(HOR_DSD_ATN ,'YYYY/MM/DD HH24:MI:SS') as HOR_DSD_ATN,
TO_CHAR(HOR_HST_ATN,'YYYY/MM/DD HH24:MI:SS') as HOR_HST_ATN
I get the error: SQLCODE: -6502 SQLERRM: ORA-06502: PL/SQL: error ...
Any clues ? BTW I must use a SP to retrieve this value.
Update: the column is type date. Here's the full SP:
FUNCTION FN_AAM_EV_RSTCN (
I_NUM_CONTRATO IN AAM0_DT_RSTCN.NUM_CONTRATO%TYPE,
I_COD_PFL IN AAM0_DT_RSTCN.COD_PFL%TYPE,
I_COD_APL_PFM IN AAM0_DT_RSTCN.COD_APL_PFM%TYPE,
I_COD_PTO IN AAM0_DT_RSTCN.COD_PTO%TYPE,
I_COD_FNC IN AAM0_DT_RSTCN.COD_FNC%TYPE
) RETURN BOOLEAN
AS
T_FEC_DSD_ATN AAM0_DT_RSTCN.FEC_DSD_ATN%TYPE;
T_HOR_DSD_ATN AAM0_DT_RSTCN.HOR_DSD_ATN%TYPE;
T_FEC_HST_ATN AAM0_DT_RSTCN.FEC_HST_ATN%TYPE;
T_HOR_HST_ATN AAM0_DT_RSTCN.HOR_HST_ATN%TYPE;
T_NOM_SEM_DSD_ATN AAM0_DT_RSTCN.NOM_SEM_DSD_ATN%TYPE;
T_NOM_SEM_HST_ATN AAM0_DT_RSTCN.NOM_SEM_HST_ATN%TYPE;
O_RESULTSET2 REST_REFCUR;
BEGIN
OPEN O_RESULTSET2 FOR
SELECT FEC_DSD_ATN, FEC_HST_ATN, NOM_SEM_DSD_ATN, NOM_SEM_HST_ATN,
TO_CHAR(HOR_DSD_ATN ,'DD/MM/YYYY HH24:MI:SS') as HOR_DSD_ATN,
TO_CHAR(HOR_HST_ATN,'DD/MM/YYYY HH24:MI:SS') as HOR_HST_ATN
FROM AAM0_DT_RSTCN
WHERE ROWNUM <=1
AND NUM_CONTRATO = NVL ( I_NUM_CONTRATO, NUM_CONTRATO )
AND COD_PFL = NVL ( I_COD_PFL, COD_PFL )
AND COD_APL_PFM = NVL ( I_COD_APL_PFM, COD_APL_PFM )
AND COD_PTO = NVL ( I_COD_PTO, COD_PTO )
AND COD_FNC = NVL ( I_COD_FNC, COD_FNC )
AND FLG_RCS = 'D'
AND COD_TPO_CDC = 'PC'
;
FETCH O_RESULTSET2 INTO T_FEC_DSD_ATN, T_FEC_HST_ATN, T_NOM_SEM_DSD_ATN, T_NOM_SEM_HST_ATN, T_HOR_DSD_ATN, T_HOR_HST_ATN ;
IF (O_RESULTSET2%NOTFOUND) THEN
RETURN TRUE;
ELSE
dbms_output.put_line('EVALUO RESTRICCIONES: T_FEC_DSD_ATN ' || T_FEC_DSD_ATN || ' T_FEC_HST_ATN : ' || T_FEC_HST_ATN || ' T_NOM_SEM_DSD_ATN: ' ||
T_NOM_SEM_DSD_ATN || ' T_NOM_SEM_HST_ATN: ' || T_NOM_SEM_HST_ATN || ' T_HOR_DSD_ATN: ' || TO_CHAR(T_HOR_DSD_ATN ,'DD/MM/YYYY HH24:MI:SS') ||
' T_HOR_HST_ATN: ' || TO_CHAR(T_HOR_HST_ATN ,'DD/MM/YYYY HH24:MI:SS') );
IF (NOT((T_FEC_DSD_ATN IS NULL) and (T_FEC_HST_ATN IS NULL)) ) THEN
IF ( NOT ((T_FEC_DSD_ATN <= SYSDATE) AND (T_FEC_HST_ATN >= SYSDATE ))) THEN
RETURN FALSE;
END IF ;
END IF ;
RETURN TRUE;
END IF ;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN TRUE;
WHEN OTHERS THEN
IF O_RESULTSET2%ISOPEN THEN
CLOSE O_RESULTSET2;
END IF;
DBMS_OUTPUT.PUT_LINE('ERROR en FN_AAM_EV_RSTCN : ');
DBMS_OUTPUT.PUT_LINE(' SQLCODE: ' || SQLCODE );
DBMS_OUTPUT.PUT_LINE(' SQLERRM: ' || SQLERRM );
ROLLBACK;
END FN_AAM_EV_RSTCN;
Your problem lies with the following code:
...
T_HOR_DSD_ATN AAM0_DT_RSTCN.HOR_DSD_ATN%TYPE;
T_HOR_HST_ATN AAM0_DT_RSTCN.HOR_HST_ATN%TYPE;
...
SELECT FEC_DSD_ATN, FEC_HST_ATN, NOM_SEM_DSD_ATN, NOM_SEM_HST_ATN,
TO_CHAR(HOR_DSD_ATN ,'DD/MM/YYYY HH24:MI:SS') as HOR_DSD_ATN,
TO_CHAR(HOR_HST_ATN,'DD/MM/YYYY HH24:MI:SS') as HOR_HST_ATN
FROM AAM0_DT_RSTCN
...
FETCH O_RESULTSET2 INTO T_FEC_DSD_ATN, T_FEC_HST_ATN, T_NOM_SEM_DSD_ATN,
T_NOM_SEM_HST_ATN, T_HOR_DSD_ATN, T_HOR_HST_ATN ;
Since the HOR_DSD_ATN and HOR_HST_ATN columns have the DATE data type, your local variables (T_HOR_DSD_ATN and T_HOR_HST_ATN) are also DATEs. However, in your SELECT you are converting these dates to strings with the TO_CHAR function. Therefore, your fetch is effectively doing this (I've made up some dates here):
T_HOR_DSD_ATN := '03/02/2010 09:33:30';
T_HOR_HST_ATN := '01/01/2010 12:30:00';
Since you are assigning a string to a date variable, Oracle must do an implicit TO_DATE - therefore it is using the session's NLS_DATE_FORMAT to convert them, which probably just gets the date portion (e.g. DD/MM/YYYY) and loses the time values.
To fix it, just remove the TO_CHAR()s from your SELECT statement - that way you will get dates + time values unmodified into your local variables.
Since the TO_DATE function takes a VARCHAR as argument, you wouldn't use this function on a DATE field. If you want to retrieve both the date and the time from a DATE field you would just SELECT the fields without functions:
SELECT FEC_DSD_ATN, FEC_HST_ATN, NOM_SEM_DSD_ATN, NOM_SEM_HST_ATN,
HOR_DSD_ATN, HOR_HST_ATN
...
update
The problem is that you are fetching TO_CHAR(HOR_DSD_ATN, 'DD/MM/YYYY HH24:MI:SS') into a DATE field. There is an implicit conversion that truncates your date. Use to_char on a DATE variable and use to_date on a CHAR variable.
My suggestion:
FUNCTION FN_AAM_EV_RSTCN(I_NUM_CONTRATO IN AAM0_DT_RSTCN.NUM_CONTRATO%TYPE,
I_COD_PFL IN AAM0_DT_RSTCN.COD_PFL%TYPE,
I_COD_APL_PFM IN AAM0_DT_RSTCN.COD_APL_PFM%TYPE,
I_COD_PTO IN AAM0_DT_RSTCN.COD_PTO%TYPE,
I_COD_FNC IN AAM0_DT_RSTCN.COD_FNC%TYPE)
RETURN BOOLEAN AS
BEGIN
FOR cc IN (SELECT FEC_DSD_ATN, FEC_HST_ATN, NOM_SEM_DSD_ATN,
NOM_SEM_HST_ATN, HOR_DSD_ATN, HOR_HST_ATN
FROM AAM0_DT_RSTCN
WHERE ROWNUM <= 1
AND NUM_CONTRATO = NVL(I_NUM_CONTRATO, NUM_CONTRATO)
AND COD_PFL = NVL(I_COD_PFL, COD_PFL)
AND COD_APL_PFM = NVL(I_COD_APL_PFM, COD_APL_PFM)
AND COD_PTO = NVL(I_COD_PTO, COD_PTO)
AND COD_FNC = NVL(I_COD_FNC, COD_FNC)
AND FLG_RCS = 'D'
AND COD_TPO_CDC = 'PC') LOOP
dbms_output.put_line(' T_HOR_DSD_ATN: ' ||
TO_CHAR(cc.HOR_DSD_ATN, 'DD/MM/YYYY HH24:MI:SS') ||
' T_HOR_HST_ATN: ' ||
TO_CHAR(cc.HOR_HST_ATN, 'DD/MM/YYYY HH24:MI:SS'));
-- your logic with return boolean
END LOOP;
-- no rows found
RETURN TRUE;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR en FN_AAM_EV_RSTCN : ');
DBMS_OUTPUT.PUT_LINE(' SQLCODE: ' || SQLCODE);
DBMS_OUTPUT.PUT_LINE(' SQLERRM: ' || SQLERRM);
RAISE;
END FN_AAM_EV_RSTCN;
If HOR_HST_ATN is a date column then TO_DATE(HOR_HST_ATN,'DD/MM/YYYY HH24:MI:SS') must be a typo. You probably mean TO_CHAR().
If the columns were populated by dates without a time element Oracle defaults the time to midnight...
SQL> create table t23 (d date)
2 /
Table created.
SQL> insert into t23 values (sysdate)
2 /
1 row created.
SQL> insert into t23 values (to_date('03-FEB-2010', 'DD-MON-YYYY'))
2 /
1 row created.
SQL> select to_char(d, 'DD/MM/YYYY HH24:MI:SS') as datetime from t23
2 /
DATETIME
-------------------
02/02/2010 17:59:51
03/02/2010 00:00:00
SQL>

Resources