Query with NOW() in criteria behaves differently in psql vs. JDBC - java

I am executing following query in psql via console and getting output :
select details
from history_transactions
,history_operations
where history_operations.transaction_id = history_transactions.id
and type = 3
and created_at >= NOW() - INTERVAL '5 minutes'
However when I call this code from my java program, it is not returning any output. The ResultSet is null. PFB my code:
Connection conn = getConnection();
java.sql.Statement stmt = null;
String sql ="select details from history_transactions , history_operations where history_operations.transaction_id=history_transactions.id and type =3 and created_at >= NOW() - INTERVAL '5 minutes'";
try{
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
while(rs.next()) {
System.out.println("Inside resultset");
}
}
catch(Exception e)
{
e.printStackTrace();
}
Any idea where I am going wrong?
I am not getting any exception as well.
Note: If I change the interval from 5 minute to 6 hours or more it is working and giving me output. If I change the interval < 5 hours then the resultset is null. However If I login to psql server and execute the query as it is in the code. I am getting output.
I am using java version "1.8.0_151" and PostgreSQL JDBC 4.2 Driver, 42.2.1 - as per https://jdbc.postgresql.org/download.html - it is the suitable driver.

The PostgreSQL NOW() function returns a timestamp with time zone value. In order to use that value against a column of type timestamp (without time zone) PostgreSQL needs to implicitly CAST that value to match the column type. However, testing shows that if the client and the server are set to different time zones the result of that CAST can be different when connected via psql vs. when connected via JDBC. For example:
Server time zone: UTC
Client time zone: America/Denver, a.k.a. "MST/MDT", currently UTC-7
When connected via psql,
SELECT CAST(CAST(NOW() AS timestamp) AS varchar)
returns the UTC value
2018-02-05 22:40:25.012933
but when connected via JDBC the same query returns the MST value
2018-02-05 15:40:57.288587
To return the UTC value under JDBC we can execute
set time zone 'UTC'
before running our SELECT query.

Related

Oracle - update record and return updated date in same query

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

Fetching time zones using different Application Servers produces Unexpected results

I have two applications with different time zones.
Application 1: -Duser.timezone=Australia/Darwin
Application 2: -Duser.timeZone=Asia/Kolkata
Application 1 inserts TimeStamp based on Zone1 and Application2 inserts TimeStamp based on Zone2.
While fetching data from Application1, Zone conversion is not done.
Instead it displays the same result.
Values inserted to DB:
2019-02-19 15:39:40 - Application1
2019-02-19 11:40:09 - Application2
Output when fetched from Application 1/ Application2
Time Stamp from DB: 2019-02-19 15:39:40.0
Time Stamp from DB: 2019-02-19 11:40:09.0
For Example , if data is read from Application 1, time Stamp should be displayed according to Austria/Darwin.
How to achieve this?
Here is the code snippet.
String selectSQL = "select createdtime from TZ_TEST6";
PreparedStatement ps = conn.prepareStatement(selectSQL);
ResultSet rs = ps.executeQuery(selectSQL );
while (rs.next())
{
Timestamp timestamp = rs.getTimestamp(1);
System.out.println("Time Stamp from DB: " +timestamp);
}

Timestamp insert issue in Mysql from Oracle

I am trying to insert the timestamp value from oracle to mysql timestamp column.
oracle value is 2017-09-01 11:35:22.495000000 but while getting value from result set its giving 2017-09-01 11:35:22.495.
its stored in oracle using oracle.sql.timestamp and i cannot insert the value in mysql.so getting stringvalue or timestamp value from oracle.sql.timestamp API.
But mysql storing the value is 2017-09-01 11:35:22.000495 and datatype defined as timestamp (6) and am not sure why its inserting the value like this?
How i can store the value in mysql similar to oracle ?
Using JDBC you should be able to directly copy a timestamp from one database to another doing something like this:
try(Connection oracleConnection = getOracleConnection();
Connection mysqlConnection = getMySQLConnection();
PreparedStatement oracleStmt = oracleConnection.prepareStatement("SELECT my_time FROM oracle_table");
PreparedStatement mysqlStmt = mysqlConnection.prepareStatement("INSERT INTO mysql_table VALUES (?)");
ResultSet rs = oracleStmt.executeQuery()) {
while(rs.next) {
mysqlStmt.setTimestamp(1, rs.getTimestamp("my_time"));
mysqlStmt.execute();
}
}
Timestamps are essentially numeric datatypes. Different DBMS's can have different precisions and different ways of handling timezones, but you shouldn't need any database specific API's to interact with them in most cases.
If you need to format a Timestamp you can use SimpleDateFormat on what you get back from getTimestamp() to format the string any way you need to.

JDBC PreparedStatement - setTimestamp does not save the time

I am trying to save a timestamp to a SQL DB with the following line inside a PreparedStatement
ps.setTimestamp(5, new Timestamp(ITEM.getModifiedTime().getTime()));
When I debug and inspect the PreparedStatement I can see the date and the time with the Java and SQL types being timestamp but when I look at the DB the field appears like this
2016-08-08 00:00:00.000
How can I get the time to come through? I am using SQL Server 2008

Java JDBC Procedure Call

I have a oracle procedure that takes date as a parameter and gets called by two different Java web apps, within the procedure I extract the day using to_char(date, 'd') from the date passed. I am unable to find out why the day returned by one app is different from other. I am using same ojdbc driver for both of the apps. Does it have anything to do with machine env variable these apps are running at?
Thanks
this is because the first day of the week is not the same in all countries, for example in Europe the first day of the week is Monday while in the US it is Sunday. Consider:
SQL> select * from nls_session_parameters where parameter = 'NLS_TERRITORY';
PARAMETER VALUE
------------------------------ ----------------------------------------
NLS_TERRITORY AMERICA
SQL> select to_char(date '2010-12-07', 'D') from dual;
TO_CHAR(DATE'2010-12-07','D')
-----------------------------
3
SQL> alter session set nls_territory=FRANCE;
Session altered
SQL> select to_char(date '2010-12-07', 'D') from dual;
TO_CHAR(DATE'2010-12-07','D')
-----------------------------
2
Set the session parameter NLS_TERRITORY at the beginning of the procedure if it depends on it.
Try to explicitly specify the timezone on both of your webapp containers by passing them the -Duser.timezone="America/New_York" VM argument (adjust per your timezone needs) when startingup them.
To address your comment, in the application level you could explicitly specify the desired timezone when calling your stored proc. For example:
CallableStatement statement = null;
Connection conn = null;
try {
conn = getYourConnection();
Calendar dbCal = new GregorianCalendar(YOUR_DATABASE_TIMEZONE);
String sql = "begin schema_name.package_name.stored_proc(var1=>?, " +
"var2=>?); end;";
statement = conn.prepareCall(sql);
statement.setInt(1, something);
statement.setTimestamp(2, yourDate.getTime(), dbCal);
statement.execute();
conn.commit();
} finally {
if (statement!=null) statement.close();
if (conn!=null) conn.close();
}
try to check the default locale in JAVA/Oracle in both the applications.
I think that it may depend on the default locale set in JAVA.

Categories

Resources