Spring Boot JPA - SQL error on native query double apostrophe - spring

I have a large query that works perfectly fine in normal postgres, but when I run in a JPA native query I get the following error:
org.postgresql.util.PSQLException: ERROR: syntax error at or near ":"
The query contains the following line:
...
WHERE year = extract( year FROM CURRENT_DATE - '2 month'::interval)::int
and month = extract( month FROM CURRENT_DATE - '2 month'::interval)::int
...
I tried escaping by adding a \ before each apostrophe but the code won't compile:
error: illegal escape character
" WHERE year = extract( year FROM CURRENT_DATE - '2 month'\:\:interval)\:\:int and month = extract( month FROM CURRENT_DATE - '2 month'\:\:interval)\:\:int \n" +
Is it not possible to use :: in a native query? Again this works perfectly fine when run normally.

You can avoid the headache figuring the necessary escape sequence completely. Postgres uses the double colon (::) as a proprietary CAST operation, but the SQL standard is supported. Also, rather than casting the character string '2 month' as an interval you can declare it as such by prefixing it. Your clause then becomes:
where year = cast (extract( year FROM CURRENT_DATE - interval '2 month') as integer)
and month = cast (extract( month FROM CURRENT_DATE - interval '2 month') as integer)
No escape required. And makes it a lot easier to read (i.e. understand).

Related

Trying to calculate difference between two date in format (00-00-0000 00:00:00 ) in minutes in oracle

I have date in following format a_time=01-06-2020 15:28:06 & b_time=01-06-2020 15:39:00 in table t_mst
and i want to convert diff of given values in queries in minutes
select (extract( day from diff )*24*60*60 +
extract( hour from diff )*60*60 +
extract( minute from diff )*60 +
extract( second from diff ))/60 total_Minutes
from(select b_time - a_time diff
from t_mst Where a_time between (trunc(sysdate, 'mm')) and (sysdate))
But getting Error "Invalid extract field for extract source"
any idea would be appreciated.
The error you show means that b_time - a_time worked. Which means they are in date (or perhaps timestamp) data type; that is good.
Then, they must be date; if they were timestamp then the difference would be interval data type, and you can indeed extract time elements from interval. So, the error message suggests that the data type of a_time and b_time is indeed date.
Now: In Oracle, the difference between two dates is a number (in days); you can't extract time elements from a number. Instead, consider that the difference is already a number of days (including a fractional part); to convert it to minutes, you only have to multiply it by 1440 - and then round the result, if needed.
You have tagged with 3 databases and the code is for postgreSQL. I assume you meant, postgreSQL:
select (extract( epoch from age(a_time, b_time)/60) total_Minutes
from t_mst
--Where a_time between (trunc(sysdate, 'mm')) and (sysdate))
If you need it casted to int:
select (extract( epoch from age(a_time, b_time)/60)::int total_Minutes
from t_mst
PS: Not sure you meant plSQL or PL\pgSQL.
If b_timeand a_time data types are DATE you can simply run
select (b_time - a_time) * 24*60 AS total_Minutes
from t_mst
Where a_time between trunc(sysdate, 'mm') and sysdate
In case they are TIMESTAMP data type you have to extract the values, e.g. like this:
select
EXTRACT(DAY FROM (b_time - a_time))*24*60
+ EXTRACT(HOUR FROM (b_time - a_time))*60
+ EXTRACT(MINUTE FROM (b_time - a_time))
+ EXTRACT(SECOND FROM (b_time - a_time))/60
AS total_Minutes
from t_mst
Where a_time between trunc(sysdate, 'mm') and sysdate

Date conversion from regexp output data -- ORA-01841: (full) year must be between -4713 and +9999, and not be 0

I am trying to convert a value to the normal date format. But i am receiving the error ORA-01841: (full) year must be between -4713 and +9999, and not be 0 . I have researched the answers for a similar question in this website but that doesn't address my issue.
-- How the data looks like
select REPLACE(REGEXP_SUBSTR(data_detail, '([^|]*)([$|]|$)', 1, 5), '|', '') from land.LAND_DATA;
Output
2017-11-16T04:45:05.000Z
2017-11-16T04:46:04.000Z
When i am trying to convert the above mentioned output in to an appropriate date format i am receiving the error. What mistake am i doing here
select
TO_DATE(
TO_CHAR(
TO_TIMESTAMP(
REPLACE(REGEXP_SUBSTR(data_detail, '([^|]*)([$|]|$)', 1, 5), '|', ''),
'YYYY-MM-DD"T"HH24:MI:SS.ff3"Z"'),'MM/DD/YYYY HH24:MI:SS'),
'MM/DD/YYYY HH24:MI:SS')
from land.LAND_DATA;
These results are input data for the TO_TIMESTAMP function:
2017-11-16T04:45:05.000Z
2017-11-16T04:46:04.000Z
A year comes first, then a month and a day, and a time follows, which has milliseconds at the very end (after the comma).
This is a snippet from your code:
TO_TIMESTAMP( ....... , 'MM/DD/YYYY HH24:MI:SS' )
the second parameter is a date format model, these letters have the following meaning (in order):
MM - Month (01-12; January = 01).
/ - separator
DD - Day of month (1-31)
/ - separator
YYYY - 4-digit year; S prefixes BC dates with a minus sign.
- separator (space)
HH24 - Hour of day (0-23).
: - separator
MI - Minute (0-59).
: - separator
SS - Second (0-59).
The above format models doesn't match a format of input data, because a month comes first in this format, but your data starts with a year !!!
Use the following format instead:
'yyyy-mm-dd"T"hh24:mi:ss.ff"Z"'
You can test whether a format is fine or gives an error using a simple query like this:
select
to_timestamp( '2017-11-16T04:45:05.000Z', 'yyyy-mm-dd"T"hh24:mi:ss.ff"Z"')
from dual;
TO_TIMESTAMP('2017-11-16T04:4
-----------------------------
2017/11/16 04:45:05.000000000

Single Month Digit Date Format issue in Oracle

Am getting the below issue when am using 'mon-d-yyyy' to convert date to char, as i need a single day digit for values from 1 to 9 days in a month.
When i use the 'mon-d-yyyy' format, am losing out on 5 days and getting a wrong date. Any help on this would be great.
select to_char(sysdate-22,'mon-d-yyyy') from dual;--aug-2-2017
select to_char(sysdate-22,'mon-dd-yyyy') from dual;--aug-07-2017
select sysdate-22 from dual;--07-AUG-17 11.06.43
In Oracle date formats, d gets the day of week. The 2 in your output means monday, not august the 2nd.
Try using Fill Mode as Format Model Modifier
select to_char(sysdate-22,'mon-fmdd-yyyy') from dual;
One option might be to piece together the date output you want:
SELECT
TO_CHAR(sysdate-22, 'mon-') ||
TRIM(LEADING '0' FROM TO_CHAR(sysdate-22, 'dd-')) ||
TO_CHAR(sysdate-22, 'yyyy')
FROM dual;
The middle term involving TRIM strips off the leading zeroes, if present, from the date.
Output:
Demo here:
Rextester
SQL>SELECT TO_CHAR(TO_DATE('29-AUG-2017','DD-MON-YYYY') - 22,'"WEEKDAY :"D, MON-FMDD-YYYY') "Before22Days" FROM DUAL;
D- Gives you a numeric weekday(2nd weekday in a week) on AUG-07-2017.
DD-Gives a Numeric Month Day i.e,07th
FMDD-Gives 7th
Before22Days
----------------------
WEEKDAY :2, AUG-7-2017

Oracle DB Ora-01839: date not valid for month specified. 29-02-2016 leap year

We all know today is a special day. Its the 29th of February 2016 of a leap year.
We receive an error message from some tables in our Oracle DB. The error is:Oracle ORA-01839: date not valid for month specified.
For example a simple select where the error occurs:select * from table where table_date > sysdate -0.1;
For other tables this select makes no problem, just for some of the tables.
Is there a way to fix this issue? Because we are not able to use many tables today.
We are using Oracle 12c.
After intensive research, its clear why some of our selects does not work today. The error is caused by the keyword interval and its a known issue. (Or it's how the ANSI/ISO spec says it should work, bottom of page 205/top of page 206)
Here is a qoute from the oracle community blog:
Question:
select to_date('2012-feb-29','yyyy-mon-dd') + interval '1' year as dt from dual;
ORA-01839: date not valid for month specified
01839. 00000 - "date not valid for month specified"
*Cause:
*Action:
select to_date('2012-feb-29','yyyy-mon-dd') + interval '2' year as dt from dual;
ORA-01839: date not valid for month specified
01839. 00000 - "date not valid for month specified"
*Cause:
*Action:
select to_date('2012-feb-29','yyyy-mon-dd') + interval '3' year as dt from dual;
ORA-01839: date not valid for month specified
01839. 00000 - "date not valid for month specified"
*Cause:
*Action:
select to_date('2012-feb-29','yyyy-mon-dd') + interval '4' year as dt from dual;
29-FEB-16 00:00:00
select to_date('2012-feb-29','yyyy-mon-dd') + interval '1' day as dt from dual;
01-MAR-12 00:00:00
select to_date('2012-feb-29','yyyy-mon-dd') + interval '1' month as dt from dual;
29-MAR-12 00:00:00
Answer:
That's just how INTERVALs work. Leap years are the least of the
problem; adding 1 month to March 31 results in the same error. If you
want to make sure that the result is a valid DATE, then use
ADD_MONTHS. (There's no separate function for adding years; use
ADD_MONTH (SYSDATE, 12*n) to get the DATE that is n years from now.)
Why it happens in our case:
In our case, we used virtual private database for some of our tables because of security reasons. And there we applied the interval keyword in most of the selects.
What to do instead:
Use ADD_MONTHS instead.
select add_months(to_date('2012-feb-29','yyyy-mon-dd'), 12) as dt from dual;

Oracle ORA-01839: date not valid for month specified Leap Year

Oracle 11g
here is a quick one hopefully.
Below is part of a script that gets date only from from the next month
first day of next month to last day. But today 29th feb it thrown an error of
ORA-01839: date not valid for month specified
M.MS_DATE between trunc(sysdate + interval '1' month,'MM') and last_day(sysdate + interval '1' month)
Is there a way round this. Many thanks
I have seen this as well and I consider this a bug in Oracle.
The workaround is to use add_months() instead :
between trunc(add_months(sysdate,1),'MM') and last_day(add_months(sysdate,1));
I would probably use add_months() as a_horse_with_no_name suggests, but just as an alternative if you want to use intervals, you can move the point you do the truncation in the first expression, and include the same truncation in the second expression:
select trunc(sysdate, 'MM') + interval '1' month as first_day,
last_day(trunc(sysdate, 'MM') + interval '1' month) as last_day
from dual;
FIRST_DAY LAST_DAY
---------- ----------
2015-02-01 2015-02-28
This works because all months have a first day, so you don't trip over the documented caveat.
When interval calculations return a datetime value, the result must be an actual datetime value or the database returns an error

Resources