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>
Related
I have a problematic SQL Sentence, when it runs
SELECT code, my_date, my_time
FROM my_table
WHERE to_date(to_char(my_date, 'YYYY-MM-DD') || ' ' || my_time, 'YYYY-MM-DD HH24:MI:SS') > sysdate - 5
I always get: ORA-01841: (full) year must be between -4713 and +9999, and not be 0
This is the definition of my table:
CREATE TABLE my_table (code NUMBER(10), my_date DATE, my_time VARCHAR2(8));
ALTER TABLE my_table ADD CONSTRAINT pk_my_table PRIMARY KEY (code);
CREATE INDEX i_my_table_001 ON my_table (my_date);
But If I add an extra restriction, I never get the error:
SELECT code, my_date, my_time
FROM my_table
WHERE my_date > trunc(sysdate - 5)
AND to_date(to_char(my_date, 'YYYY-MM-DD') || ' ' || my_time, 'YYYY-MM-DD HH24:MI:SS') > sysdate - 5
All validations are ok. Not invalid dates, not invalid times
Is there any way to find which is the 'offending' record?
Brute force is not an option because table has more than 25M records.
If you are on Oracle 12.2 or higher, you can use the VALIDATE_CONVERSION function to see which rows could be giving you an error.
Example Query
WITH
my_table (code, my_date, my_time)
AS
(SELECT 1, date '2020-01-01', '08:00:00' FROM DUAL
UNION ALL
SELECT 2, date '2020-01-31', '25:00:00' FROM DUAL)
SELECT *
FROM my_table
WHERE validate_conversion (to_char(my_date, 'YYYY-MM-DD') || ' ' || my_time AS DATE, 'YYYY-MM-DD HH24:MI:SS') = 0;
Result
CODE MY_DATE MY_TIME
_______ ______________ ___________
2 2020-01-31 25:00:00
Update
One update that may be a bit easier than cloning your database and upgrading is to create your own function to validate the date and call that from a test SQL statement like the on below. I'm not sure if defining a function within a common table expression is supported in 12.1, but if it is not, you can make it a standalone function and call that from your query.
WITH
FUNCTION validate_date (p_date DATE, p_time VARCHAR2)
RETURN NUMBER
AS
l_test_date DATE;
BEGIN
l_test_date :=
TO_DATE (TO_CHAR (p_date, 'YYYY-MM-DD') || ' ' || p_time, 'YYYY-MM-DD HH24:MI:SS');
RETURN 1;
EXCEPTION
WHEN OTHERS
THEN
RETURN 0;
END;
SELECT *
FROM (SELECT 1 AS code, DATE '2020-01-01' AS my_date, '08:00:00' AS my_time FROM DUAL
UNION ALL
SELECT 2, DATE '2020-01-31', '25:00:00' FROM DUAL) my_table
WHERE validate_date (my_date, my_time) = 0;
Trying to create a procedure that changes dates when the end date is less than sysdate, but it changes all the dates, so here is the code:
CREATE OR REPLACE PROCEDURE CHANGE_DATES
as
BEGIN
FOR rec IN (SELECT start_period_date,end_period_date FROM mytable) LOOP
DBMS_OUTPUT.PUT_LINE('Old Date:' || rec.start_period_date ||' ' || rec.end_period_date);
IF rec.end_period_date < sysdate THEN
update mytable set start_period_date = sysdate;
update mytable set end_period_date = sysdate + 6;
commit;
--DBMS_OUTPUT.PUT_LINE('New Date:' || begin_date ||' ' ||end_date);
end if;
END LOOP;
END;
You need a WHERE clause (and you can do it all in one UPDATE statement):
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE mytable ( start_period_date, end_period_date ) AS
SELECT DATE '2018-01-01', DATE '2018-01-02' FROM DUAL
/
CREATE OR REPLACE PROCEDURE CHANGE_DATES
AS
start_dates SYS.ODCIDATELIST;
end_dates SYS.ODCIDATELIST;
BEGIN
UPDATE ( SELECT m.*,
( SELECT m.start_period_date FROM DUAL ) AS old_start_date,
( SELECT m.end_period_date FROM DUAL ) AS old_end_date
FROM mytable m )
SET start_period_date = SYSDATE,
end_period_date = SYSDATE + INTERVAL '6' DAY
WHERE end_period_date < SYSDATE
RETURNING old_start_date, old_end_date
BULK COLLECT INTO start_dates, end_dates;
FOR i IN 1 .. start_dates.COUNT LOOP
DBMS_OUTPUT.PUT_LINE( 'Old Date:' || start_dates(i) ||' ' || end_dates(i) );
END LOOP;
-- Do not COMMIT in the procedure, COMMIT in the calling scope.
END;
/
Query 1:
BEGIN
CHANGE_DATES;
COMMIT;
END;
Query 2:
SELECT * FROM mytable
Results:
| START_PERIOD_DATE | END_PERIOD_DATE |
|----------------------|----------------------|
| 2018-05-21T09:06:05Z | 2018-05-27T09:06:05Z |
ORACLE (using SQL DEVELOPER).
I need to properly structure EXECUTE IMMEDIATE statement.
I do not have "create" priveleges. The task is to get number of rows per table per date for dynamic list of tables/dates.
I have the following:
DECLARE CURSOR cur_table_name IS SELECT TABLE_NAME
FROM ALL_TABLES WHERE TABLE_NAME IN ('table_a', 'table_b', 'table_c');
CURSOR cur_BEGIN_DATE IS
select to_date('2014-09-25 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + rownum -1 AS BEGIN_DATE,
to_date('2014-09-26 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + rownum -1 AS END_DATE from dual
Connect by level <= to_date('2014-09-30 00:00:00', 'YYYY-MM-DD HH24:MI:SS') - to_date('2014-09-25 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + 1;
var_total_rows NUMBER(15);
var_table_name VARCHAR2 (50);
var_bgn_date DATE;
var_end_date DATE;
BEGIN
OPEN cur_TABLE_NAME;
LOOP
FETCH cur_TABLE_NAME INTO var_table_name;
EXIT WHEN cur_TABLE_NAME%NOTFOUND;
--testing output
DBMS_OUTPUT.PUT_LINE ('Table: '|| var_table_name);
var_total_rows :=0;
OPEN cur_BEGIN_DATE;
LOOP
FETCH cur_BEGIN_DATE INTO var_bgn_date, var_end_date;
EXIT WHEN cur_BEGIN_DATE%NOTFOUND;
--TESTING OUTPUT
DBMS_OUTPUT.PUT_LINE ('DATES ARE: ' || var_bgn_date || ', ' ||var_end_date|| ' Table IS: '||var_table_name);
--------THIS IS THE NOT WORKING STATEMENT DUE TO VARIABLES IN THE WHERE STATEMENT:
execute immediate 'SELECT COUNT(*) FROM '||var_table_name || ' where DTM >= '|| var_bgn_date ||' and DTM < '||var_end_date INTO var_total_rows;
DBMS_OUTPUT.PUT_LINE (var_table_name||' '||var_bgn_date||' '||var_end_date ||' '||var_total_rows);
END LOOP;
CLOSE cur_BEGIN_DATE;
END LOOP;
CLOSE cur_TABLE_NAME;
END;
If I remove the variables from the where statement (just do 'Select * from || var_table_name into var_total_rows; ) this works. And if there is a static value in the where clause - it works (but loops through with the same date and I need the changing dates!). But I cannot make the syntax to work for dynamic variables in the where clause.
Can this be done?
Appreciate your help!
Your var_bgn_date and var_end_date variables are of DATE type, but are being plugged into the dynamic statement as unquoted strings with implicit formatting based on the session NLS_DATE_FORMAT value. You'll get a generated statement like:
SELECT COUNT(*) FROM table_a where DTM >= 2014-09-25 00:00:00 and DTM < 2014-09-26 00:00:00
You could add escaped single quotes to turn that into a valid statement, still relying on implicit conversion back using the same NLS settings:
EXECUTE immediate 'SELECT COUNT(*) FROM '||var_table_name
|| ' where DTM >= '''|| var_bgn_date ||''' and DTM < '''||var_end_date ||''''
INTO var_total_rows;
which would generate:
SELECT COUNT(*) FROM table_a where DTM >= '2014-09-25 00:00:00' and DTM < '2014-09-26 00:00:00'
But really you should use bind variables to avoid any conversion to or from strings:
EXECUTE immediate 'SELECT COUNT(*) FROM '||var_table_name
|| ' where DTM >= :bgn_date and DTM < :end_date'
INTO var_total_rows
USING var_bgn_date, var_end_date;
Here is my code:
create or replace
procedure date_report (start_date timestamp , end_date timestamp )
is
cursor cursor_audit is
select audit_id, audit_action, audit_user, audit_date
from customer_audit
where audit_date between start_date and end_date
;
rec cursor_audit%rowtype;
begin
open cursor_audit;
fetch cursor_audit into rec;
while cursor_audit%found
loop
dbms_output.put_line('User : ' || rec.audit_user
|| ', ID :' || rec.audit_id
|| ', Action: ' || rec.audit_action
|| ', Date : ' || rec.audit_date );
fetch cursor_audit into rec;
end loop;
close cursor_audit;
end;
I want to query all rows between specific dates but it seems to not report anything.
Not exactly what you were asking for, but worth mentioning: You can write better, i.e. more idiomatic PL/SQL like this:
create or replace
procedure date_report (start_date timestamp , end_date timestamp )
is
cursor cursor_audit is select audit_id, audit_action, audit_user, audit_date
from customer_audit
where audit_date between start_date and end_date
;
begin
for rec in cursor_audit
loop
dbms_output.put_line('User : '||rec.audit_user ||', ID :' ||rec.audit_id||', Action: '
|| rec.audit_action||', Date : ' ||rec.audit_date );
end loop;
end;
or even
procedure date_report (start_date timestamp , end_date timestamp )
is
begin
for rec in (select audit_id, audit_action, audit_user, audit_date
from customer_audit
where audit_date between start_date and end_date)
loop
dbms_output.put_line('User : '||rec.audit_user ||', ID :' ||rec.audit_id||', Action: '
|| rec.audit_action||', Date : ' ||rec.audit_date );
end loop;
end;
A possible cause for your problem is that you select e.g. 09-16-2010 to 09-16-2010, which means 09-16-2010 00:00:00 to 09-16-2010 00:00:00. To find all rows from 09-16-2010, you have to explicitely pass a time (or just add 1 to the end_date, which is sufficient in most cases)
Look and see if it is checked.
Firstly, it is advisable to prefix variables and parameters so they do not conflict with column names.
In your example, if "customer_audit" contained start_date and end_date columns then these would be used in preference over PL/SQL variables or parameters of the same name.
Secondly, the original title included "the-parameter-always-null". If the parameters are null then the condition will not be true and no rows will be returned.
If you want to cater for this, you need to code in some logic like:
> select audit_id, audit_action, audit_user, audit_date
> from customer_audit
> where (audit_date >= i_start_date or i_start_date is null)
> and (audit_date <= i_end_date or i_end_date is null)
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