I have a query to test two dates against two timestamp columns in the table if they overlap or not.
Query is working fine in the database client but when i added it in my java code it fails with an exception error.
I need to know how to format the && symbols in the query to be able to work.
SELECT count(*)
FROM attendance_jobs
WHERE tsrange( start_date, end_date) && tsrange(TIMESTAMP '2019-04-22', TIMESTAMP '2019-03-22 ')
Here is my java code:
long count = jdbi.withHandle(handle -> {
return handle.createQuery("select count(*) from attendance_jobs where tsrange(start_date, end_date) && tsrange(timestamp :start_date, timestamp :end_date)")
.bind("start_date", start_date)
.bind("end_date", end_date)
.mapTo(Long.class)
.findOnly();
});
The start_date and end_date data type is Timestamp.
org.jdbi.v3.core.statement.UnableToExecuteStatementException: org.postgresql.util.PSQLException: ERROR: syntax error at or near "$1"
This is just guesswork, but I think you should have a look at the usage of :start_date and :end_date again:
If start_date and end_date (java variables) are of type Timestamp you should remove the timestamp prefix to :start_date and :end_date in the query. As the documentation says, the java type Timestamp is supported by jdbi:
Out of the box, Jdbi supports the following types as SQL statement arguments:
* ...
* java.sql: Blob, Clob, Date, Time, and Timestamp
* ...
So my guess is that you have to use the query like this:
long count = jdbi.withHandle(handle -> {
return handle.createQuery("select count(*) from attendance_jobs where tsrange(start_date, end_date) && tsrange(:start_date, :end_date)")
.bind("start_date", start_date)
.bind("end_date", end_date)
.mapTo(Long.class)
.findOnly();
});
Also, but this may be personal taste, I recommend to use different spelling of bind variables and database columns. The latter with underscores (as you did), the other in camel case so it is less confusing if you use similar names. Also, it is uncommon to use underscores in java variables, so the code would look similar to this in my spelling:
Timestamp startDate = ...;
Timestamp endDate = ...;
String queryString = "select count(*) from attendance_jobs "
+ "where tsrange(start_date, end_date) && tsrange(:startDate, :endDate)";
long count = jdbi.withHandle(handle -> {
return handle.createQuery(queryString)
.bind("startDate", startDate)
.bind("endDate", endDate)
.mapTo(Long.class)
.findOnly();
});
Related
I have an insert query where along with other fields , I am inserting Timestamp. Now whenever, value of Timestamp is null, I am getting the error -
java.sql.SQLException: ORA-00932: inconsistent datatypes: expected DATE got BINARY
I am using oracle 11g.
Query is :
#Modifying
#Query(value ="INSERT INTO mams_asset a ( a.mams_asset_id, a.mams_folder_id, a.asset_name, a.gist, a.last_modified_date, a.last_exported_date, a.created_date ) VALUES (hextoraw(?1), hextoraw(?2), ?3, ?4, ?5, ?6 , ?7)" , nativeQuery = true)
int insertIntoMamsAsset(String mamsAssetId, String mamsFolderId, String assetName, String gist, Timestamp lastModifiedDate, Timestamp lastExportedDate, Timestamp createdDate);
This is though spring data JPA one. I tried using this approach too but same error:
public int insertIntoMamsAsset(String mamsAssetId, String mamsFolderId, String assetName, String gist, Timestamp lastModifiedDate, Timestamp lastExportedDate, Timestamp createdDate){
final Query query = entityManager.createNativeQuery("INSERT INTO mams_asset a ( a.mams_asset_id, a.mams_folder_id, a.asset_name, a.gist, a.last_modified_date, a.last_exported_date, a.created_date ) VALUES (hextoraw(?), hextoraw(?), ?, ?, ?, ? , ?)")
.setParameter(1, mamsAssetId)
.setParameter(2,mamsFolderId)
.setParameter(3,assetName)
.setParameter(4,gist)
.setParameter(5,lastModifiedDate)
.setParameter(6,lastExportedDate)
.setParameter(7,createdDate);
return query.executeUpdate();
}
Though the query seems long but you can focus only on Timestamp field that's what is generating error.
What is the work around for this ?
This worked for me
final Query query = entityManager.createNativeQuery("INSERT INTO mams_asset a ( a.mams_asset_id, a.mams_folder_id, a.asset_name, a.gist, a.last_modified_date, " +
"a.last_exported_date, a.created_date ) VALUES (hextoraw(?), hextoraw(?), ?, ?, ?, ? , ?)")
.setParameter(1, mamsAssetId)
.setParameter(2, mamsFolderId)
.setParameter(3, assetName)
.setParameter(4, gist)
.setParameter(5, lastModifiedDate, TemporalType.TIMESTAMP)
.setParameter(6, lastExportedDate, TemporalType.TIMESTAMP)
.setParameter(7, createdDate, TemporalType.TIMESTAMP);
I added TemporalType.TIMESTAMP in setParameter.
It happens cause your table dont admit null value for last_modified_date.
Try to check if the input value lastModifiedDate is null or no before launche the query like this
if(lastModifiedDate = null){
Timestamp myModifiedDate = new Timestamp(0001-01-01 00:00:00);
}
Or simply change the database like this:
ALTER TABLE table_name MODIFY COLUMN date TIMESTAMP NULL
This oracle message is happens when you try to insert a value to a column from different types for more detail :
http://www.dba-oracle.com/sf_ora_00932_inconsistent_datatypes_expected_string_got_string.htm
now to insert a date value better to use Calendar class or Date class.
I try to retrieve records from ORACLE database table using JDBC thin driver.
The prepared statement I'm using:
(1)
SELECT (t1.LOGGED_TIME - ?) AS TDIFF, t1.ID, t1.STATUS, t1.LOGGED_TIME, t1.SERVER_TIME
FROM table_1 t1
WHERE (
((t1.LOGGED_TIME - ?) <= INTERVAL '10' DAY)
AND ((t1.LOGGED_TIME - ?) >= INTERVAL '-10' DAY))
ORDER BY t1.LOGGED_TIME DESC
where t1.LOGGED_TIME represents a timestamp column. Every three parameters are identical timestamps set with
java.sql.Timestamp controlTime = Timestamp.valueOf("2014-08-15 03:52:00");
lookupTime.setTimestamp(1, controlTime);
lookupTime.setTimestamp(2, controlTime);
lookupTime.setTimestamp(3, controlTime);
Executing the code works fine - no exceptions or warnings are displayed. Nevertheless the resultset returned by
rs = lookupTime.executeQuery();
is empty.
Setting the query to
(2)
SELECT (t1.LOGGED_TIME - TO_TIMESTAMP('2014-08-15 03:52', 'yyyy-mm-dd hh24:mi')) AS TDIFF, t1.ID, t1.STATUS, t1.LOGGED_TIME, t1.SERVER_TIME
FROM table_1 t1
WHERE (
((t1.LOGGED_TIME - TO_TIMESTAMP('2014-08-15 03:52', 'yyyy-mm-dd hh24:mi')) <= INTERVAL '10' DAY)
AND ((t1.LOGGED_TIME - TO_TIMESTAMP('2014-08-15 03:52', 'yyyy-mm-dd hh24:mi')) >= INTERVAL '-10' DAY))
ORDER BY t1.LOGGED_TIME DESC
returns the expected data.
When I query e.g. strings from another column of the same table with a prepared statement the result is ok.
What I'm missing here? Where is the point? Any idea?
To say it clear: the point is not to identify a kind of wrong date/time format conversion in (2). That will always lead to an oracle error message and can be fixed easily.
The question is: why stays the RecordSet returned by the preparedStatement (1) empty (= not a single record) without any error notification? If the Timestamp format is wrong in any way, why there isn't an error or a warning?
Check your TO_TIMESTAMP format:
TO_TIMESTAMP('2014-08-15 03:52',
'dd.mm.yy hh24:mi')
Aug. 14, 2015, not Aug. 15, 2014
Update
Actually, I get the following error when trying that one:
ORA-01843: not a valid month
01843. 00000 - "not a valid month"
Update2
A Java Timestamp maps to an Oracle DATE data type, not a TIMESTAMP. Don't know if that makes a difference, but you might try TO_TIMESTAMP(?).
I would however change the query to allow use of a potential index on LOGGED_TIME:
SELECT ID, STATUS, LOGGED_TIME, SERVER_TIME
FROM table_1
WHERE LOGGED_TIME BETWEEN ? AND ?
ORDER BY LOGGED_TIME DESC
Then do all the math in Java:
Timestamp controlTime = Timestamp.valueOf("2014-08-15 03:52:00");
Calendar cal = Calendar.getInstance();
cal.setTime(controlTime);
cal.add(Calendar.DAY_OF_MONTH, -10);
lookupTime.setTimestamp(1, new Timestamp(cal.getTimeInMillis()));
cal.setTime(controlTime);
cal.add(Calendar.DAY_OF_MONTH, 10);
lookupTime.setTimestamp(2, new Timestamp(cal.getTimeInMillis()));
try (ResultSet rs = lookupTime.executeQuery()) {
while (rs.next()) {
long tdiffInSeconds = (rs.getTimestamp("LOGGED_TIME").getTime() - controlTime.getTime()) / 1000;
// other code
}
}
Here I am going to get data based on date only but my data continence both date and time here I am using like query to select that data based on date but I am not getting it can any plz exp line it thanks.
String device = "NR09G05635";
String date = "2013-11-29";
java.util.Date temp = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse(date);
java.sql.Date date1 = new java.sql.Date(temp.getTime());
sql = "select * from gpsdata1 where deviceId=? and dateTime like '" + date1 + "'";
System.out.println("sql" + sql);
ps1 = con.prepareStatement(sql);
ps1.setMaxRows(1);
ps1.setString(1, device);
ps1.execute();
rs = ps1.getResultSet();
-You use the LIKE operator to compare a character, string, or CLOB value to a pattern. Case is significant. LIKE returns the BOOLEAN value TRUE if the patterns match or FALSE if they do not match
Use TO_CHAR to explicitly create a string based on a DATE, using the format you want. Don't rely on implicit conversions.
Select *
From gpsdata1
Where NVL ( TO_CHAR ( dateTime
, 'YYYY-MM-DD HH:MI:SS AM'
)
, ' ' -- One space
) Like '%';
SELECT * FROM gpsdata1
WHERE deviceId=? and CONVERT(VARCHAR(25), dateTime, 126) LIKE '2013-11-19%'
LIKE operator does not work against DATETIME variables, but you can cast the DATETIME to a VARCHAR
I have the following
DateFormat dformat = new SimpleDateFormat("yyyy-M-d");
dformat.setLenient(false);
Date cin = dformat.parse(cinDate);
and the sql function
create or replace function search(_checkIn date, _checkOut date) returns setof Bookings as $$
declare
r Bookings;
begin
for r in
select * from Bookings
loop
if ((_checkIn between r.checkIn and r.checkOut) or (_checkOut between r.checkIn and r.checkOut)) then
return next r;
end if;
end loop;
return;
end;
$$ language plpgsql;
The date format for the postgresql is standard (default)
create table Bookings (
id serial,
status bookingStatus not null,
pricePaid money not null,
firstName text,
lastName text,
address text,
creditCard text,
checkOut date not null,
checkIn date not null,
room integer not null,
extraBed boolean not null default false,
foreign key (room) references Rooms(id),
primary key (id)
);
and I'm trying to parse a date into the function so it can return a table for me, I seem to run into the issue of date formatting (which is why I think I'm getting this error)
org.postgresql.util.PSQLException: ERROR: syntax error at or near "Feb"
So I was wondering how would I fix this problem, I don't know how to format the date properly
EDIT:
I'm calling the query like this
try {
String searchQuery = "SELECT * FROM Rooms r where r.id not in (select * from search(" + cin +", " + cout +"))";
PreparedStatement ps = conn.prepareStatement(searchQuery);
rs = ps.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
so I think the error comes in because the way I format the date is wrong and postgres won't read it
It sounds like you're passing the argument by concatenating them directly into the string. This is a very bad idea, since it can lead to SQL injections. Always use PreparedStatements with the ? place-holders to pass parameters, never pass them directly by concatening them directly into the query string (more so, you'd need the ' delimiters around).
You could have something like:
PreparedStatement stmt
= con.prepareStatement("SELECT id FROM Bookings WHERE checkIn=?")
stmt.setDate(1, new java.sql.Date(cin.getTime()));
// ? parameters are indexed from 1
ResultSet results = stmt.executeQuery();
Alternatively, PostgreSQL internal date conversion is usually fairly good and flexible. You could cast the string parameter to a date with PostgreSQL:
PreparedStatement stmt
= con.prepareStatement("SELECT id FROM Bookings WHERE checkIn=CAST(? AS DATE)");
stmt.setString(1, cinDate);
ResultSet results = stmt.executeQuery();
This is flexible, but might not lead to the exact result you need depending on the date format (you can check the PostgreSQL manual for details on date conversion formats). The input format you're using should work just fine, though (Try SELECT CAST('2012-05-01' AS DATE) directly in PostgreSQL, for example, this will return a correct PostgreSQL date.)
Note that when using new java.sql.Date(cin.getTime()), you're likely to run into time zone issues. You could use java.sql.Date.valueOf(...) too.
To clarify, following your edit:
This will not work, since the dates would be part of the SQL syntax itself, not strings or dates: "SELECT * FROM Rooms r where r.id not in (select * from search(" + cin +", " + cout +"))"
You'd at least need to use ' quotes: "SELECT * FROM Rooms r where r.id not in (select * from search("' + cin +"', '" + cout +"'))". Here, to a degree, you could expect the parameters to be formatted properly, but don't do it. In addition, would would still have to cast the string using CAST('...' AS DATE) or '...'::DATE.
The simplest way would certainly be:
String searchQuery = "SELECT * FROM Rooms r where r.id not in (select SOMETHING from search(CAST(? AS DATE), CAST(? AS DATE)))";
PreparedStatement ps = conn.prepareStatement(searchQuery);
ps.setString(1, cinDate);
ps.setString(2, coutDate);
(As a_horse_with_no_name pointed out in a comment, the general query wouldn't work anyway because of your inner select.)
You already have advice concerning prepared statements and proper format.
You can also largely simplify your PostgreSQL function:
CREATE OR REPLACE FUNCTION search(_checkin date, _checkout date)
RETURNS SETOF bookings AS
$BODY$
BEGIN
RETURN QUERY
SELECT *
FROM bookings
WHERE _checkin BETWEEN checkin AND checkout
OR _checkiut BETWEEN checkin AND checkout;
END;
$BODY$ language plpgsql;
Or even:
CREATE OR REPLACE FUNCTION search(_checkin date, _checkout date)
RETURNS SETOF bookings AS
$BODY$
SELECT *
FROM bookings
WHERE _checkin BETWEEN checkin AND checkout
OR _checkiut BETWEEN checkin AND checkout;
$BODY$ language sql;
Rewrite the LOOP plus conditions to a plain SQL statement which is much faster.
Return from a plpgsql function with RETURN QUERY - simpler and faster than looping.
Or use a plain sql function.
Either variant has its advantages.
No point in using mixed case identifiers without double quoting. Use all lower case instead.
According to this page, the standard format for date/time strings in SQL is:
YYYY-MM-DD HH:MM:SS
And of course for dates you can use
YYYY-MM-DD
PostgreSQL accepts other formats (see here for some details) but there's no reason not to stick to the standard.
However, since you are getting a syntax error it sounds like you are injecting the date strings into your SQL statement without the proper quoting/escaping. Double-check that you are properly escaping your input.
Im new to sql and im facing a problem with the below native query
public void saveOfflineBatchDetails(BigInteger user_id) {
em.createNativeQuery("INSERT INTO rst_offline_transaction_batch (created_date , user_id)" +
"VALUES('?1', ?2)")
.setParameter(1, new java.util.Date())
.setParameter(2, user_id)
.executeUpdate();
}
It doesn't pass the values to the database. the created date should be the today's date and time. Can anyone tell me whats wrong in this query.
Thanks a lot
You generally don't include the single quotes for parameterised queries. Try:
VALUES(?1, ?2)
(without the quotes around the ?1). Otherwise it's hard (for both readers and parsers) to tell whether you wanted parameter 1 or the literal value ?1 to be inserted.
You should also check the return value from executeUpdate() to see if it thinks it affected any rows. This will probably give you zero but it's worth checking anyway.
And, finally, I think dates require special handling as per:
setParameter(1, new java.util.Date(), TemporalType.DATE);
This is because the Java Date object is not a date at all but a timestamp - you need to ensure you select the correct temporal object type so that the right value is placed in the query.
So, in short, something like:
int affected = em.createNativeQuery(
"INSERT INTO rst_offline_transaction_batch (" +
" created_date," + // ?1
" user_id" + // ?2
") VALUES (?1,?2)"
)
.setParameter(1, new java.util.Date(), TemporalType.DATE)
.setParameter(2, user_id)
.executeUpdate();
// Check affected.