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
Related
I am confused with to_date(char[,'format'[,nls_lang]) function. Lets suppose I have to_date('31-DEC-1982','DD-MON-YYYY');should the format specified in the function be same as the date string? The above function works fine. When I use to_date('31-DEC-1982','DD-MM-YYYY'); also works fine but the month field in date string and that in format does not match.
So my doubt is should the date string and format specified match exactly to convert it to Date object.
Thanks
Generally speaking, yes, the date string and specified format should match. But the reason why it works in your case is that Oracle, for certain cases, provides flexibility of alternative format matching.
Excerpt from official Oracle Site
If a match fails between a datetime format element and the corresponding characters in the date string, then Oracle attempts alternative format elements
So as per above table, you can use 'MON' or 'MONTH' in place of 'MM'.
Similarly you can use 'YYYY' in place 'YY', etc
Reference:
Oracle Format Matching
Whatever format you follow, the object returned will be of date type.
You can test this via creating a dummy table and showing the table description.
e.g. CREATE TABLE TEST AS(
select to_date('31-DEC-1982','DD-MON-YYYY') dd from dual);
Now desc test;
Result will be dd date.
Similar will be the result with another type.
However if you are using SQL Developer, the date will be show in the exact NLS format as the setting there applies.
tools->preferences->database->NLS
The Query using LIKE :(This query when fired gives the desired result)
select * from catissue_audit_event where event_timestamp like '16-DEC-14'
But when using query with '=' results in an empty resultset
select * from catissue_audit_event where event_timestamp='16-DEC-14'
Here event_timestamp is of type Date
Strange thing is that the query runs for other dates such as:
select * from catissue_audit_event where event_timestamp='15-DEC-14'
What can be the issue? I already checked for leading and trailing spaces in the data
Output after running the first query:
In Oracle a DATE (and of course a TIMESTAMP) column contains a time part as well.
Just because your SQL client is hiding the time, doesn't mean it isn't there.
If you want all rows from a specific day (ignoring the time) you need to use trunc()
select *
from catissue_audit_event
where trunc(event_timestamp) = DATE '2014-12-16';
Be aware that this query will not use an index on the event_timestamp column.
You should also not rely on implicit data type conversion as you do with the expression event_timestamp = '16-DEC-14. That statement is going to fail if I run it from my computer because of different NLS settings. Always use a proper DATE literal (as I have done in my statement). If you don't like the unambiguous ISO date, then use to_date():
where trunc(event_timestamp) = to_date('16-12-2014', 'dd-mm-yyyy');
You should avoid using month names unless you know that all environments (which includes computers and SQL clients) where your SQL statement is executed are using the same NLS settings. If you are sure, you can use e.g. to_date('16-DEC-14', 'dd-mon-yy')
The reason why this is different is different to the solution to your issue.
The solution to your issue is to stop performing date comparisons by implicit conversion to a string. Convert your string to a date to perform a date comparison:
select * from catissue_audit_event where event_timestamp = date '2014-12-16'
I cannot stress this enough; when performing a date comparison only compare dates.
Your column EVENT_TIMESTAMP is being implicitly (this is bad) converted to a date in accordance with your NLS_DATE_FORMAT, which you can find as follows:
select * from nls_session_parameters
This governs how date-data is displayed and implicitly converted. The reason why LIKE works and and = doesn't is because your NLS_DATE_FORMAT is masking additional data. In other words, your date has a time component.
If you run the following and then re-select the data from your table you'll see the additional time component
alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss'
Thus, if you want all the data for a specific date without constraint on time you'll need to remove the time component:
select * from catissue_audit_event where trunc(event_timestamp) = date '2014-12-16'
have you tried matching the event_timestamp format example: DD-MMM-YY with the date that you are passing?
May I know could I verify whether the date displayed in the field is in specific format
As per my requirement, the datetime should be displayed in format 'yyyy/mm/dd HH(24hr)/MM/SS'
Eg: The valid value should be '2014/07/18 14:16:48'. If the date is displayed as '18/07/2014 14:16:48', then it is invalid.
Using query how I verify whether it is shown in the format which I have expected. I could use IsDate option to verify it is a valid date and also I could use Mid function to verify the date separator which is '/', but how could I verify the format.
Thanks
If the column is stored as Text, use the SQL Like operator. Select valid dates:
SELECT * FROM myTable WHERE myDate Like "####/##/## ##:##:##"
Select invalid dates
SELECT * FROM myTable WHERE myDate Not Like "####/##/## ##:##:##"
# stands for a single digit.
See Like Operator.
But note that this only makes sense if myDate is a Text! If the type of myDate is Date/Time, the date is stored in a numeric format internally and is only formatted as a date for display. So don't confuse the date value per se and the date as it is displayed.
A Date/Time is always stored in the same way, no matter how it is formatted and displayed!
All you need to do is to open the Table in Design View and to set the Format property.
I have to run column checks for data consistency and the only thing that is throwing off my code is checking for character lengths for dates between certain parameters.
SEL
sum(case when ( A.date is null or (character_length(A.date) >8)) then 1 else 0 end ) as Date
from
table A
;
The date format of the column is YYYY-MM-DD, and the type is DA. When I run the script in SQL Assistant, I get an error 3580 "Illegal use of CHARACTERS, MCHARACTERS, or OCTET_LENGTH functions."
Preliminary research suggests that SQL Assistant has issues with the character_length function, but I don't know how to adjust the code to make it run.
with chareter length are you trying to get the memory used? Becuase if so that is constant for a date field. If you are trying to get the length of the string representation i think LENGTH(A.date) will suffice. Unfortanatly since teradata will pad zeros on conversions to string, I think this might always return 10.
UPDATE :
Okay so if you want a date in a special 'form' when you output it you need to select it properly. In teradata as with most DBs Date are not store in strings, but rather as ints, counting days from a given 'epoch' date for the database (for example the epoch might be 01/01/0000). Each date type in teradata has a format parameter, which places in the record header instructions on how to format the output on select. By default a date format is set to this DATE FROMAT 'MM/DD/YYYY' I believe. You can change that by casting.
Try SELECT cast(cast(A.date as DATE FORMAT 'MM-DD-YYYY') as CHAR(10)) FROM A. and see what happens. There should be no need to validate the form of the dates past a small sample to see if the format is correct. The second cast forces the database to perform the conversion and use the format header specified. Other wise what you might see is the database will pass the date in a date form to SQL Assitant and sql assitant will perform the conversion on the application level, using the format specified in its own setting rather then the one set in the database.
When ececute the following SQL syntax in Oracle, always not success, please help.
40284.3878935185 represents '2010-04-16 09:18:34', with microsecond.
an epoch date of 01 January 1900 (like Excel).
create table temp1 (date1 number2(5,10));
insert into temp1(date1) values('40284.3878935185');
select to_date(date1, 'yyyy-mm-dd hh24:mi:ssxff') from temp1
Error report: SQL Error: ORA-01861: literal does not match format
string
01861. 00000 - "literal does not match format string"
*Cause: Literals in the input must be the same length as literals in
the format string (with the exception of leading whitespace). If the
"FX" modifier has been toggled on, the literal must match exactly,
with no extra whitespace.
*Action: Correct the format string to match the literal.
Thanks to Mark Bannister
Now the SQL syntax is:
select to_char(to_date('1899-12-30','yyyy-mm-dd') +
date1,'yyyy-mm-dd hh24:mi:ss') from temp1
but can't fetch the date format like 'yyyy-mm-dd hh24:mi:ss.ff'. Continue look for help.
Using an epoch date of 30 December 1899, try:
select to_date('1899-12-30','yyyy-mm-dd') + date1
Simple date addition doesn't work with timestamps, at least if you need to preserve the fractional seconds. When you do to_timestamp('1899-12-30','yyyy-mm-dd')+ date1 (in a comment on Mark's answer) the TIMESTAMP is implicitly converted to a DATE before the addition, to the overall answer is a DATE, and so doesn't have any fractional seconds; then you use to_char(..., '... .FF') it complains with ORA-01821.
You need to convert the number of days held by your date1 column into an interval. Fortunately Oracle provides a function to do exactly that, NUMTODSINTERVAL:
select to_timestamp('1899-12-30','YYYY-MM-DD')
+ numtodsinterval(date1, 'DAY') from temp3;
16-APR-10 09.18.33.999998400
You can then display that in your desired format, e.g. (using a CTE to provide your date1 value):
with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')
+ numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SSXFF') from temp3;
2010-04-16 09:18:33.999998400
Or to restrict to thousandths of a second:
with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')+
+ numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SS.FF3') from temp3;
2010-04-16 09:18:33.999
An epoch of 1899-12-30 sounds odd though, and doesn't correspond to Excel as you stated. It seems more likely that your expected result is wrong and it should be 2010-04-18, so I'd check your assumptions. Andrew also makes some good points, and you should be storing your value in the table in a TIMESTAMP column. If you receive data like this though, you still need something along these lines to convert it for storage at some point.
Don't know the epoch date exactly, but try something like:
select to_date('19700101','YYYYMMDD')+ :secs_since_epoch/86400 from dual;
Or, cast to timestamp like:
select cast(to_date('19700101', 'YYYYMMDD') + :secs_since_epoch/86400 as timestamp with local time zone) from dual;
I hope this doesn't come across too harshly, but you've got to totally rethink your approach here.
You're not keeping data types straight at all. Each line of your example misuses a data type.
TEMP1.DATE1 is not a date or a varchar2, but a NUMBER
you insert not the number 40284.3878935185, but the STRING >> '40284.3878935185' <<
your SELECT TO_DATE(...) uses the NUMBER Temp1.Date1 value, but treats it as a VARCHAR2 using the format block
I'm about 95% certain that you think Oracle transfers this data using simple block data copies. "Since each Oracle date is stored as a number anyway, why not just insert that number into the table?" Well, because when you're defining a column as a NUMBER you're telling Oracle "this is not a date." Oracle therefore does not manage it as a date.
Each of these type conversions is calculated by Oracle based on your current session variables. If you were in France, where the '.' is a thousands separator rather than a radix, the INSERT would completely fail.
All of these conversions with strings are modified by the locale in which Oracle thinks your running. Check dictionary view V$NLS_PARAMETERS.
This gets worse with date/time values. Date/time values can go all over the map - mostly because of time zone. What time zone is your database server in? What time zone does it think you're running from? And if that doesn't spin your head quite enough, check out what happens if you change Oracle's default calendar from Gregorian to Thai Buddha.
I strongly suggest you get rid of the numbers ENTIRELY.
To create date or date time values, use strings with completely invariant and unambiguous formats. Then assign, compare and calculate date values exclusively, e.g.:
GOODFMT constant VARCHAR2 = 'YYYY-MM-DD HH24:MI:SS.FFF ZZZ'
Good_Time DATE = TO_DATE ('2012-02-17 08:07:55.000 EST', GOODFMT);