Formatting timestamp in oracle - sql

We have a column of type varchar2(200 char) which holds a timestamp in the format 2019-03-28:17:01:44.407000000
Now we would like to update the values in the column so that the format looks like 3/28/2019 5:01:43.475 PM
We are using Oracle 12c.
I am new to oracle, Any lead would be helpful.

This is a pretty terrible data model. A timestamp should really, really be stored in a timestamp column rather than in a varchar2. Both because then the data type identifies what is actually in the column and because it is more efficient and because it lets you use all Oracle's timestamp functions on the data sensibly.
Assuming that you are stuck with an incorrect data model
update your_table
set your_column = to_char( to_timestamp( your_column, 'YYYY-MM-DD:HH24:MI:SS.FF9' ),
'MM/DD/YYYY HH:MI:SS.FF3 PM' )
would update all the data to the new format in the unlikely event that every single value in the table is in the correct format already. In most real-world systems, you'd need to do a fair amount of clean-up first because inevitably someone has stored in incorrect string or two in your column.
If you do happen to be able to update all the data successfully, be aware that any queries that do order by your_column will almost certainly stop doing what you want. Since the column is a varchar2 rather than a timestamp, sorting is done alphabetically rather than by the point in time that the string represents. If you change the format to something where temporal order doesn't match alphabetical order, you are likely to have unhappy users.

Related

Converting all data in a Varchar column to a date format

I'm working on a table with a column, 'Expiry Date', as a varchar with all data formatted as DD/MM/YYYY.
The creator of the table has used the wrong type for this expiry date column and now the client needs to filter and show all records before and after the current date as the time. This means the type needs to be changed to date or datetime type to be able to use the CURDATE() function.
However, the current format of the values does not satisfy and wont allow the type to change unless the format is changed to YYYY-MM-DD (or similar).
Is there any way to mass format the values in this column and this column alone as there are thousands of entries and formatting one by one would be extremely time consuming.
Let me assume that you are using MySQL.
Perhaps the simplest method is to add a generated column that is a date:
alter table t add column expiry_date_date as
(str_to_date(expiry_date, '%d/%m/%Y'));
You can also fix the data:
update t
set expiry_date = str_to_date(expiry_date, '%d/%m/%Y');
This will implicitly convert the result of str_to_date() to a date, which will be in the YYYY-MM-DD format.
More importantly, you can then do:
alter table t modify column expiry_date date;
Here is a db<>fiddle.
You can do similar operations in other databases, but the exact code is a bit different.
What you need is an update on that column, but before doing it I suggest you to check if the result is what you want.
select replace(expiry_date, '/', '-') new_expiry_date
from table_name
If this returns the results you want you can run the following update:
update table_name
set expiry_date = replace(expiry_date, '/', '-')
Of course you will need to replace expiry_date and table_name with the names of your column and table.

SQL query to retrieve last twelve months data for Oracle database

I am using Oracle database. I have a table called "TEST" where the dates/timestamps(These are stored as "Char" in my case) are stored in the following format. Now I want to retrieve the records of last twelve months based on today's date. What would be the correct way to do that?
TESTCOLUMN
------------
2019-06-28-02.01.07.327240
2020-06-28-04.49.12.480240
2020-06-28-05.05.10.681240
I think you need to use the ADD_MONTHS function and BETWEEN clause as follows:
SELECT * FROM YOUR_TABLE
WHERE TO_TIMESTAMP(YOUR_COLUMN,'YYYY-MM-DD HH24.MI.SS.FF')
BETWEEN ADD_MONTHS(SYSTIMESTAMP,-12) AND SYSTIMESTAMP;
Although storing values in a string is not recommended, your format is comparable. So you can do the comparison using strings rather than date/timestamps. Assuming your values are only in the past:
where testcolumn >= to_char(SYSTIMESTAMP, -12), 'YYYY-MM-DD HH24.MI.SS.FF')
This has an advantage over Tejash's solution, because this can make use of an index (or partitions) on testcolumn. Moving the date manipulations only on the "constants" (i.e. the system timestamp) helps the Oracle optimizer.

ORA-01843: not a valid month error

I have a column in Oracle DB which is varchar2 data type. Typical value stored in this column is like 06/16/2015 02:14:18 AM.
I am trying to get all records wherein this column is having records after 1st August 2015.
select *
from MYTABLE
where to_date(substr(MYCOLUMN,1,10),'dd-mm-yyyy') > to_date('01-08-2015','dd-mm-yyyy');
But, I am getting ORA-01843. Where am I doing wrong?
Respect the format in your VARCHAR
....where to_date(substr(MYCOLUMN,1,10),'mm/dd/yyyy')
I have a column in Oracle DB which is varchar2 data type. Typical value stored in this column is like 06/16/2015 02:14:18 AM.
The first question is why do you store DATE as string? Using appropriate data type is one of the most important part of database design and performance.
Understand that DATE doesn't have the format you see, it is internally stored in 7 bytes which is Oracle's proprietary format. Storing date as a string to have a fixed format is not recommended.
I would suggest first fix the design so that you don't have to do this overhead activity while comparing dates. In the longer run it will help you.
1. Add a new column as DATE data type.
ALTER TABLE table_name
ADD new_column DATE;
2. Update the new column.
UPDATE table_name
SET new_column = TO_DATE(old_column, 'mm/dd/yyyy hh:mi:ss pm');
3. DROP the old column.
ALTER TABLE table_name
DROP COLUMN old_column;
4. Rename the new column to old column name.
ALTER TABLE table_name
RENAME COLUMN old_name to new_name;
Now, you could compare dates easily:
SELECT * FROM MYTABLE WHERE mycolumn > to_date('01-08-2015','dd-mm-yyyy');
This will also use any regular index on the date column.
From performance point of view:
If you don't fix it now, you will keep facing performance issues. Because the immediate fix of SUBSTR will not let you use any regular index, you need to create a function-based index.
If in your table all values like 06/16/2015 02:14:18 AM then you can use trunc(to_date(MYCOLUMN,'mm/dd/yyyy HH:mi:SS PM'),'dd') against to_date(substr(MYCOLUMN,1,10),'dd-mm-yyyy').

Return an oracle column as timestamp

I'm in coldfusion working with data from an sql table, and using a query of queries to join the sql data to some data from an oracle database. Unfortunately, I need to order them by date, and the oracle table has two columns - DRWR_DATE which is of type DATE and TIME which is of type VARCHAR2. The two columns put into a string read 17-JUN-03 16:35:18 or something similar. I need to return these two columns as a TIMESTAMP so I can use query of queries to sort them.
Also, I think I read that a date column holds the time in Oracle anyway? I don't have much experience with Oracle so I am unsure how best to do this.
Try this:
SELECT to_timestamp(
to_char( drwr_date,'dd-mon-yy') ||' '|| time
, 'dd-mon-yy hh24:mi:ss'
)
FROM your_table
Try using TO_TIMESTAMP function:
SELECT TO_TIMESTAMP('17-JUN-03 16:35:18', 'DD-MON-RR HH24:MI:SS')
FROM DUAL;
you can try converting the column to date as the following:
TO_DATE(column,'DD-MON-YY HH24:MI:SS')
The first parameter takes your column and the second parameter specifies the date format that is used
If all you have to do is order by date, all you need is an order by clause.
order by drwr_date, time
You don't have to cast these to anything, unless you need to do so for another reason. Remember that a date datatype is essentially a floating point number. This, "17-JUN-03" is simply how your client is displaying it.

SQL oracle beginner questions

Question1:
Do i have to use to_date while inserting date?
INSERT INTO some_table (date1, date2)
VALUES (to_date('2012-10-24','YYYY-MM-DD'), to_date('2012-10-24','YYYY-MM-DD'));
Or can just insert as string? Will everything be OK this way too? I've tried and it worked.
INSERT INTO some_table (date1, date2)
VALUES ('2012-10-24',2012-10-24');
Question2:
What happens if i won't name columns that i'm inserting into? It works, but my question is if it inserts randomly now or it takes order of columns during creation of table?
INSERT INTO some_table
VALUES ('2012-10-24',2012-10-24');
1 seems to only work with the 'YYYY-MM-DD' format:
http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements003.htm#SQLRF51049 says
You can specify a DATE value as a string literal ... to specify a DATE value as a literal, you must use the Gregorian calendar. You can specify an ANSI literal... The ANSI date literal contains no time portion, and must be specified in the format 'YYYY-MM-DD'.
However, it might work with time if you use the
Alternatively you can specify an Oracle date value... The default date format for an Oracle DATE value is specified by the initialization parameter NLS_DATE_FORMAT.
For question 2, it uses the order at definition of the table. However you have to give values for all columns in that case.
Oracle supports Standard SQL date literals (since 9i).
It's DATE followed by a string with 'yyyy-mm-dd' format
DATE '2014-05-10'
It's much shorter than TO_DATE and it's independent of any NLS settings.
Similar for timestamps:
TIMESTAMP '2014-05-10 09:52:35'
Regarding your 2nd question: It's the order of columns as defined within the CREATE TABLE.
You could even do it like this one:
ALTER SESSION SET NLS_DATE_FORMAT = 'MM:YYYY:DD';
INSERT INTO some_table (date1) VALUES ('05:2014:10');
...but doing it like this is not recommended. Use TO_DATE or DATE Literal, e.g. DATE '2014-05-10' instead. It makes your life easier.