You do not need dynamic SQL, if your procedure is expecting a date:
CREATE PACKAGE pkg AS
PROCEDURE other_procedure ( p_date IN DATE );
END;
/
CREATE PACKAGE BODY pkg AS
PROCEDURE other_procedure ( p_date IN DATE )
IS
BEGIN
DBMS_OUTPUT.PUT_LINE(TO_CHAR(p_date, 'YYYY-MM-DD HH24:MI:SS'));
END;
END;
/
Then pass a date (and not a query):
DECLARE
v_month PLS_INTEGER := 2;
BEGIN
Pkg.other_procedure(
p_date => ADD_MONTHS(TRUNC(SYSDATE, 'YY'), v_month - 1)
);
END;
/
or:
DECLARE
v_month DATE := TO_DATE(
'01-feb-' || EXTRACT(YEAR FROM SYSDATE),
'DD-MON-YYYY',
'NLS_DATE_LANGUAGE=English'
);
BEGIN
Pkg.other_procedure(
p_date => v_month
);
END;
/
If you do want to use a dynamic SQL statement then use bind variables:
DECLARE
V_first_day DATE := TO_DATE(
'01-feb-' || EXTRACT(YEAR FROM SYSDATE),
'DD-MON-YYYY',
'NLS_DATE_LANGUAGE=English'
);
V_sql VARCHAR2(1000) := 'select :1 from dual';
v_date DATE;
BEGIN
EXECUTE IMMEDIATE v_sql INTO v_date USING v_first_day;
Pkg.other_procedure( p_date => v_date );
END;
/
If you really do want to pass a dynamic query (don't, it opens your code up to SQL injection attacks):
CREATE OR REPLACE PACKAGE pkg AS
PROCEDURE other_procedure (
p_sql IN VARCHAR2
);
END;
/
CREATE OR REPLACE PACKAGE BODY pkg AS
PROCEDURE other_procedure (
p_sql IN VARCHAR2
) IS
v_date DATE;
BEGIN
EXECUTE IMMEDIATE p_sql INTO v_date;
DBMS_OUTPUT.PUT_LINE(TO_CHAR(v_date, 'YYYY-MM-DD HH24:MI:SS'));
END;
END;
/
Then convert the date to a string using TO_CHAR
and embed it into the dynamic SQL where you can convert it back to a date using TO_DATE
:
DECLARE
V_first_day DATE := TO_DATE(
'01-feb-' || EXTRACT(YEAR FROM SYSDATE),
'DD-MON-YYYY',
'NLS_DATE_LANGUAGE=English'
);
V_sql VARCHAR2(1000) := q'[select TO_DATE(']'
|| TO_CHAR(v_first_day, 'YYYY-MM-DD HH24:MI:SS')
|| q'[', 'YYYY-MM-DD HH24:MI:SS') from dual]';
BEGIN
Pkg.other_procedure( p_sql => v_sql );
END;
/
fiddle