The system I'm working on uses an oracle 11 db and has a java implemented backend which uses JDBC.
The system has one main performance problem:
The oracle db has indexed DATE columns but the java backend access the db like this
String sql = "SELECT foo FROM bar WHERE a_date > ?";
// ... prepare the statement
statement.setTimestamp(1, new Timestamp());
then Oracle will not use the index and fall back to full table scan because of statement.setTimestamp.
First Solution:
So I have changed the access of the backend from statement.setTimestamp to statement.setDate.
The performance has been improved and the DATE index was now used, but now I lost the accuracy of the timestamp data type, and only got a day-accuracy of the java.sql.Date type.
Thus, the first solution was unusable for my system.
Second Solution:
I don’t change the java backend thus using statement.setTimestamp and change all DATE columns of the oracle db like the following sql command example:
ALTER TABLE <table_1> MODIFY <date_column> TIMESTAMP;
Now my question:
What must be considered when modifying Oracle DATE column to TIMESTAMP
I think a list of the important aspects would be perfect.
Here my first draft of the "CHECKLIST of Migrating Oracle DATE columns to TIMESTAMP
1. CREATE / INSERT
2. READ / SELECT
3. UPDATE / UPDATE
4. DELETE / DELETE
5. TO_DATE( )
select * from table where crea_time between TO_DATE( '10.2014', 'MM.yyyy' ) and TO_DATE( '12.2014', 'MM.yyyy' ) ;
6. TRUNC( )
select TRUNC( crea_time ) from table;
output of crea_time data typ DATE
05.11.2014 00:00:00
output of crea_time data typ TIMESTAMP
05.11.2014 00:00:00
7. TO_CHAR( )
select to_char( crea_time,'hh24miss' ) from table;
output data typ DATE
140612
output data typ TIMESTAMP
140612
8. NESTED - TRUNC( TO_DATE() )
select TRUNC(TO_DATE( crea_time), 'YEAR') from table;
output of crea_time data typ DATE
01.01.2014 00:00:00
output of crea_time data typ TIMESTAMP
ORA-01830:
01830. 00000 - "date format picture ends before converting entire input string"
*Cause:
*Action:
Solution >>> select TRUNC( TO_TIMESTAMP( crea_time), 'YEAR' ) from table;
output of crea_time data typ TIMESTAMP
01.01.2014 00:00:00
9. Add A DAY/HOUR/MINUTE/SECOND
select crea_time+1 from table;
output data typ DATE
06.11.2014 14:06:12
output data typ TIMESTAMP
06.11.2014 14:06:12
10. MIN() / MAX()
SELECT MIN(crea_time) FROM table;
output data typ DATE
05.11.2014 14:06:12
output data typ TIMESTAMP
05.11.2014 14:06:12,000000000
Please excuse my bad English.
Related
I have this query in oracle:
DELETE FROM my_table
WHERE to_date(last_update, 'DD/MM/YYYY') < to_date('01/01/2000', 'DD/MM/YYYY');
when I run this, I get this error:
ORA-01841: (full) year must be between -4713 and +9999 and must not be 0
there is not any 0 value in the table.
any one knows what is the problem?
I am assuming that you have stored your dates as a string with the DD/MM/YYYY format; it would be better if you stored them all as a DATE data type and then you would not have to do this conversion (and you would be using the most appropriate data type for the data).
From Oracle 12, you can use:
SELECT *
FROM my_table
WHERE TO_DATE( last_update, 'DD/MM/YYYY' DEFAULT NULL ON CONVERSION ERROR ) IS NULL;
To identify the rows that are raising that exception.
If you are already storing them as a DATE data type then don't use TO_DATE on a value that is already a DATE as TO_DATE expects a string so Oracle will implicitly cast your DATE to a string and then try to convert it back and your query is effectively:
DELETE FROM my_table
WHERE TO_DATE(
TO_CHAR(
last_update,
( SELECT value FROM NLS_SESSION_SETTINGS WHERE PARAMETER = 'NLS_DATE_FORMAT' )
),
'DD/MM/YYYY'
) < to_date('01/01/2000', 'DD/MM/YYYY');
And if the NLS_DATE_FORMAT and your format model do not match then you will get errors (or, worse, the query will succeed and your data will be inconsistent as it may have swapped days and months or months and years).
Instead, just use:
DELETE FROM my_table
WHERE last_update < DATE '2000-01-01';
If the datatype of last_update is date, don't use the to_date function:
DELETE FROM my_table
WHERE last_update < to_date('01/01/2000', 'DD/MM/YYYY');
I am using SAP BODS and I am trying to fetch data from an ORACLE server using SQL query transormation. Now The table has a column named latest_changed_date which is a datetime column. I only want yesterday and current day data from that table. Now since the column is datetime, I need to convert it to date, but when I am using to_date function I get the following error.
SELECT *
FROM ABC.TEST
WHERE TO_DATE(LATEST_CHANGED_DATE) = TO_DATE(SYSDATE-1)
The database error message is
ORA-01843: not a valid month
I tried giving date format in TO_DATE condition as below:
SELECT *
FROM ABC.TEST
WHERE TO_DATE(LATEST_CHANGED_DATE,'YYYY-MM-DD') >= TO_DATE(SYSDATE-1,'YYYY-MM-DD')
Here I got the error:
date format picture ends before converting entire input string
I used trunc function also and again got either:
not a valid month
or
inconsistent datatypes: expected NUMBER got DATE
Below is a sample data for the column. I just need data for current and day before data from the column.
Update: I think the main issue is that I am not able to determine the proper datatype for the column in the source table and currently I don't have an option to determine that.
Rather than trying to implicitly cast your dates to strings and convert them back using TO_DATE( string_value, format_model ) you can use TRUNC() to truncate SYSDATE to the start of the day:
SELECT *
FROM ABC.TEST
WHERE LATEST_CHANGED_DATE >= TRUNC( SYSDATE-1 )
this will work:
SELECT *
FROM ABC.TEST
where sysdate-LATEST_CHANGED_DATE<=sysdate-(sysdate-2);
for example take this:
ALTER SESSION SET NLS_DATE_FORMAT = ' DD-MON-YYYY HH24:MI:SS';
SELECT * FROM d061_dates ;
03-DEC-2018 17:44:38
25-AUG-2018 17:44:42
30-AUG-2018 17:44:46
01-DEC-2018 17:44:49
02-DEC-2018 17:46:31
SELECT * FROM d061_dates
where sysdate-a<=sysdate-(sysdate-2);
03-DEC-2018 17:44:38
02-DEC-2018 17:46:31
you have to take sysdate minus on both sides to get comparision by a number which is less than equal to 2 to get day and day before yesterday and its giving the correct output.
thank you!!!!!!!!!!!!!
I have some timestamp data in an old Oracle database that needs converting into HH:MM:SS. After trying to use to_char function, the value I give is not readable (E.g. 105001, to_char('105001','HH24:MI:SS)), this SQL will break. I can convert sysdate into the incorrect format but I can't reverse the procedure.
For example:
select to_char(sysdate, 'HHmiss')from table
returns '105001'
I need something that will convert the hhmmss format into HH:MM:SS so when I produce a select statement it is in a readable format.
You can first select from dual table which is virtual table
There are 2 different way to have time
24 hours : like 5 and 15
select to_char(sysdate, 'HH24:MI:SS')from dual
Result
14:25:56
12 hours : like 2 AM and 2 PM
select to_char(sysdate, 'HH:MI:SS AM')from dual
Result
02:22:35 PM
Assuming that your values are a NUMBER in the database which is six-digits long and represents an HHMMSS value you can format it as you want by using SUBSTR:
SELECT SUBSTR(TO_CHAR(SOME_TIMESTAMP, 'FM000000'), 1, 2) || ':' ||
SUBSTR(TO_CHAR(SOME_TIMESTAMP, 'FM000000'), 3, 2) || ':' ||
SUBSTR(TO_CHAR(SOME_TIMESTAMP, 'FM000000'), 5, 2)
FROM cteNumbers
db<>fiddle here
I have some timestamp data in an old Oracle database that needs converting into HH:MM:SS
Just use HH24 to get a 24-hour clock and add the : separators to your format model and then apply that format directly to your TIMESTAMP column using the TO_CHAR function:
Oracle 11g R2 Schema Setup:
CREATE TABLE table_name ( your_timestamp_column TIMESTAMP );
INSERT INTO table_name ( your_timestamp_column )
VALUES ( TIMESTAMP '2018-09-24 12:34:56' );
Query 1:
SELECT TO_CHAR( your_timestamp_column, 'HH24:MI:SS') FROM table_name
Results:
| TO_CHAR(YOUR_TIMESTAMP_COLUMN,'HH24:MI:SS') |
|---------------------------------------------|
| 12:34:56 |
You do not need to output it as a HHMMSS string and then try to reformat it to add separators as that is needlessly complicated.
In my Oracle SQL Developer, i have a table with a column with DATE format. When i insert a new row into this table, and insert a new value in this column, it automatically suggestes me the current date with the current hour.
I would like that it automatically suggestes me current date, but with 00:00:00 hour . Is there some setting or parameter that i can set in my SQL Developer to have this result?
We can't able to insert 00:00:00 hours ... the hour value should be between 1 to 12...
we can use below query to insert 00:00:00 hours but the value will be changed to 12:00:00
INSERT INTO TABLE (DATE_COL) VALUES
( TO_DATE ('11/16/2017 00:00:00 ', 'MM/DD/YYYY HH24:MI:SS '));
It seems to me that your DATE column is set with a DEFAULT of SYSDATE. This means, for any INSERT operations which do not specify a value in your DATE column, the current date and time will populate for that row. However, if INSERT operations do specify a value in your DATE column, then the specified date value will supersede the DEFAULT of SYSDATE.
If an application is controlling INSERT operations on that table, then one solution is to ensure the application utilizes the TRUNC() function to obtain your desired results. For example:
INSERT INTO tbl_target
(
col_date,
col_value
)
VALUES
(
TRUNC(SYSDATE, 'DDD'),
5000
)
;
However, if there are multiple applications or interfaces where users could be inserting new rows into the table, (e.g. using Microsoft Access or users running INSERT statements via SQL Developer) and you can't force all of those interfaces to utilize the TRUNC() function on that column during insertion, then you need to look into other options.
If you can ensure via applications that INSERT operations will not actually reference the DATE, then you can simply ALTER the table so that the DATE column will have a DEFAULT of TRUNC(SYSDATE). A CHECK CONSTRAINT can be added for further integrity:
ALTER TABLE tbl_target
MODIFY
(
col_date DATE DEFAULT TRUNC(SYSDATE, 'DDD') NOT NULL
)
ADD
(
CONSTRAINT tbl_target_CHK_dt CHECK(col_date = TRUNC(col_date, 'DDD'))
)
;
However, if users still have the freedom to specify the DATE when inserting new rows, you will want to use a TRIGGER:
CREATE OR REPLACE TRIGGER tbl_target_biu_row
BEFORE INSERT OR UPDATE OF col_val
ON tbl_target
FOR EACH ROW
BEGIN
:NEW.col_date := TRUNC(SYSDATE, 'DDD');
END tbl_target_biu_row
;
This will take of needing to manage the application code of all external INSERT operations on the table. Keep in mind, the above trigger is also modifying the DATE column if a user updates the specified value column.
I have a problem in Oracle, with a virtual column (I need the timestamp starting from a date column); here my example:
CREATE TABLE TBDATETIME(
DATETIME_1 DATE,
DATETIME_2 TIMESTAMP(9) GENERATED ALWAYS AS (
CAST( TO_CHAR(DATETIME_1, 'DD/MM/YYYY HH24:MI:SS')
|| '.' || TO_CHAR(DATETIME_1, 'FF9') AS TIMESTAMP(9))
) VIRTUAL
);
INSERT INTO TBDATETIME(DATETIME_1)
VALUES(SYSDATE);
COMMIT;
SELECT *
FROM TBDATETIME;
ORA-01821: date format not recognized
01821. 00000 - "date format not recognized"
*Cause:
*Action:
Where is the problem fetching data? I tried a lot of format masks, but nothing helps...
DATETIME_1 DATE
TO_CHAR(DATETIME_1, 'FF9')
That's the problem - DATE doesn't have fraction seconds
And it's dangerous to cast char to timestamp (the result depends on nls settings)
I suppose you want this:
CREATE TABLE TBDATETIME(DATETIME_1 DATE, DATETIME_2 TIMESTAMP(9) GENERATED ALWAYS AS (CAST(DATETIME_1 AS TIMESTAMP(9))) VIRTUAL);