SQL Error 2207 on TO_TIMESTAMP() using datetime format - sql

In Postgres, I'm trying to do a date/time based query in my WHERE predicate.
When I try to select with this date/time format SQL error says the value needs to be an integer. I'm not sure why it does not think my minute of 17 is not an integer or why it only see it as a 1 and not a 17?
SELECT *
FROM history
WHERE create_time > TO_TIMESTAMP('2018-10-08T23:17:44.728','yyyy-MM-dd''T''HH:mm:ss.SSS');
ERROR: invalid value ":1" for "HH"
DETAIL: Value must be an integer.
SQL state: 22007

You're trying to consume a date value that contains a T, and it looks like you're trying to declare to TO_TIMESTAMP that the T is a literal value to be ignored. Problem is you're doing this by putting 'T' (apostrophe-T-apostrophe, escaped) which is bumping the parser on by 3 characters and it is then encountering ':1' from 23:17 when it is expecting HH:
--your date, and underneath it, the format you gave
2018-10-08T23:17:44.728
yyyy-MM-dd'T'HH:mm:ss.SSS
Can you see how the HH aligns (vertically) with :1? Postgres is complaining that it was expecting an integer that it could parse to 23, but it encountered the string :1 which isn't an integer.
This question:
Postgres- have to_timestamp() ignore/not read a specific character in middle of date/time string
Implies you can put a space in the format where the T is, or just cast the string you have to a Timestamp - postgres can apparently parse that string as a Timestamp without you having to literally lay the format out for it explicitly
Try:
SELECT *
FROM history
WHERE create_time > TIMESTAMP '2018-10-08T23:17:44.728'
SELECT *
FROM history
WHERE create_time > cast('2018-10-08T23:17:44.728' as timestamp)
SELECT *
FROM history
WHERE create_time > TO_TIMESTAMP('2018-10-08T23:17:44.728','yyyy-MM-dd HH:mm:ss.SSS');
You might even find this works:
SELECT *
FROM history
WHERE create_time > TO_TIMESTAMP('2018-10-08T23:17:44.728', 'yyyy MM dd HH mm ss SSS')
The numbers align with the format fields and space is used for everything else you want to ignore (hyphens, colons, dots etc)

The problem is due to using ''T'' which's before HH, and DB signals that, you might use
TO_TIMESTAMP('2018-10-08 23:17:44.728','yyyy-mm-dd HH24:MI:SS.MS')
instead.

Related

getting sql error:hour must be between 1 and 12

There is a problem with a query I use to report.I get an error comparing a value stored as a timestamp with data saved yesterday.
query:
SELECT * FROM PIECE P, PIECE_ATTRB PA WHERE P.PIECE_NUM_ID=PA.PIECE_NUM_ID
AND PA.ATTRB_CODE='PRODUCTION_CUT_DATE'
AND PA.ATTRB_AN_VALUE >=cast(TRUNC(SYSDATE-1)+ INTERVAL '00:00:00' HOUR TO SECOND AS timestamp)
AND pa.ATTRB_AN_VALUE < CAST(TRUNC(SYSDATE)+ INTERVAL '00:00:00' HOUR TO SECOND AS timestamp)
Sample value for pa.attrb_an_value : 03-FEB-21 23:43:26,000000
But I get the following error.
hour must be between 1 and 12
you can first convert the date into timestamp. Instead of ATTRB_AN_VALUE please use
to_timestamp(substr(ATTRB_AN_VALUE,1,18),'DD.MM.YYYY HH24:MI:SSFF3')
This will convert the value into 03-FEB-21 11.43.26.000000 PM and it will eliminate the error.
Since the column attrb_an_value is not a DATE or TIMESTAMP but a VARCHAR2, you cannot compare it to a date without some casting. The TO_TIMESTAMP function will take a string and convert that to a timestamp value with a given format mask.
SELECT
*
FROM
piece p,
piece_attrb pa
WHERE
p.piece_num_id = pa.piece_num_id AND
pa.attrb_code = 'PRODUCTION_CUT_DATE' AND
TO_TIMESTAMP(pa.attrb_an_value,'DD-MON-YY HH24:MI:SS,FF6') >= TRUNC(systimestamp,'DD') - INTERVAL '1' DAY AND
TO_TIMESTAMP(pa.attrb_an_value,'DD-MON-YY HH24:MI:SS,FF6') < TRUNC(systimestamp,'DD')
Note 1: This will fail as soon as a row does not contain a string matching the DD-MON-YY HH24:MI:SS,FF6 format mask.
Note 2: As others pointed out, this is a serious design flaw. No date or timestamp data should be stored in VARCHAR2 columns.
I think your problem is about formatting the date. Here's the correct formatting. Also, I thought that you wanted result set that contained PA's ATTRB_AN_VALUE values in between the beginning of yesterday and today. So, the answer contains the simplified version of compared dates.
SELECT * FROM PIECE P, PIECE_ATTRB PA WHERE P.PIECE_NUM_ID=PA.PIECE_NUM_ID
AND PA.ATTRB_CODE='PRODUCTION_CUT_DATE'
AND to_timestamp(PA.ATTRB_AN_VALUE,'DD-MON-RR HH24:MI:SS,FF') >=to_timestamp(trunc(sysdate-1))
AND to_timestamp(pa.ATTRB_AN_VALUE,'DD-MON-RR HH24:MI:SS,FF') < to_timestamp(trunc(sysdate));

Why I get error when using TO_DATE() while converting from VARCHAR to Date data type

I am currently stuck in error which I don't understand clearly.
ORA-01843: not a valid month
01843. 00000 - "not a valid month"
*Cause:
*Action:
So far I check a couple of post here in Stackoverflow but doesn't help me so much.
I have query something like
SELECT * FROM (
SELECT uta.StartDate,uta.EndDate
FROM user_timesheets_absence uta
LEFT JOIN users u
ON u.UserID = uta.UserID
AND uta.Approved = '0'
AND
((
'2020-01-30' >= TO_DATE(uta.StartDate,'YYYY-MM-DD')
AND
'2020-02-06' <= TO_DATE(uta.EndDate,'YYYY-MM-DD')
)
OR
(
'2020-01-30' <= TO_DATE(uta.StartDate,'YYYY-MM-DD')
AND
'2020-01-30' >= TO_DATE(uta.StartDate,'YYYY-MM-DD')
))
--GROUP BY uta.UserAbsenceID
UNION
SELECT ut.DATE_ AS StartDate,
ut.DATE_ AS EndDate
FROM user_timesheets ut
INNER JOIN moments m ON
m.UserTimesheetsID = ut.UserTimesheetsID
WHERE
TO_DATE(ut.DATE_,'YYYY-MM-DD') BETWEEN '2020-01-21' AND '2020-01-30' + SYSTIMESTAMP + 1
AND ut.user_id = 1
) a
Here is the problem which StartDate and EndDate filled are VARCHAR2
I try using 'TO_TIMESTAMP' and try to change format to YYYY/MM/DD but doesn't work.
I have to be honest that I don't have any idea so far what I made wrong here.
Where I made mistake ? What is wrong here ?
UPDATE
As GMB from answer said that using validate_conversion() gives meall invalid date strings
Result
And so far from query above, when I run it I get following 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.
Some of the strings in your column are invalid dates. Starting version 12.2, it is easy to exhibit them with function validate_conversion() clause of to_date(). The following query gives you all invalid date strings:
select date_
from user_timesheets
where validate_conversion(date_ as date, 'YYYY/MM/DD') = 0
You can then fix your data.
You should consider using the date datatype to store dates, so that integrity is enforced at the time when the data is written.
In the meantime, let me suggest, however, to optimize the filtering logic: the formats of your strings make it possible to use direct filtering (without prior conversion to a date): this is more efficient, since it does not requires converting the entire column before filtering (on says that the predicate is SARGeable). Typically, you would replace something like:
to_date(uta.startdate,'yyyy/mm/dd') <= '2020-01-30'
With:
ut.startdate <= '2020/01/30'
Or if you are filtering agains the current system date:
ut.startdate <= to_char(sysdate, 'YYYY/MM/DD')
Not all startdate and enddate columns have values in YYYY/MM/DD format or - if they do - they are invalid.
For example: values like 2020/A8/43 or ab3f/xy/2i or 2020/15/02 and similar are invalid.
Error says that MM part of those strings isn't in range between 01 and 12.
First you should be storing date values using date, not strings. One possibility is that these actually are dates and you don't need to reconvert them. Without sample data, it is hard to say. But you should put your effort into fixing the data.
Second, date constants in Oracle should look like:
DATE '2020-01-30'
So:
DATE '2020-01-30' >= TO_DATE(uta.StartDate,'YYYY/MM/DD')

Select Varchar as Date

I want to select a varchar field as a date field
For example a field has this value "30.12.2011 21:15:03"
and when i select this
select DATE from TABLE where DATE = '30.12.2011'
i get no result.
You ask about getting the date part of a timestamp field, but what your question is actually about is filtering on the date of a timestamp field. There is a much simpler method of accomplishing that: you can use the knowledge that all the possible timestamps on a specific date won't have any timestamps for different dates between them.
select DATE
from TABLE
where DATE >= '30.12.2011' and DATE < '31.12.2011'
Your edit explains that you haven't got a timestamp field at all. Nevertheless, a similar approach may still work:
select DATE
from TABLE
where DATE LIKE '30.12.2011 %'
Or the Firebird-specific
select DATE
from TABLE
where DATE starting with '30.12.2011 '
Assuming the field is a date field, use the DATE introducer combined with yyyy-mm-dd (or TIMESTAMP with time as well).
So use:
select datefield from sometable where datefield = DATE '2011-12-30'
Technically you can leave off the introducer, but it is 'correcter' in the light of the SQL standard.
Assuming a TIMESTAMP field, you won't get results unless the timestamp is (always) at 00:00:00.0000 (in which case it should have been a DATE instead).
For the comparison to work, you need to use either BETWEEN, eg:
select timestampfield from sometable
where timestampfield BETWEEN '2011-12-30 00:00:00.0000' AND '2011-12-30 23:59:59.9999'
or truncate the timestamp to a date (this may adversely effect performance if the timestamp is indexed, because then the index can no longer be used), eg:
select timestampfield from sometable
where CAST(timestampfield AS DATE) = '2011-12-30'
If the date is stored in a VARCHAR field (which in itself is a bad idea), there are several solutions, first is to handle it as date manipulation:
select varcharfield from sometable
where CAST(CAST(varcharfield AS TIMESTAMP) AS DATE) = '2011-12-30'
The double cast is required if you have a time-component in VARCHARFIELD as well. This assumes dates in the supported format listed below. If you use BETWEEN as above, you can use a single cast to timestamp)
The other solution (as suggested by hvd) is to treat it purely as string manipulation, for example:
select varcharfield from sometable
where varcharfield STARTING WITH '30.12.2011'
This has its own set of problems if you want to select ranges. Bottomline: use a real TIMESTAMP field!
Note that Firebird supports multiple formats:
yyyy-mm-dd, eg 2014-05-25 (ISO-8601 format, probably best to use as it reduces confusion)
dd.mm.yyyy, eg 25.05.2014
mm/dd/yyyy, eg 05/25/2014
mm-dd-yyyy, eg 05-25-2014
dd mmm yyyy, eg 25 MAY 2014 (+ variations with a -, . or / as separator)
mmm dd yyyy, eg MAY 25 2014 (+ variations with a -, . or / as separator)
select DATE from TABLE where cast(DATE as date) = '30.12.2011'
Date field is a timestamp
Here is the answere to my question:
CAST
(
SUBSTRING
(field FROM 1 FOR 2)
||'.'||
SUBSTRING
(field FROM 4 FOR 2)
||'.'||
SUBSTRING
(field FFROM 7 FOR 4)
AS DATE)
This took me 5 hours to find this out, maybe there should be a "-" instead of "." but it works.

In Oracle, convert number(5,10) to date

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);

How can I convert a varchar field (YYYYMM) to a date (MM/01/YY) in SQL?

I'm sure this is quite simple, but I've been stuck on it for some time. How can I convert a varchar field (YYYYMM) to a date (MM/01/YY) in SQL?
Thanks.
Edit: I'm using Open Office Base (HSQL), not MySQL; sorry for the confusion.
Try the str_to_date and date_format functions. Something like:
select date_format( str_to_date( my_column, '%Y%c' ), '%c/01/%y' ) from my_table
try :
SELECT STR_TO_DATE(CONCAT(myDate,'01'),'%Y%m%d')
FROM myTable
Use STR_TO_DATE:
From mysql.com:
STR_TO_DATE(str,format)
This is the inverse of the DATE_FORMAT() function. It takes a string str and a format string format. STR_TO_DATE() returns a DATETIME value if the format string contains both date and time parts, or a DATE or TIME value if the string contains only date or time parts.
The date, time, or datetime values contained in str should be given in the format indicated by format. For the specifiers that can be used in format, see the DATE_FORMAT() function description. If str contains an illegal date, time, or datetime value, STR_TO_DATE() returns NULL. Starting from MySQL 5.0.3, an illegal value also produces a warning.
Range checking on the parts of date values is as described in Section 11.3.1, “The DATETIME, DATE, and TIMESTAMP Types”. This means, for example, that “zero” dates or dates with part values of 0 are allowed unless the SQL mode is set to disallow such values.
mysql> SELECT STR_TO_DATE('00/00/0000', '%m/%d/%Y');
-> '0000-00-00'
mysql> SELECT STR_TO_DATE('04/31/2004', '%m/%d/%Y');
-> '2004-04-31'
Get the year:
SUBSTRING(field FROM 2 FOR 2)
Get the month:
SUBSTRING(field FROM -2 FOR 2)
Compose the date:
CONCAT(SUBSTRING(field FROM -2 FOR 2), '/01/', SUBSTRING(field FROM 2 FOR 2))
This will convert from YYYYMM to MM/01/YY.
To be clear: if you're looking for method to convert some value of type Varchar/Text to value of type Date than solutions are:
using CAST function
CAST(LEFT('201205',4)||'-'||SUBSTRING('201205' FROM 5 FOR 6)||'-01' AS DATE)
starting from OpenOffice 3.4 (HSQLDB 2.x) new Oracle-like function TO_DATE supposed to be available
TO_DATE('201205','YYYYMM')
in addition to the written i can mention that you also can construct a string with ANSI/ISO 'YYYY-MM-DD' formatted representation of the date,- Base will acknowledge that and succesfully convert it to the Date type if necessary (e.g. INSERTing in Date typed column etc.)
Here is doc's on HyperSQL and highly recommended OO Base guide by Andrew Pitonyak