Oracle SYSDATE question for datetime column ORA 12899 - sql

I wrote a trigger in which I have a line:
SELECT *
INTO :NEW.EVENTDATE
FROM (SELECT SYSDATE
FROM DUAL);
For some reason this does not work (EVENTDATE column has timestamp(0) type).
When I try to insert something I get error message saying that value is too long for that column. I though SYSDATE and timestamp(0) would coalesce and understand each other.
What the ?

You should just do this in PL/SQL
:new.EventDate := SYSTIMESTAMP;
but if you want to use SQL
SELECT systimestamp
INTO :new.EventDate
FROM dual;

Try an explicit cast such as
select cast(sysdate as timestamp(0)) from dual
As a thought, is there anything exotic with your session's calendar settings which might force a unusual conversion. If so, try specifying the appropriate calendar in a conversion.
select to_char(sysdate,'DD-fmMonth-YYYY','nls_calendar=''Arabic Hijrah''') from dual;

I don't know why this wouldn't work. Can you post the actual error (with code and everything) that you are getting?
I also don't know why you wouldn't just assign the variable:
:NEW.EVENTDATE := systimestamp;

What version are you running?
The following works fine on Oracle 11R2:
drop table tq84_eventdate;
create table tq84_eventdate (
data varchar2(10),
eventdate timestamp(0)
);
create trigger tq84_eventdate_trg
before insert on tq84_eventdate
for each row
begin
SELECT * INTO :NEW.EVENTDATE FROM (SELECT SYSDATE FROM DUAL);
end tq84_eventdate_trg;
/
insert into tq84_eventdate (data) values ('test');
select * from tq84_eventdate;
However, if I do a
insert into tq84_eventdate (data) values ('value too large!');
I get the ORA-12899 you mentioned. So, the error is probably not related to the select statement you posted, but to the data that you actually try to insert.
Also, on a related note, you can assign sysdate directly in the trigger, that is without the indirection of a select statement:
create trigger tq84_eventdate_trg
before insert on tq84_eventdate
for each row
begin
:new.eventdate := sysdate;
end tq84_eventdate_trg;
/

I was able to exhort my bosses to convert one column's type to another. Namely timestamp to DATE.
Strangely enough nobody throughout this branch has not pointed out that I could substitute Timestamp field with DATE field.

Related

Oracle PL/SQL error - store procedure - ORA-00979 and ORA-06512

I am using following store procedure to insert data to a table.
create or replace PROCEDURE PM
(
date1 in varchar2
,date2 in varchar2
,date3 in varchar2
) AS
cursor cur_cd is
(
select to_date(date1,'DD-MON-YY') as date1
,trim(t.DEPT_CODE) DEPT_CODE
,count(t.DEPT_CODE) count_dept
,sum(t.amount) amount
from department t
where t.date >= to_date(date2,'DD-MON-YY')
and t.date <= to_date(date2,'DD-MON-YY')
and t.dept_name like 'finance%'
and (trim(t.DT_code)='TR_01' or t.DT_file like 'DTF_20%')
and t.DEPT_CODE not in ('HR','ADMIN','ACADEMIC')
group by t.DEPT_CODE
);
Type rec_set is table of dept_file%rowtype;
v_rec_set record_set;
begin
open cur_cd;
loop
fetch cur_cd
bulk collect into v_rec_set limit 100;
exit when v_rec_set.count()=0;
begin
forall i in v_rec_set.first..v_rec_set.last
insert into dept_file
values v_rec_set(i);
end;
end loop;
close cur_cd;
exception when others then raise;
end PM;
It's giving me a runtime error when execute procedure. But the query execute without error manually.
ORA-000979 : not a GROUP BY expression
ORA-006512 : at "ABS.PM", line 9
Also, when hard code the parameters (date1, date2 and date3) the procedure working without error.
Can you please help me to resolve this error?
All non-aggregated columns must be specified in the GROUP BY clause. Therefore:
GROUP BY TO_DATE (date1, 'DD-MON-YY'), TRIM (t.dept_code)
By the way, are you really storing date values as strings? Why do I ask? Because you're using TO_DATE functions all over the code. If you are, then try not to do it in the future. Oracle offers DATE datatype, you should use it.

How to print record that caused ORA-01843 error?

I have a table with millions of records. I am trying to format one column data to DATE format
which is currently in VARCHAR2. But, I am getting ORA-01843 not a valid month error.
I am trying to get those records which are causing ORA-01843
CREATE OR REPLACE PROCEDURE pr_TEST_CUSTOM_ORA1843 AS
v_company MyTable.MyColumn%TYPE;
BEGIN
BEGIN
SELECT to_char(to_date(TRIM(MyColumn), 'YYMMDD'), 'MM/DD/YYYY')
INTO v_company FROM MyTable;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ORA-01843 caused by'||v_company);
END;
END pr_TEST_CUSTOM_ORA1843;
But, the value of v_company is not printed.
How to get the records which are causing ORA-01843 error?
I just commented on your previous question : How to format only those records for which ORA-01843 is not thrown? but you did not pay attention to it.
Create a function which checks if it is a valid date like this.
CREATE OR REPLACE FUNCTION validmmddyyyy (p_str IN VARCHAR2)
RETURN NUMBER
AS
V_date DATE;
BEGIN
V_Date := TO_DATE (p_str, 'MM/DD/YYYY');
RETURN 1;
EXCEPTION
WHEN OTHERS
THEN
RETURN 0;
END;
Then, to select the records which fail, you can run a query
select MyColumn FROM MyTable where validmmddyyyy(MyColumn) = 0
When you are lucky enough to use Oracle 12c R2, you could make use of DEFAULT..ON..CONVERSION ERROR clause of TO_DATE
SELECT *
FROM MyTable
WHERE TO_DATE (MyColumn default null on conversion error,'MM/DD/YYYY') IS NULL
An important advice as always, don't use a VARCHAR2 / CHAR type for DATEs in database.

Wrong date format for input parameter?

CREATE OR REPLACE PROCEDURE PROC1(
V_STARTTIME IN DATE,
V_ENDTIME IN DATE)
BEGIN
INSERT INTO TAB1
SELECT COINS FROM TAB2
WHERE DATE BETWEEN TO_DATE(V_STARTTIME,'MM/DD/YYYY') AND TO_DATE(V_ENDTIME,'MM/DD/YYYY');
COMMIT;
END;
SAMPLE DATE in Tab2 IS TIMESTAMP DATATYPE 5/5/2014 9:46:38.000000 AM
When I try to execute
Execute PROC1(TO_DATE('5/5/2014','MM/DD/YYYY'),TO_DATE('5/6/2014','MM/DD/YYYY'));
the procedure is successfully completed but my Insert into was ignored.
I tried printing the input date through dbms_output.put_line and the date did not return.
This is very, very similar to the question you asked yesterday.
If v_starttime and v_endtime are of type date, it makes no sense to call to_date on them. to_date does not take an argument of type date. It takes a parameter of type varchar2. If you try to pass a date to to_date, Oracle has to implicitly cast the date to a varchar2 using the session's NLS_DATE_FORMAT. If that doesn't match the format mask you're passing to to_date, you may get an error or you may get an incorrect result. As in yesterday's question, you want to avoid implicit conversions.
A date in Oracle has both a day and a time component (to the second). If you are doing the to_date in order to ensure that the time component is midnight, use the trunc function instead.
INSERT INTO TAB1( column_name )
SELECT COINS
FROM TAB2
WHERE <<timestamp column>> BETWEEN trunc( v_starttime ) AND trunc( v_endtime );
You say that your "insert was ignored". That seems highly unlikely. It's much more likely that your SELECT statement returned 0 rows so your INSERT inserted 0 rows. That's not an error. If you want to treat it as an error, you'd need to check SQL%ROWCOUNT after the INSERT and throw an error if the INSERT statement inserts 0 rows.
If the SELECT was not selecting any rows because of an implicit conversion error, then getting rid of the to_date and potentially adding the trunc would fix the problem.
The function TO_DATE requires string as first parameter.
CREATE OR REPLACE PROCEDURE PROC1(
V_STARTTIME IN DATE,
V_ENDTIME IN DATE)
BEGIN
INSERT INTO TAB1
SELECT COINS FROM TAB2 WHERE DATE BETWEEN V_STARTTIME AND V_ENDTIME;
COMMIT; --You should not use commit in procedure.
END;

Oracle Procedure error (PLS-00428)

This is the error message: PLS-00428: an INTO clause is expected in this SELECT statement. Meanwhile, this is the procedure for testing displaying the system date:
CREATE OR REPLACE
PROCEDURE "TEST_PROCEDURE"
AS
BEGIN
SELECT SYSDATE FROM DUAL;
END;
In the first place I don't need to use that INTO Oracle is insisting for me to do. Is there other way around beside using a cursor (I've seen it here https://stackoverflow.com/a/6029963/1983024)? I think it should not be like that, this does run normally just like in MS SQL without using INTO or cursor.
In the first place I don't need to use that INTO Oracle is insisting
for me to do.
The fact is, Oracle is correct: you do need to use an INTO to take the return value.
After all, if you want to display the result of the query you're going to need a variable to put it in first.
you can write
CREATE OR REPLACE
PROCEDURE "TEST_PROCEDURE"
AS
BEGIN
for r_row in ( SELECT SYSDATE s FROM DUAL)
dbms_output.put_line(r_row.s);
end loop;
END;
or you have to have a variable.
CREATE OR REPLACE
PROCEDURE "TEST_PROCEDURE"
AS
v_Date date;
BEGIN
SELECT SYSDATE into v_date FROM DUAL;
dbms_output.put_line(v_date );
END;
output format is dictated by your NLS_DATE_FORMAT setting, or you can be explicit like to_char(v_date, 'dd-mm-yyyy') etc.
Finally found a solution to the output I want (based on your responses) :D
CREATE OR REPLACE
PROCEDURE "TEST_PROCEDURE"
RET_DATE CHAR(10);
BEGIN
SELECT TO_CHAR(SYSDATE, 'MM/DD/YYYY') INTO RET_DATE FROM DUAL;
DBMS_OUTPUT.PUT_LINE(RET_DATE);
END;
This displays the SYSDATE with format of MM/DD/YYYY. Still, thanks for the replies and ideas (mostly #Jeffrey Kemp). Oracle just lengthens what MS SQL can normally do in one line :D
You can use like
CREATE OR replace PROCEDURE Test_procedure
IS
date CHAR(10);
BEGIN
SELECT To_char(SYSDATE, 'MM/DD/YYYY')
INTO date
FROM dual;
dbms_output.Put_line(date);
END;
it will return date into char format.
If you want to get date into date format just declare the date type variable then assign the sysdate value INTO that variable.Then use DBMS_OUTPUT.PUT_LINE(variable) to print the DATE.
If you wanted to do it in one line, you could also use:
CREATE OR replace PROCEDURE Test_procedure
IS
BEGIN
dbms_output.put_line(to_char(sysdate, 'MM/DD/YY'));
END;

Want to insert timestamp through procedure in oracle

I have this procedure
PROCEDURE insertSample
(
return_code_out OUT VARCHAR2,
return_msg_out OUT VARCHAR2,
sample_id_in IN table1.sample_id%TYPE,
name_in IN table1.name%TYPE,
address_in IN table1.address%TYPE
)
IS
BEGIN
return_code_out := '0000';
return_msg_out := 'OK';
INSERT INTO table1
sample_id, name, address)
VALUES
(sample_id_in, name_in, address_in);
EXCEPTION
WHEN OTHERS
THEN
return_code_out := SQLCODE;
return_msg_out := SQLERRM;
END insertSample;
I want to add 4th column in table1 like day_time and add current day timestamp in it.. ho can i do that in this procedure.. thank you
Assuming you you have (or add) a column to the table outside of the procedure, i.e.
ALTER TABLE table1
ADD( insert_timestamp TIMESTAMP );
you could modify your INSERT statement to be
INSERT INTO table1
sample_id, name, address, insert_timestamp)
VALUES
(sample_id_in, name_in, address_in, systimestamp);
In general, however, I would strongly suggest that you not return error codes and error messages from procedures. If you cannot handle the error in your procedure, you should let the exception propagate up to the caller. That is a much more sustainable method of writing code than trying to ensure that every caller to every procedure always correctly checks the return code.
Using Sysdate can provide all sorts of manipulation including the current date, or future and past dates.
http://edwardawebb.com/database-tips/sysdate-determine-start-previous-month-year-oracle-sql
SYSDATE will give you the current data and time.
and if you add the column with a default value you can leave your procedure as it is
ALTER TABLE table1 ADD when_created DATE DEFAULT SYSDATE;