sql server jdbc query on datetime column - java

I've looked around and could not seem to find this asked specifically, on SO, but I've found similar questions like this one and lots of questions regarding SQL itself or C#...
Here is what I am seeing:
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
//parameterSource.addValue( "insertDate", DateTime.now().minusHours( 1 ).toGregorianCalendar(), Types.TIME );
parameterSource.addValue( "insertDate", new Timestamp( DateTime.now().minusHours( 1 ).getMillis() ) );
List< String > contents =
_simpleJdbcTemplate
.query(
"SELECT TOP (200) inserteddatetime, Contents FROM dbo.tsomeTable WHERE (ServiceName = 'something') and inserteddatetime > :insertDate",
new RowMapper< String >() {
#Override
public String mapRow( final ResultSet rs, final int rowNum ) throws SQLException {
System.out.println( rs.getTimestamp( "inserteddatetime" ) );
return rs.getString( "Contents" );
}
}, parameterSource );
The query "hangs"\does nothing\never returns if:
I use the uncommented Timestamp object (as presented above)
I replace the parameterSource object with DateTime.now().minusHours( 1 ).toGregorianCalendar() or DateTime.now().minusHours( 1 ).toGregorianCalendar().getTime()
I try the commented out line, but change the type to Timestamp
So, here is my question or questions...
Is there a known bug\issue with querying on datetime columns in sql server?
Why do I have to use Time and not Timestamp?
I suspect that Spring is converting the date objects over to Timestamp when I query with the object directly (as demonstrated in #2).

TIMESTAMP is a server-generated value used to help with data consistency, its not a simple data type, so for storing datetime value, avoid TIMESTAMP datatype.
Also, SQL Server TIMESTAMP is confusing, and it's deprecated. It is replaced by the ROWVERSION keyword, which should reduce confusion.

Related

Groovy Sql Query Returning Date Column as String

I have a groovy class that is responsible for running a query against a sql database table and extracting some data from the results to build a DTO. The database column I am interested in is called 'release_date' is of type (date,null). I was expecting the results to return a java.util.Date object but instead I am getting a java.lang.String. The strange thing is, if I change the type of the column to a datetime it seems to work correctly.
Is this expected behaviour from groovy? Is there a way to get it to return a Date object without having to change the column of the database?
My Groovy Code:
Sql opticsSql=myDb;
def run(Map<Long, OriginalDateDTO> dtoMap) {
def query = """select p.id,p.release_date as planned from releases p; """;
opticsSql.eachRow(query.toString()) { val->
Long id = val.id;
Date planned = val.planned;
Map localMap = dtoMap;
Boolean hasKey = localMap.containsKey(id);
if(hasKey) {
dtoMap.get(id).originalPlannedDate = planned;
}
}
}

Postgres overlapping symbol not running in java

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

Spark with Cassandra SaveToCassandra

I'm using Cassandra with spark, and I have a JavaRDD<Srring> containing 6 columns separated by , like this:
header: canal,action,time,tiemend,client
I have created a table Mytable with 6 columns:
CREATE TABLE IF NOT EXISTS ref_event_by_user_session (
canal TEXT,
action TEXT,
time timestamp,
timeend timestamp,
Client INT,
PRIMARY KEY(canal, action, time, timeend)
);
and now I want to save my JavaRDD in my Cassandra table using javaFunctions().saveToCassandra,
but I don't know how to use it. Could you please show me how to do it?
I've found the solution.
If it can help someone :)
I just create a java class table2 with canal String,
action String,
time Date,
timeend Date,
Client String,
and then :
JavaRDD<Table2> table2 = session_7.map(new Function<Tuple2<KeyTable2, ValueTable2>, Table2>() {
#Override
public Table2 call(Tuple2<KeyTable2, ValueTable2> keyTable2ValueTable2Tuple2) throws Exception {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date startdate = formatter.parse(keyTable2ValueTable2Tuple2._1.time.replace("+","."));
Date endtdate = formatter.parse(keyTable2ValueTable2Tuple2._1.endtime.replace("+","."));
Table2 t = new Table2(keyTable2ValueTable2Tuple2._2.canal,keyTable2ValueTable2Tuple2._2.motif,startdate,endtdate,keyTable2ValueTable2Tuple2._1.client);
return t;
}
});
javaFunctions(table2).writerBuilder("Schema", "Table", mapToRow(Table2.class)).saveToCassandra();
Note : you must add the getters in the class even if the differents variables are public.

DATE FORMAT SQL

I have a table called Abbonamento that has the following attributes:
Abbonamento(idAbbonamento, tipo, DataInizio, DataScadenza, ....)
DataInizio and DataScadenza are of type DATE.
The problem borns when I do a select on this table:
String queryAbb = "select idabbonamento, tipo, DATE_FORMAT(datainizio,'%d-%m-%Y'), DATE_FORMAT(datascadenza,'%d-%m-%Y'), ...;
prest = con.prepareStatement(queryAbb);
rs = prest.executeQuery();
while (rs.next()) {
a=new Abbonamento();
a.setIdAbbonamento(rs.getInt(1));
a.setTipo(rs.getString(2));
a.setDataInizio(rs.getDate(3));
System.out.println(rs.getDate(3));
a.setDataScadenza(rs.getDate(4));
...
}
Now, if the date DataInizio in the db is for example 2013-11-05 00:00:00 I would like to have 05-11-2013 but the println prints 0004-10-13.
What's wrong with the code above?
Instead of
rs.getDate(3)
you should use
rs.getString(3)
because the data is already formatted as String. If you want to get as Date, first, a Date object is created from your 05-11-2013 string, then you receive that.
If you have Date objects in your objects, you should either parse() the returnes string with the same format you returned from the DB, or let the JDBC do the conversion for you (in this case, simply select idabbonamento, tipo, datainizio, ...) without formatting.
I recommend that let JDBC do it. Less user code, less trouble :)
String queryAbb = "select idabbonamento, tipo, datainizio, datascadenza, ...";
...
a.setDataInizio(rs.getDate(3));
// reading the formatted data:
System.out.println(new SimpleDateFormat().format(a.getDataInizio());
Actually, there is one more trick, but you don't have to care about: rs.getDate() returns java.sql.Date, but you probably use java.util.Date. That's not a problem, because java.sql.Date is a subclass of java.util.Date, so this assignment is totally valid.
Try this:
select idabbonamento, tipo, convert(char(10), datainizio, 105)....
In a database-independent way, you could use java.text.SimpleDateFormat. For example:
java.util.Date date = rs.getDate(3);
String dateFormatted = (new java.text.SimpleDateFormat()).format(date);
a.setDataInizio(dateFormatted);

Formatting Date for Postgresql

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.

Categories

Resources