I'm trying to convert a VARCHAR2 variable which contains a timestamp w/ time zone into a DATE variable. I can convert the timestamp without the time zone but when I add logic for timezone I get "ORA-01821: date format not recognized". Please see code below:
DECLARE
v_string VARCHAR2(400) := '2011-05-12 19:04:41.032645 +00:00';
v_date DATE;
BEGIN
SELECT to_timestamp(v_string,'YYYY-MM-DD HH24:MI:SSxFF TZH:TZM')
INTO v_date
FROM dual;
END;
Use TO_TIMESTAMP_TZ:
SQL> DECLARE
2 v_string VARCHAR2(400) := '2011-05-12 19:04:41.032645 +00:00';
3 v_date DATE;
4 BEGIN
5 v_date := to_timestamp_tz(v_string, 'YYYY-MM-DD HH24:MI:SS.FF TZH:TZM');
6 END;
7 /
PL/SQL procedure successfully completed
Related
Morning All, Hopefully someone can help. I'm an MSSQL specialist and have very little experience of Oracle PL/SQL. I've been asked to write an Oracle Stored Procedure which gets specific fields from the latest Monthly audit table. This is what I've come up with but it doesn't seem to run or output anywhere.
Can someone help?
CREATE OR REPLACE PROCEDURE GetLatestMonthAuditTable
AS
BEGIN
DECLARE
v_lastmonth date := interval '-1' month +systimestamp;
v_year varchar2(4) := extract(year from v_lastmonth);
v_month varchar2(2) := extract(month from v_lastmonth);
v_day varchar2(2) := extract(day from LAST_DAY(v_lastMonth));
v_sql varchar2(256) := 'SELECT ACT_CODE, CHANGE_BY, CHANGE_DATE FROM AUDIT_' || v_year || v_month || v_day;
BEGIN
EXECUTE IMMEDIATE v_sql;
END;
END;
You didn't actually run it - you just created a procedure.
Could've been like this:
Sample table:
SQL> CREATE TABLE AUDIT_20211031
2 AS
3 SELECT 1 act_code, 'Littlefoot' change_by, SYSDATE change_date FROM DUAL;
Table created.
Procedure (it is a good habit to display statement you'll run using dbms_output.put_line; once you make sure it is OK, remove that line):
SQL> CREATE OR REPLACE PROCEDURE GetLatestMonthAuditTable
2 AS
3 v_lastmonth DATE := INTERVAL '-1' MONTH + SYSTIMESTAMP;
4 v_year VARCHAR2 (4) := EXTRACT (YEAR FROM v_lastmonth);
5 v_month VARCHAR2 (2) := EXTRACT (MONTH FROM v_lastmonth);
6 v_day VARCHAR2 (2) := EXTRACT (DAY FROM LAST_DAY (v_lastMonth));
7 v_sql VARCHAR2 (200);
8 BEGIN
9 v_sql :=
10 'SELECT ACT_CODE, CHANGE_BY, CHANGE_DATE FROM AUDIT_'
11 || v_year
12 || v_month
13 || v_day;
14
15 DBMS_OUTPUT.put_line (v_sql);
16
17 EXECUTE IMMEDIATE v_sql;
18 END;
19 /
Procedure created.
Testing:
SQL> SET SERVEROUTPUT ON
SQL>
SQL> BEGIN
2 GetLatestMonthAuditTable;
3 END;
4 /
SELECT ACT_CODE, CHANGE_BY, CHANGE_DATE FROM AUDIT_20211031
PL/SQL procedure successfully completed.
SQL>
Now, your procedure doesn't do anything - it runs that select, but it isn't displayed anywhere on the screen.
If it were a function instead, you could return ref cursor and see something. For example:
SQL> CREATE OR REPLACE FUNCTION GetLatestMonthAuditTable
2 RETURN SYS_REFCURSOR
3 AS
4 v_lastmonth DATE := INTERVAL '-1' MONTH + SYSTIMESTAMP;
5 v_year VARCHAR2 (4) := EXTRACT (YEAR FROM v_lastmonth);
6 v_month VARCHAR2 (2) := EXTRACT (MONTH FROM v_lastmonth);
7 v_day VARCHAR2 (2) := EXTRACT (DAY FROM LAST_DAY (v_lastMonth));
8 v_sql VARCHAR2 (200);
9 rc SYS_REFCURSOR;
10 BEGIN
11 v_sql :=
12 'SELECT ACT_CODE, CHANGE_BY, CHANGE_DATE FROM AUDIT_'
13 || v_year
14 || v_month
15 || v_day;
16
17 OPEN rc FOR v_sql;
18
19 RETURN rc;
20 END;
21 /
Function created.
Testing the function:
SQL> SELECT GetLatestMonthAuditTable FROM DUAL;
GETLATESTMONTHAUDITT
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
ACT_CODE CHANGE_BY CHANGE_DATE
---------- ---------- -------------------
1 Littlefoot 16.11.2021 12:14:18
SQL>
I am having a Procedure , which is accepting fromDate and toDate input parameters I need to set default values as First date of Last month and last date of previous month respectively. I am trying to use below code, but still proper default dates are not being set. Please let me know if below code is valid or i can do something to correct it:
create or replace PROCEDURE "TEST"
(
fromdate_in IN varchar2,
todate_in IN varchar2,
type_in IN number DEFAULT 01
)
is
V_date varchar2(3000);
begin
select to_date(fromdate_in) into V_date from dual; -- Correct date entered
Exception WHEN Others THEN
select to_char(trunc(trunc(sysdate, 'MM') - 1, 'MM'),'DD/MM/RRRR') into V_date from dual; -- if fromdate_in --is null then set V_date to first date of Previous month
-- calculations using V_date
end TEST;
Please note , I have shown only how I am setting first date of Previous month to From Date for simplicity.
If you want to set a default value for a parameter, do so as in this example:
SQL> create or replace procedure p_test
2 (fromdate_in in varchar2
3 default to_char(trunc(add_months(sysdate, -1), 'mm'), 'dd/mm/rrrr'))
4 is
5 begin
6 dbms_output.put_Line('fromdate_in = ' || fromdate_in);
7 end;
8 /
Procedure created.
As you wanted, its default value is the first day of the previous month. Works like this:
SQL> set serveroutput on;
SQL> exec p_test;
fromdate_in = 01/08/2018
PL/SQL procedure successfully completed.
SQL> exec p_test('24/09/2018');
fromdate_in = 24/09/2018
PL/SQL procedure successfully completed.
SQL>
Note that you should really consider switching to DATE datatype parameter instead of VARCHAR2 - you're dealing with dates anyway, so - why bother with invalid values passed to the procedure? If it is a string, what will prevent someone from passing e.g. '99/66/x-FZ' to the procedure? Now you have to worry about it, write exception handler ... everything because you didn't set parameters' datatype to DATE.
You could do it much easier like this:
create or replace PROCEDURE "TEST"
(
fromdate_in IN DATE,
todate_in IN DATE,
type_in IN number DEFAULT 1
)
is
V_date DATE;
begin
V_date := NVL(fromdate_in, TRUNC(ADD_MONTHS(SYSDATE, -1), 'MM'));
-- calculations using V_date
end TEST;
If you are forced to use VARCHAR2 for fromdate_in then convert the value to DATE:
V_date := NVL(TO_DATE(fromdate_in, 'DD/MM/YYYY'), TRUNC(ADD_MONTHS(SYSDATE, -1), 'MM'));
User give any date format value ,
Select To_Date('20-11-2014','yyyy-mm-dd') From Dual ;
(or)
Select To_Date('2014-11-28','yyyy-mm-dd') From Dual ;
But we want to convert into single format(this format)
select to_char(to_date(trunc(datereceipt), 'DD-MM-YYYY'), 'yyyy-mm-dd') from vttrcwfheggrecivdlot
datereceipt := '20-11-2014';
(this format is ok for above query)
but
datereceipt := '2014-11-28';
(For using this format want to convert the date format in datediff function all operation are performing in runtime)
If there are just this two date format, this works:
select decode(instr(:datereceipt, '-'), 3, to_char(to_date(:datereceipt, 'DD-MM-YYYY'), 'yyyy-mm-dd'), :datereceipt)
from dual
or if you want them as dates
select decode(instr(:datereceipt, '-'), 3, to_date(:datereceipt, 'DD-MM-YYYY'), to_date(:datereceipt, 'yyyy-mm-dd'))
from dual
You may need to accept date inputs (strings) in different formats, but you just need to convert them to dates, not to a formatted string. A function like this can be used:
function my_to_date (p_str varchar2) return date
is
begin
return to_date (p_str, 'DD/MM/YYYY');
exception
when others then
return to_date (p_str, 'YYYY-MM-DD');
end;
Test:
SQL> alter session set nls_date_format = 'YYYY-MM-DD';
Session altered.
SQL> declare
2 function my_to_date (p_str varchar2) return date
3 is
4 begin
5 return to_date (p_str, 'DD/MM/YYYY');
6 exception
7 when others then
8 return to_date (p_str, 'YYYY-MM-DD');
9 end;
10 begin
11 dbms_output.put_line(my_to_date('29-DEC-1999'));
12 dbms_output.put_line(my_to_date('30/12/1999'));
13 dbms_output.put_line(my_to_date('1999-12-31'));
14 end;
15 /
1999-12-29
1999-12-30
1999-12-31
PL/SQL procedure successfully completed.
It might be a silly problem but I cant find a solution with "DATE" type passed in a PL/SQL proc which is called dynamically. What I need is to pass both date and time parts in the called proc:
create or replace
PROCEDURE DATE_TIME_TEST ( dte_Date_IN IN DATE )
IS
vch_SQL_Stmnt VARCHAR2(2000);
BEGIN
DBMS_OUTPUT.PUT_LINE('Date is :'||TO_CHAR(dte_Date_IN, 'DD-Mon-YYYY HH24:MI:SS'));
END;
/
declare
v_sql varchar2(2000);
begin
v_sql := 'begin DATE_TIME_TEST( dte_Date_IN => '''||
sysdate || ''''|| '); end;';
execute immediate v_sql;
end;
/
The output here is - Date is :27-Aug-2013 00:00:00.
I want it to be - Date is :27-Aug-2013 13:01:09
Use bind variables
SQL> create or replace procedure proc( p_dt in date )
2 as
3 begin
4 dbms_output.put_line( to_char( p_dt, 'yyyy-mm-dd hh24:mi:ss' ));
5 end;
6 /
Procedure created.
SQL> declare
2 l_sql varchar2(1000);
3 begin
4 l_sql := 'begin proc(:dt); end;';
5 execute immediate l_sql using sysdate;
6 end;
7 /
2013-08-26 22:14:26
PL/SQL procedure successfully completed.
The problem with your code is that in order to build up your string, Oracle has to convert the DATE to a VARCHAR2. It does that using your session's NLS_DATE_FORMAT. But your session's NLS_DATE_FORMAT probably doesn't include the time component so the time is lost when your procedure is actually called. Using bind variables means that you don't have to deal with that sort of implicit conversion (it is also more efficient and more secure).
If you really wanted to avoid using bind variables, you could explicitly cast sysdate to a string using a to_char and then put a to_date in the dynamic procedure call. But that's a lot of extra code and a number of unnecessary conversions.
SQL> ed
Wrote file afiedt.buf
1 declare
2 l_sql varchar2(1000);
3 begin
4 l_sql := q'{begin proc(to_date('}' ||
5 to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss') ||
6 q'{', 'yyyy-mm-dd hh24:mi:ss')); end;}';
7 execute immediate l_sql;
8* end;
SQL> /
2013-08-26 22:19:52
PL/SQL procedure successfully completed.
I must write a procedure which save the execute time of any sql-statement in a table.
The procedure is calling by exec measuresqltime('sql statement as string');
My idea is like this:
--declarations
timestart NUMBER;
BEGIN
dbms_output.enable;
timestart:=dbms_utility.get_time();
EXECUTE IMMEDIATE sql
COMMIT;
dbms_output.put_line(dbms_utility.get_time()-timestart);
-- save time
But it didn't work for me for a SELECT *... clause. (I think sql need a INTO-order)
Is there a way to execute any sql-atatements in a procedure?
If your SQL statement is a SELECT, you need to fetch from the cursor to have a meaningful measure of its execution time.
If you don't fetch from the cursor, you only measure the time spent in "parse" and "execution" phases, whereas much of the work is usually done in the "fetch" phase for SELECT statements.
You won't be able to fetch with EXECUTE IMMEDIATE or OPEN cursor FOR 'string' if you don't know the number of columns the actual statement will have. You will have to use the dynamic SQL package DBMS_SQL if the number/type of columns of the SELECT is unknown.
Here's an example:
SQL> CREATE OR REPLACE PROCEDURE demo(p_sql IN VARCHAR2) AS
2 l_cursor INTEGER;
3 l_dummy NUMBER;
4 timestart NUMBER;
5 BEGIN
6 dbms_output.enable;
7 timestart := dbms_utility.get_time();
8 l_cursor := dbms_sql.open_cursor;
9 dbms_sql.parse(l_cursor, p_sql, dbms_sql.native);
10 l_dummy := dbms_sql.execute(l_cursor);
11 LOOP
12 EXIT WHEN dbms_sql.fetch_rows(l_cursor) <= 0;
13 END LOOP;
14 dbms_sql.close_cursor(l_cursor);
15 dbms_output.put_line(dbms_utility.get_time() - timestart);
16 END;
17 /
Procedure created.
SQL> exec demo('SELECT * FROM dual CONNECT BY LEVEL <= 1e6');
744
PL/SQL procedure successfully completed.
Note that this will measure the time needed to fetch to the last row of the SELECT.
completing devosJava answered... avoid using it at dawn ;P
PROCEDURE MY_PROCEDURE IS
timeStart TIMESTAMP;
timeEnd TIMESTAMP;
timeSecond NUMBER
BEGIN
timeStart := SYSTIMESTAMP;
-- YOUR CODE HERE
timeEnd := SYSTIMESTAMP;
timeSecond :=((extract(hour from timeEnd)*3600)+(extract(minute from timeEnd)*60)+extract(second from timeEnd))-((extract(hour from timeStart)*3600)+(extract(minute from timeStart)*60)+extract(second from timeStart));
dbms_output.put_line('finished: '||timeSecond||' seconds');
END MY_PROC;
To calculate the duration for an execution time
PROCEDURE MY_PROCEDURE IS
timeStart TIMESTAMP;
timeEnd TIMESTAMP;
BEGIN
timeStart := SYSTIMESTAMP;
-- YOUR CODE HERE
timeEnd := SYSTIMESTAMP;
INSERT INTO PROC_RUNTIMES (PROC_NAME, START_TIME, END_TIME)
VALUES ('MY_PROCEDURE ', timeStart , timeEnd );
END MY_PROC;
INSERT INTO PROC_RUNTIMES (PROC_NAME, START_TIME, END_TIME)
VALUES ('PROC_NAME', TO_CHAR
(SYSDATE, 'DD/MM/YYYY HH24:MI:SS'),NULL );
Your query here;
INSERT INTO PROC_RUNTIMES (PROC_NAME, START_TIME, END_TIME)
VALUES ('PROC_NAME',NULL, TO_CHAR
(SYSDATE, 'DD/MM/YYYY HH24:MI:SS'));