I need to support both, Oracle und SQL Server. I have pretty identical procedures named get_current_date in both DBs. Now I have a query:
SELECT col1, col2 FROM table WHERE colDate < get_current_date()
This works beautifully in Oracle but lacks the dbo. prefix when executed in SQL Server.
Should Spring be able to handle that? What other options do I have? I dont think it should be necessary to determine the DB type myself.
Thank you!
Every JDBC driver should support the JDBC function escapes (defined in section 13.4.1 and listed in appendix D of the JDBC 4.1 spec). For the CURRENT_DATE it is CURRENT_DATE or CURRENT_DATE().
You can call this in a query as
SELECT col1, col2 FROM table WHERE colDate < {fn CURRENT_DATE}
You can query the list of supported functions of your specific driver with DatabaseMetaData.getTimeDateFunctions()
BTW: This assumes you just want the current date of the database. It is not a general solution for calling user defined functions in your query.
Should Spring be able to handle that?
--> get_current_date() is database method/procedure (may it be of database or your custom) so it is dependent on database, Spring would not take care of that.
What other options do I have?
--> Well you can put current date in query in code so it will be independent of database what you use. Something like :
String sql = "SELECT col1, col2 FROM table WHERE colDate < " + new Date();
How about get current date in java something like:
Calendar cal = Calendar.getInstance();
currentDate = cal.getTime();
and then you do:
SELECT col1, col2 FROM table WHERE colDate < currentDate
Related
I use spring boot, and I want to add 1 year to a specific column in mysql database
String queryRecherche = "UPDATE myTable t SET t.dateDebut = DATE_ADD(t.dateDebut, INTERVAL 1 YEAR) WHERE.id = 3 ";
Query query = em.createQuery(queryRecherche);;
query.executeUpdate();
But I get the folowing error :
org.hibernate.query.sqm.ParsingException: line 1:66 no viable alternative at input 'DATE_ADD(t.dateDebut,INTERVAL1'
Have you please any suggestions to do this.
You're using Hibernate 6 (I can tell by the error message), so the correct HQL syntax to use is:
UPDATE MyEntity t SET t.dateDebut = t.dateDebut + 1 year WHERE t.id = 3
You had three errors in your query:
You referred to the name of a table instead of the name of an entity class in the UPDATE clause.
You used the unportable MySQL DATE_ADD function instead of the portable HQL date/time arithmetic described here.
The syntax of your WHERE clause was garbled.
Perhaps you meant for this to be a native SQL query, in which case you called the wrong method of Session. But there's no need to use native SQL for the above query. As you can see, HQL is perfectly capable of expressing that query.
You can use SQL directly, via createNativeQuery, or register a new function as shown in this example to call it from HQL
I'm using Java 8 with Spring's JdbcTemplate and Oracle 12.1,
I want to update record and get the exact time record was updated
jdbcTemplate.update(UPDATE_SQL, null);
Currently it returns (int) the number of rows affected, but I want the exact updated date
Must I send a new request to get current time which may be inaccurate?
More exact will be to save in column updated date, but then to execute another SQL
Is there another option to get updated date in one query?
Obviously, I don't want to use get date from code also (as new Date()) also because server time is/can be different than DB Time
You decided to use JDBCTemplate most probably to simplify the code in comparison to plain JDBC.
This particular problem IMHO makes the plain JDBC solution as proposed in other answer much simpler, so I'd definitively recommend to get the database connection from JDBCTemplate and make the insert in a JDBC way.
The simplest solution using JDBCTemplate that comes to my mind is to wrap the insert in a PROCEDURE and return the timestamp as an OUT parameter.
Simple example (Adjust the time logik as required)
create procedure insert_with_return_time (p_str VARCHAR2, p_time OUT DATE) as
BEGIN
insert into identity_pk(pad) values(p_str);
p_time := sysdate;
END;
/
The call is done using SimpleJdbcCall
SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName("insert_with_return_time");
SqlParameterSource params = new MapSqlParameterSource().addValue("p_str", str);
Map<String, Object> out = jdbcCall.execute(params);
The Map contains the returned value e.g. [P_TIME:2019-10-19 11:58:10.0]
But I can only repeat, in this particular use case is IMHO JDBC a rescue from JDBCTemplate;)
You're right that passing new Date() would store the server time rather than the DB time.
To store the DB time you can set your timestamp to the DB system timestamp systimestamp then you could run a query to retrieve that row and its updated timestamp.
If you want to update the row and get the updated timestamp in a single execution then you could do the following using RETURNING INTO where TimestampUpdated is your column name:
Connection con = ...;
String sql = "UPDATE TableName SET <updates> , TimestampUpdated = systimestamp RETURNING TimestampUpdated INTO ?";
CallableStatement statement = con.prepareCall(sql);
statement.registerOutParameter(1, Types.TIMESTAMP);
int updateCount = statement.executeUpdate();
Timestamp timestampUpdated = statement.getInt(1);
System.out.println("Timestamp Updated = " + timestampUpdated);
Here is a related link doing this with JdbcTemplate
I'm using Java 8 with Spring's JdbcTemplate and Oracle 12.1,
I want to update record and get the exact time record was updated
jdbcTemplate.update(UPDATE_SQL, null);
Currently it returns (int) the number of rows affected, but I want the exact updated date
Must I send a new request to get current time which may be inaccurate?
More exact will be to save in column updated date, but then to execute another SQL
Is there another option to get updated date in one query?
Obviously, I don't want to use get date from code also (as new Date()) also because server time is/can be different than DB Time
You decided to use JDBCTemplate most probably to simplify the code in comparison to plain JDBC.
This particular problem IMHO makes the plain JDBC solution as proposed in other answer much simpler, so I'd definitively recommend to get the database connection from JDBCTemplate and make the insert in a JDBC way.
The simplest solution using JDBCTemplate that comes to my mind is to wrap the insert in a PROCEDURE and return the timestamp as an OUT parameter.
Simple example (Adjust the time logik as required)
create procedure insert_with_return_time (p_str VARCHAR2, p_time OUT DATE) as
BEGIN
insert into identity_pk(pad) values(p_str);
p_time := sysdate;
END;
/
The call is done using SimpleJdbcCall
SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName("insert_with_return_time");
SqlParameterSource params = new MapSqlParameterSource().addValue("p_str", str);
Map<String, Object> out = jdbcCall.execute(params);
The Map contains the returned value e.g. [P_TIME:2019-10-19 11:58:10.0]
But I can only repeat, in this particular use case is IMHO JDBC a rescue from JDBCTemplate;)
You're right that passing new Date() would store the server time rather than the DB time.
To store the DB time you can set your timestamp to the DB system timestamp systimestamp then you could run a query to retrieve that row and its updated timestamp.
If you want to update the row and get the updated timestamp in a single execution then you could do the following using RETURNING INTO where TimestampUpdated is your column name:
Connection con = ...;
String sql = "UPDATE TableName SET <updates> , TimestampUpdated = systimestamp RETURNING TimestampUpdated INTO ?";
CallableStatement statement = con.prepareCall(sql);
statement.registerOutParameter(1, Types.TIMESTAMP);
int updateCount = statement.executeUpdate();
Timestamp timestampUpdated = statement.getInt(1);
System.out.println("Timestamp Updated = " + timestampUpdated);
Here is a related link doing this with JdbcTemplate
I'm attempting to convert an Oracle MERGE statement to a MySQL Update statement. This particular MERGE statement only does an update (no inserts), so am unclear why the previous engineer used a MERGE statement.
Regardless, I know need to convert this to MySQL and am not clear as to how this is done. (side note, I'm doing this within a JAVA App)
Here is the MERGE statement :
MERGE INTO table1 a
USING
(SELECT DISTINCT(ROWID) AS ROWID FROM table2
WHERE DATETIMEUTC >= TO_TIMESTAMP('
formatter.format(dWV.getTime())
','YYYY-MM-DD HH24:MI:SS')) b
ON(a.ROWID = b.ROWID and
a.STATE = 'WV' and a.LAST_DTE = trunc(SYSDATE))
WHEN MATCHED THEN UPDATE SET a.THISIND = 'S';
My attempts goes something like this :
UPDATE table1 a
INNER JOIN table2 b ON (a.ROWID = b.ROWID
and a.STATE = 'WV'
and a.LAST_DTE = date(sysdate()))
SET a.THISIND = 'S'
WHERE DATETIMEUTC >= TO_TIMESTAMP('formatter.form(dWV.getTime())', 'YYYY-MM-DD HH24:MI:SS')
However, I'm unclear if this is actually doing the same thing or not?
As noted by you, the original Oracle MERGE statement only performs updates, no inserts.
The general syntax of your MySQL query looks ok compared to the Oracle version. Here is an updated version :
UPDATE table1 a
INNER JOIN table2 b
ON a.ROWID = b.ROWID
AND b.DATETIMEUTC >= 'formatter.form(dWV.getTime())'
SET a.THISIND = 'S'
WHERE
a.STATE = 'WV'
AND a.LAST_DTE = CURDATE()
Changes :
current date can be obtained with function CURDATE()
'YYYY-MM-DD HH24:MI:SS' is the default format for MySQL dates, hence you do not need to convert it, you may just pass it as is (NB1 : it is unclear what 'formatter.form(dWV.getTime())' actually means - NB2 : if you ever need to translate a string to date, STR_TO_DATE is your friend)
the filter conditions on table a are better placed in the WHERE clause, while those on table b would better belong in the INNER JOIN
I have a SQL statement and trying execute with H2 in-memory database in Java. The following exception thrown.
SQL:
SELECT ACCT_RULE_ID, ACCT_ACTION_ID
FROM ACCT_RULE
WHERE (ACCT_ACTION_ID = ?)
AND (START_DATETIME <= to_char(?, 'mm/dd/yyyy HH:MI:SS AM'))
AND (STOP_DATETIME > to_char(?, 'mm/dd/yyyy HH:MI:SS AM'))
Replacing first parameter with Id and second and third parameter with new Date() value.
Exception:
Caused by: org.h2.jdbc.JdbcSQLException: Function "TO_DATE" not found; SQL statement:
you should be able to create your own to_date function
drop ALIAS if exists TO_DATE;
CREATE ALIAS TO_DATE as '
import java.text.*;
#CODE
java.util.Date toDate(String s, String dateFormat) throws Exception {
return new SimpleDateFormat(dateFormat).parse(s);
}
'
Of course you could also just use parsedatetime() per David Small's answer
One way to remove the time portion from a date-time field in H2, is to format the field as a string and then parse it. This worked for me:
PARSEDATETIME(FORMATDATETIME(field_name, 'yyyy-MM-dd'), 'yyyy-MM-dd')
H2's parse and format date functions follow the java.text.SimpleDataFormat semantics.
Yes, it is NOT super optimized. This is fine for our needs since we only use H2 for unit tests.
H2 database does not have TO_CHAR() function. But H2 database does have sysdate, dual, varchar2 which makes writing oracle query that will run on H2 database quite easy. So you can write a function instead which will H2 database function alias for making it handle date/timestamp with format. TO_CHAR(sysdate, 'DD/MM/YYYY HH24:MI:SS') can be used in H2 database.
Despite the lack of documentation there are TO_DATE function in PostgreSQL compatibility mode since 2.0.204.
Changelog ticket