I want to insert "0001-01-01" as a value into a date field by using Java PreparedStatement.
But it throws exception when I tried this:
String sql = "insert into mytable values(?)"
ps = conn.prepareStatement(sql);
ps.setDate(1, java.sql.Date.valueOf("0001-01-01"));
ps.executeUpdate(); // throws exceptions here.
The error is :
The supplied value is not a valid instance of data type datetime. Check the source data for invalid values. An example of an invalid value is data of numeric type with scale greater than precision.
If I don't use PreparedStatement, I can insert "0001-01-01". However,
prepare statement seems not allow me to insert this value.
It will work if I inserted "1969-01-01" instead of "0001-01-01".
Any ideas?
Updates:
Here are more info that might be needed.
we use sql server 2012.
we have to use "0001-01-01" because these values were already there. I am changing some very very old codes to use prepare statement. So I have to insert the same values in the same functionality.
Updates 2:
We are using "date" datatype, not "datetime" datatype.
Based on this https://msdn.microsoft.com/en-us/library/bb630352.aspx, "0001-01-01" is not out of range for "date" field.
In addition, I am able to insert "0001-01-01" to the date field without using prepare statement. i.e.
String sql = "insert into mytable values('0001-01-01')"
java.sql.Statement statement = conn.createStatement();
statement.executeUpdate(sql);
So it is not sql server's problem or db field's problem.
Try using the different suitable JDBC driver.
Related
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.
I am working with some legacy code that performs database operations in a generic way, so that the User/developer can work with a different database by changing only the JDBC driver.
I have a problem with PostgreSQL JDBC driver. My test case:
//ddl
CREATE TABLE test
(
id numeric,
name text,
)
//java code
String sqlCmd = "INSERT INTO test values (?, ?)";
PreparedStatement ps = connection.prepareStatement( sqlCmd );
ps.setString( 1, "1" );
ps.setString( 1, "name1" );
ps.executeUpdate();
With Postgres, the result of this case is an exception with message: "can't cast string to int..."
Is it inappropriate to use PreparedStatement.setString() to set values that database expects to be numeric?
Should I expect the JDBC driver to automatically convert java types to database types?
This test passes with other databases, including H2 and MySQL. Does the failure with PostgreSQL reflect a bug in the JDBC driver? Is it possible to make this case work without changing code?
The documentation for java.sql.PreparedStatement has this to say:
Note: The setter methods (setShort, setString, and so on) for setting IN parameter values must specify types that are compatible with the defined SQL type of the input parameter. For instance, if the IN parameter has SQL type INTEGER, then the method setInt should be used.
Whether a particular database or JDBC driver allows you to be sloppy about that is its own affair, but you are not justified in expecting that all drivers will allow such slop, even if certain ones do.
while migrating from oracle database to postgresql, I found that may help you to use setString with numeric types and date types as well.
Just you have to use the connection parameter stringtype=specified as mentioned in the documentation.
https://jdbc.postgresql.org/documentation/head/connect.html
You are using setString() method to insert integers and postgres could not do that, Use
ps.setInt(1, INTEGER_VALUE);
insertSQL = "insert into TELBP_INPUT_LOG (SERIAL_NO, INPUT_XML) values (?, ?)";
statement = connection.prepareStatement(insertSQL);
statement.setString(1, serialNo);
statement.setString(2, inXml);
//statement.setString(2, "test");
insertCount = statement.executeUpdate();
when the program run to executeUpdate(), error
java.sql.SQLException: ORA-01461: can bind a LONG value only for insert into a LONG column
is thrown, but if I copy the value of serialNO and inXml and run in SQL developer, no error prompted, what is the reason?
oracle version:Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
column:
SERIAL_NO VARCHAR2(22)
INPUT_XML CLOB
Websphere:Websphere 5.1
jdbc: both ojdbc14 and ojdbc6 is tried, both has same error
You cannot write a String into a Clob column.
Instead of
statement.setString(2, inXml);
use
statement.setClob(2, xmlClob);
You first need to create xmlClob:
Clob xmlClob = connection.createClob();
Writer clobWriter = myClob.setCharacterStream(1);
clobWriter.write(inXml);
for clob field you can make use of .setClob(..)
setString():Sets the designated parameter to the given Java String value. The driver converts this to an SQL VARCHAR or LONGVARCHAR value (depending on the argument's size relative to the driver's limits on VARCHAR values) when it sends it to the database.
API DOC
CLOB API DOC
Java (the underlying driver) treats CLOB as a character stream. When ever you are setting String, the underlying driver implementation will automatically do the relevant conversion (String to Varchar etc.,). As CLOB is a special type, it is the responsibility of the programmer to do the necessary steps. Follow the link to now how to insert clob using java:
http://docs.oracle.com/javase/tutorial/jdbc/basics/blob.html
I want to insert null data to Teradata with JDBC connection on JAVA.
First of all I try this:
PreparedStatement stmt;
String qm="Insert into db.user values (?,?,?,?,?,?,?)";
connection= DriverManager.getConnection
(
"jdbc:teradata://192.xxx.x.xx/database=DBC,tmode=ANSI,charset=UTF8","user","passw0rd" );
stmt = connection.prepareStatement(qm);
//some code here to open while loop
stmt.setObject(i,null); // This isnt working with Terada JDBC. It is working for Oracle and MSSQL JDBC
//and I finish my code
And after, that I tried this instead of stmt.setObject(i,null); :
stmt.setNull(i,rsmd.getColumnType(i),rsmd.getColumnTypeName(i));
rsmd.getColumnType(i) is equal to 97
rsmd.getColumnTypeName(i) is equal to DATE
Yes it is true my field is DATE.
But it gives this ERROR:
ERROR : [Teradata JDBC Driver] [TeraJDBC 14.10.00.17] [Error 857] [SQLState HY000] Two different data types are being set for parameter 17 (449 & 749)
How can I fix this.
I used in the past the setNull(i, Types.#field type#) in a custom DB layer for TD.
However if you search the codes returned in the exception you'll find that they represent a Date and a Varchar, as if, at the same position, you sometimes pass a Date type and sometimes a Varchar.
Are you by chance passing not null dates as Date-like strings (e.g. "2015-08-18"), and not as java.sql.Date objects?
If that's the case you should change the code to use java.sql.Date objects and this will solve your issue.
Typically if you wish to INSERT a NULL value into ColC I would suggest using the following method with your INSERT ... VALUES statement:
INSERT (ColA, ColB, ColD, ColE) VALUES (1000, 'Testing Null', 1.00, DATE '2013-06-30);
Teradata will take the absence of the column in the INSERT statement to place either the pre-defined DEFAULT value or NULL for the column.
What if you try the following:
stmt.SetNull(i,Types.NULL)
The workaround for this issue is to cast the NULL to be a VARCHAR, so that it is compatible.
INSERT INTO XYA(PKEY,REF_KEY) VALUES(2,cast(null as varchar(10)));
I have an auto generated timestamp that is created each time a record is inserted or updated in a mysql table. Is there a way to return this timestamp in a way similar to how I would use a keyholder to return a newly created id?
KeyHolder keyHolder = new GeneratedKeyHolder();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//Insert Contact
jdbcTemplate.update(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement preparedStatement = connection.prepareStatement(SQL_ADD, Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, contact.getFirstName());
preparedStatement.setString(2, contact.getLastName());
preparedStatement.setInt(3, contact.getOrganizationId());
preparedStatement.setString(4, contact.getType());
preparedStatement.setInt(5, contact.getUserId());
return preparedStatement;
}
}, keyHolder);
//Use keyholder to obtain newly created id
contact.setId(keyHolder.getKey().intValue());
Is there some way to also return the new timestamp without having to requery the table? I have been looking for ways to return it along with the id as a key in the keyholder, but it doesn't seem to be returned as a key?
Not very satisfying, but I think "no" is the answer to your question. I don't know any of the Spring stuff, but I think this is due to the basic JDBC that it's wrapping. See http://docs.oracle.com/javase/6/docs/api/java/sql/Statement.html#getGeneratedKeys%28%29
You only option would be to create a stored procedure on MySQL that has an out parameter and call that. See http://dev.mysql.com/doc/refman/5.0/en/call.html.
There are few options for solving this issue on the MySQL database server side. You could start with creating a TRIGGER on the table. As TRIGGER has a restriction and cannot return data, you can set the TIMESTAMP value to a variable:
DEMILITER //
CREATE TRIGGER ai_tbl_name AFTER INSERT ON tbl_name
FOR EACH ROW
BEGIN
SET #TimeStamp = NEW.timestamp_column;
END;//
DELIMITER ;
To retrieve this timestamp value, run the following command:
SELECT #TimeStamp;
Since the variables are stored in the memory, there will be no need to open any tables again.
You go even further. You could create a STORED PROCEDURE in MySQL to automate all the above (sample code, as I do not know your table's details):
DELIMITER //
DROP PROCEDURE IF EXISTS sp_procedure_name //
CREATE PROCEDURE sp_procedure_name (IN col1_val VARCHAR(25),
IN col2_val VARCHAR(25),
IN col3_val INT)
BEGIN
INSERT INTO tbl_name (col1, col2, col3)
VALUES (col1_val, col2_val, col3_val);
SELECT #TimeStamp;
END; //
DELIMITER ;
You can run this procedure with the following code:
CALL sp_procedure_name(col1_val, col2_val, col3_val);
As I'm not familiar with the Java, you'll need to finish it up with your side of code.
It seems that the variable contact is an instance for the newly inserted record. As it contains the newly generated id (primary key) field value, you can execute a new query to return the required timestamp field value for this new id.
The query may look like this:
select timestamp_field from my_table where id=?
Use PreparedStatement to input new id value and execute it to fetch required timestamp field value.
GeneratedKeyHolder also has two methods: getKeyList() that returns Map<String,Object> of generated fields; and getKeyList() that produces a list of generated keys for all affected rows.
See java doc of GeneratedKeyHolder and Spring tutorial of auto generated keys
In addition Spring's SimpleJdbcInsert has methods for generated key retrieval. See also method SimpleJdbcInsert#usingGeneratedKeyColumns
There are 2 methods in java.sql.Connection class causing PreparedStatement execution to return selected key columns :
PreparedStatement prepareStatement(String sql,
int[] columnIndexes)
throws SQLException
PreparedStatement prepareStatement(String sql,
String[] columnNames)
throws SQLException
You don't need to use Spring KeyHolder & JDBCTemplate to do this.
The give hope you could number/name your timestamp column. But the javadoc doesn't require or suggest that any JDBC implementation can return non-key columns, so your out of luck with this approach:
Creates a default PreparedStatement object capable of returning the auto-generated keys
designated by the given array. This array contains the names of the columns in the target
table that contain the auto-generated keys that should be returned.
As suggested in another answer, can switch to a stored procedure that does exactly what you want (CallableStatement is actually a PreparedStatement that executes storedprocedures - i.e. a subclass).
Can populate the timestamp column within the prepared statement via new Timestamp(new Date()) - but you should have in place a mechanism to sync times across your various servers (which is often used in windows and *nix environments). Your trigger could set the timestamp only if a value wasn't already provided.
As part of your app & DB design, you need to commit to a philosophy of where certain operations occur. If the DB derives needed data, the app needs to refresh data - you must pay the price of separate query executions or a combined stored proc that inserts & retrieves.