ORACLE SQL Trim ineffective with Regular Expressions - sql

CLARIFICATION
When I simplify the query, i.e.
SELECT TO_CHAR(MIN(I.INCIDENTID)) AS "Incident ID",
TRIM(TO_CHAR(I.CREATIONDATE,'DD-MON-YYYY')) AS "Creation Date"
FROM INCIDENT I
GROUP BY TRIM(TO_CHAR(I.CREATIONDATE,'DD-MON-YYYY'))
I get
But if I incorporate into my actual query for 164,000+ distinct rows, I get
But I expect this (only difference is, Creation Date must have proper Date format, not this complex string)
ORIGINAL QUESTION
I am reading a date-time from an external Oracle Database, and have trimmed any extra spaces successfully with TRIM(I.CREATIONDATE).
I have verified this because my SQL query only displays distinct date values
However, TRIM(I.CREATIONDATE) turns 2/26/2019 11:05:44 AM into 26-FEB-19 11.05.43.925000 AM, but I only want 26-FEB-19
When I apply regular expression to only get date, i.e. REGEXP_SUBSTR(TRIM(I.CREATIONDATE),'[^ ]+'), it certainly outputs 26-FEB-19, but somehow extra spaces are added because I get duplicate dates.
I have tried applying TRIM a second time, i.e. TRIM(REGEXP_SUBSTR(TRIM(I.CREATIONDATE),'[^ ]+')), but I still get duplicates
Then I tried running regular expression first, then trim, but this does not work, i.e. TRIM(REGEXP_SUBSTR(I.CREATIONDATE,'[^ ]+')) still gives duplicates.
Please assist

I think you want trunc(), not trim() to remove the time component.
So try:
trunc(i.creationdate)
Or if you want the days in a particular string representation:
to_char(i.creationdate, 'YYYY-MM-DD')

Try to_char:
trim(to_char(column_name,'dd-mon-yy'))

Related

SQL date format picture ends before converting entire input string

I am trying to execute a query looking something like this:
create table A as
select
userid, to_date(date1, 'mm/dd/yyyy') as startDate,
to_date(date2, 'mm/dd/yyyy') as endDate
from TABLE;
I am getting the error:
ORA-01830: date format picture ends before converting entire input string
What's really strange here is that when I run only the SELECT... part of the query it works perfectly, I am only getting the error when I try to create a table. I absolutely need to make a table, so how can I get around this?
Thanks!
There's likely some bad data past the first few rows. When you run the select, it will do the conversion for the first few (less than 1000 for me) rows only. The results are paged. You'll need to clean up the data first. You could write a simple function like this to figure out which dates it's failing on.
How to handle to_date exceptions in a SELECT statment to ignore those rows?

selecting data fom a view throws error

I get input as 2011/11/13 00:00:00. So I made the query as:
select * from xxcust_pfoa434p_vw
where week_ending_date = to_date(substr(:value,1,10),'YYYY/MM/DD')
The same statement gives proper result when queried against other tables. But throws error when I query this against the view xxcust_pfoa434p_vw
I have a view xxcust_pfoa434p_vw which has a column week_ending_date of date data type.
The value in that column is like 3/2/2014,12/25/2011 i.e. MM/DD/YYYY
Even
select * from xxcust_pfoa434p_vw where week_ending_date='3/2/2014'
also gives
ORA-01843: not a valid month. What is the cause for this error.
You say
"The same statement gives proper result when queried against other
tables. But throws error when I query this against the view
xxcust_pfoa434p_vw"
So clearly the problem is with the view. You also say
"[the view] has a column week_ending_date of date data type. The value
in that column is like 3/2/2014,12/25/2011 i.e. MM/DD/YYYY "
Those values would only display like that if the default date mask for you system were MM/DD/YYYY. This is easy enough to check with the query
select * from V$NLS_PARAMETERS
where parameter = 'NLS_DATE_FORMAT';
Personally, my money is on that column not being a date column. ORA-01841 always indicates oracle attempting to cast a string into a date and finding a value which doesn't fit the explicit or default format mask. Plus the so-called date '3/2/2014' lacks leading zeroes and that's suspicious too.
I think whoever wrote that view decided to fix the format of week_ending_date and so deployed TO_CHAR to present a string not a date datatype. A DESC in SQL*Plus or looking at the view TEXT in ALL_VIEWS will reveal the answer.
select * from xxcust_pfoa434p_vw
where week_ending_date=to_date('03/02/2014','MM/DD/YYYY');
Even if you see formatted date in this format - it is only a visual representation, when oracle process your query it automatically convers string given by you into its own interal representation.
It is always better to use proper SQL one YYYY-MM-DD:
for 2nd march: select * from xxcust_pfoa434p_vw where week_ending_date = to_date('2014-03-02', 'YYYY-MM-DD')
for 3rd february: select * from xxcust_pfoa434p_vw where week_ending_date = to_date('2014-02-03', 'YYYY-MM-DD')
this conforms to SQL standard and do not produce confusion between DD/MM/YYYY and MM/DD/YYYY
Just quote from standard:
There is an ordering of the significance of <datetime field>s. This
is, from most significant to least significant: YEAR, MONTH, DAY,
HOUR, MINUTE, and SECOND.
UPDATE: it is very good idea always use to_date function to specify exact format and avoid dependancy on any kind of localization settings

How to compare two date values in Oracle based on the date and time

I'm working in an aviation environment where I have to compare two values. The OEM in all its wisdom has stored all datetime values in char. The values to compare are called, say, aibt and sibt
As part of the where clause I need to check if aibt is greater than sibt. So this is what I did :
To_Date(aibt,'YYYYMMDDHH24MISS') > To_Date(sibt,'YYYYMMDDHH24MISS')
When applying to_date, the original char values are converted to : 25.12.2013 12:54:00
But I get the following error :
ORA-01841: (full) year must be between -4713 and +9999, and not be 0
You obviously have some data that can not be converted with TO_DATE to a proper date. Feel free to berate your OEM for not defining constraints or otherwise prevent this from happening.
While he gets around to fix his problems, you can use this as a workaround:
WHERE aibt > sibt
Seems like an error in your data. Try this first:
Select to_date(aibt,'YYYYMMDDHH24MISS') from your_table
Select to_date(sibt,'YYYYMMDDHH24MISS') from your_table
to check if you have some incorrect data in your columns.
When you identified your problematic data in your column, you could find the data that is messing this up with somethin like this:
select *
from yourtable
where not regexp_like(aibdt, '^[[:digit:]]+$')
OR length(aibdt)<4 OR
substr(aibdt,1,4)<0
There was some problem in the data. Also thanks Twinkles for your contribution. I hadnt thought of that. Can anyone explain how comparing two char values work?
I got the answer (what I'd really required) in another post Oracle: how to add minutes to a timestamp? which I used for constructing the comparison :
WHERE To_Date(aibt,'YYYYMMDDHH24MISS')>To_Date(sibt,'YYYYMMDDHH24MISS')+ INTERVAL '15' MINUTE
Thanks everyone!

Select data in date format

I have a query in which I want to select data from a column where the data is a date. The problem is that the data is a mix of text and dates.
This bit of SQL only returns the longest text field:
SELECT MAX(field_value)
Where the date does occur, it is always in the format xx/xx/xxxx
I'm trying to select the most recent date.
I'm using MS SQL.
Can anyone help?
Try this using ISDATE and CONVERT:
SELECT MAX(CONVERT(DateTime, MaybeDate))
FROM (
SELECT MaybeDate
FROM MyTable
WHERE ISDATE(MaybeDate) = 1) T
You could also use MAX(CAST(MaybeDate AS DateTime)). I got in the (maybe bad?) habit of using CONVERT years ago and have stuck with it.
To do this without a conversion error:
select max(case when isdate(col) = 1 then cast(col as date) end) -- or use convert()
from . . .
The SQL statement does not specify the order of operations. So, even including a where clause in a subquery will not guarantee that only dates get converted. In fact, the SQL Server optimizer is "smart" enough to do the conversion when the data is brought in and then do the filtering afterwards.
The only operation that guarantees sequencing of operations is the case statement, and there are even exceptions to that.
Another solution would be using PATINDEX in WHERE clause.
SELECT PATINDEX('[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]', field_value)
Problem with this approach is you really are not sure if something is date (e.g. 99/99/9999 is not date).
And problem with IS_DATE is it depends on configuration (e.g. DATEFORMAT).
So, use an appropriate option.

How to update dates stored as varying character formats (PL/SQL)?

Problem: I have a large database table (~500k records) which has a list of dates stored in a varchar2(15) column. These dates are stored in varying formats, ie. some are yyyy-mm-dd, some are mm/dd/yyyy, some are dd/mm/yy, some are mm/dd/yy, etc. Ie:
1994-01-13
01/13/1994
01/13/94
13/01/94
13/01/1994
etc
I need to be able to shift these dates slightly, for example to add 30 days to each date. (This is an oversimplification of my objective but it's easier to explain this way).
If all the dates were formatted consistently, I would achieve this as follows:
UPDATE history_table
SET some_date_col =
to_char(to_date(some_date_col, 'mm/dd/yyyy')+30, 'mm/dd/yyyy')
WHERE some_date_col IS NOT NULL;
Due to the size of the database, I cannot afford to loop through the values one by one and parse the date value. Can anyone suggest a means to accomplish this without loops, ie with a mass UPDATE statement?
Are the formats of these dates really that important? They should be datetime columns. Then you could just use date math functions on that field.
well, you've got a real problem here.
07/07/1994 is valid for 'MM/DD/YYYY' and 'DD/MM/YYYY'
However, outside of that issue, you can try nesting decodes.
I entered the following dates into a varchar field:
01/12/2009, 01-12-2009, 2009-01-12, 01/12/09
and using the below, I was consistently returned 1/12/2009. You'll have to figure out all the patterns possible and keep nesting decodes. The other thing you could do is create a function to handle this. Within the function, you can check with a little more detail as to the format of the date. It will also be easier to read. You can use the function in your update statement so that should be faster than looping through, as you mentioned.
(for what its worth, looping through 500k rows like this shouldn't take very long. I regularly have to update row by row tables of 12 million records)
select mydate,
decode(instr(mydate,'-'),5,to_date(mydate,'YYYY-MM-DD'),3,to_date(mydate,'MM-DD-YYYY'),
decode (length(mydate),8,to_date(mydate,'MM/DD/YY'),10,to_date(mydate,'MM/DD/YYYY')))
from mydates;
and here is the update statement:
update mydates set revdate = decode(instr(mydate,'-'),5,to_date(mydate,'YYYY-MM-DD'),3,to_date(mydate,'MM-DD-YYYY'),
decode (length(mydate),8,to_date(mydate,'MM/DD/YY'),10,to_date(mydate,'MM/DD/YYYY')))
IMHO, you have a bigger problem:
If some dates are dd/mm/yyyy and some are mm/dd/yyyy how can you difference which format applies for certain date?
for example, how can I know if a value "12/09/2008" means December or September?