Spring JDBCTemplate with Temporary Table - java

I have couple of questions:
1) First basic question how can i execute multiple statements
(Create temp table and Select from temp table) using same jdbc connection in spring jdbctemplate?
2) I am creating temp table using below sql statement. JDBCTemplate execute(String sql) method doesn't accept any parameters then how to run it using jdbc template
Select column1, column2, column3... into #t
from Table where column1 >= ? and column1 < ?

In JUtil I use single connection wrapper:
dataSource = new org.springframework.jdbc.datasource.SingleConnectionDataSource(dataSource.getConnection(), true);
#Test
public void testTemporaryTable() {
JdbcTemplate dao = new JdbcTemplate(dataSource);
dao.update("create local temporary table test_table as select 'text' id");
Assert.assertEquals("text", dao.queryForObject("select id from test_table ", String.class));
}

Related

Create table as select with parameter using jdbcTemplate

I want to use jdbcTemplate to create table based on another table under condition. I have postgres database. When I execute this and pass parameter:
String SQL = "create table test as (select * from users where countryId =?)";
jdbcTemplate.update(SQL, new Object[] {3})
I receive table test with all columns from users table but with no rows.
However, when I execute this:
String SQL = "create table test as (select * from users where countryId =3)";
jdbcTemplate.update(SQL)
I receive test table with rows where countryId = 3, so that is what I was expecting to receive in the first solution.
Your passing of the bind variable is not correct, but it does not play any role.
You simple can not use a bind variable in a data definition statement as you immediately see in the triggered error
Caught: org.springframework.jdbc.UncategorizedSQLException:
PreparedStatementCallback; uncategorized SQLException for SQL
[create table test as (select * from users where countryId =?)];
SQL state [72000]; error code [1027];
ORA-01027: bind variables not allowed for data definition operations
So you have two options, either concatenate the statement (which is not recommended due to the danger of SQL injection)
or split the statement in two parts:
// create empty table
sql = "create table test as (select * from users where 1 = 0)";
jdbcTemplate.update(sql)
// insert data
sql = "insert into test(countryId, name) select countryId, name from users where countryId =?";
updCnt = jdbcTemplate.update(sql, new SqlParameterValue(Types.INTEGER,3));
Note that in the insert statement you can see the correct way of passing an interger value of 3 as a bind variable.
You can follow below approach as well:-
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS employee_tmp (id INT NOT NULL)");
List<Object[]> employeeIds = new ArrayList<>();
for (Integer id : ids) {
employeeIds.add(new Object[] { id });
}
jdbcTemplate.batchUpdate("INSERT INTO employee_tmp VALUES(?)", employeeIds);
Here you may query with 2 operations to avoid SQL injection.
You are using method update from jdbcTemplate in a wrong way.
Try with this:
String SQL = "create table test as (select * from users where countryId = ?)";
jdbcTemplate.update(SQL, 3);

Execute multiple queries with parameters on a single connection using jdbc template

I need to execute multiple queries via jdbc template in a single connection.
I am using SQL server with the mssql jdbc driver. Here is the query:
IF OBJECT_ID('tempdb..#temp') IS NULL
SELECT * INTO #temp FROM ( SELECT * FROM "complex query here" ) a
DECLARE #page_size INT
SET #page_size = ?
SELECT *
FROM ( SELECT TOP(#page_size) * FROM #temp
WHERE custom_column > ?
ORDER BY custom_column ) inner_query
(MULTIPLE JOINES HERE)
ORDER BY custom_column
The query simply puts the whole result from the complex query to the temp table if the table does not exist and selects pages from the generated temp table.
Since the temp tables have connection scope, i need to execute the whole paging with multiple queries in a single connection. This is the code i have tried:
try (Connection connection = dataSource.getConnection()) {
while (true) {
List<CustomObject> customObjects = customRepository.
.getCustomObjectsPage(connection, pageSize, minimumValueInWhere);
// business logic here..
if (customObjects.size() < pageSize) {
break;
}
minimumValueInWhere = customObjects.get(customObjects.size() - 1).getId().toString();
}
}
and getCustomObjectsPage():
public List<CustomObject> getCustomObjectsPage(Connection connection, int pageSize,
String parameter) {
JdbcTemplate singleConnectionJdbcTemplate = new JdbcTemplate(
new SingleConnectionDataSource(connection, true));
try {
return singleConnectionJdbcTemplate
.query("the query from above", new Object[]{pageSize, parameter},
JdbcTemplateMapperFactory.newInstance()
.newResultSetExtractor(CustomObject.class)); // the root entity.
}
}
But for some reasons the queries are not executed in a single connection, and if i hardcode the
parameters to the query instead of passing them to the jdbc template it works perfectly.
How to make this work independently of the parameters ?

select scope_identity() using createSQLQuery in Hibernate

I am forced to use createSQLQuery to insert values into tables with an Identity column (the first column and the primary key) using hibernate. Using hibernate classes are not an option since the tables are created on the fly for each customer that is added to the system. I have run the query and it successfully inserts into the table. I then execute a "select scope_identity()" and it always returns null. "select ##Identity" works but that is not guaranteed to be the correct one. I have also tried to append "select scope_identity()" to the insert query. Then I tried query.list() and query.uniqueResult() both of which throw the hibernate exception of "No Results ..."
Session session = DatabaseEngine.getSessionFactory().openSession();
String queryString = "insert into table1 (dataid) values (1)"
SQLQuery query = session.createSQLQuery(insertQueryString);
query.executeUpdate();
query = session.createSQLQuery("select scope_identity()");
BigDecimal entryID = (BigDecimal)query.uniqueResult();
The simple example table is defined as follows:
"CREATE TABLE table1 (EntryID int identity(1,1) NOT NULL," +
"DataID int default 0 NOT NULL, " +
"PRIMARY KEY (EntryID))";
Is there a way I am missing to use scope_identity() with createSQLQuery?
Actually the SQLServerDialect class used by Hibernate uses the same "scope_identity()" too.
The reason why it's not working is because you need to execute those in the same statement or stored procedure.
If you execute the scope_identity() call in a separate statement, SQL Server will not be able to give you last inserted identity value.
You cannot do it with the SQLQuery, even Hibernate uses JDBC to accomplish this task. I wrote a test on GitHub to emulate this and it works like this:
Session session = entityManager.unwrap(Session.class);
final AtomicLong resultHolder = new AtomicLong();
session.doWork(connection -> {
try(PreparedStatement statement = connection.prepareStatement("INSERT INTO post VALUES (?) select scope_identity() ") ) {
statement.setString(1, "abc");
if ( !statement.execute() ) {
while ( !statement.getMoreResults() && statement.getUpdateCount() != -1 ) {
// do nothing until we hit the resultset
}
}
try (ResultSet rs = statement.getResultSet()) {
if(rs.next()) {
resultHolder.set(rs.getLong(1));
}
}
}
});
assertNotNull(resultHolder.get());
The code uses Java 8 lambdas instead of anonymous classes, but you can easily port it to Java 1.7 too.

SPRING MVC database error jdbc

Thanks for your time
I am getting an error as my project is having 2 modules add driver and add truck for which i am executing the sql query for both but when i execute the query for addDriver module the database exception is throwing stating
org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [INSERT INTO truck(TRegnNo,VendorName,PurchaseDate,Price,RepairDate,InvoiceNo,RepairCost) VALUES(?,?,?,?,?,?,?)]; Column 'TRegnNo' cannot be null; nested exception is com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Column 'TRegnNo' cannot be null
org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:101)
driver insert sql statement public void insertData(Driver driver)
{
String sql = "INSERT INTO driver" + "(DLNo,DName,Age,Experience) VALUES (?,?,?,?)";
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update(sql, new Object[] {driver.getLicenseNumber(),driver.getDriverName(),driver.getAge(),driver.getExperience()});
} Truck Insert code public void insertData(Truck truck)
{
String sql = "INSERT INTO truck" + "(TRegnNo,VendorName,PurchaseDate,Price,RepairDate,InvoiceNo,RepairCost) VALUES(?,?,?,?,?,?,?)";
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update(sql , new Object[] {truck.getTregNo(),truck.getVendorName(),truck.getPurchaseDate(),truck.getPrice(),truck.getRepairDate(),truck.getInvoiceNo(),truck.getRepairCost()});
}
Column TRegnNo can not be null. You have to assign a (unique) value to this row.
Check out with this :
StackTrace contains Column 'TRegnNo' cannot be null pointing to constraints in Truck table, like primary key or foreign key etc..

"super-dynamic" query with MyBatis

Is there way to create sql query on the fly with MyBatis? To concretize: I have a query, where part of it (but not parameter) needs to be created in the runtime:
with dummy (id) as (
values (#{rangeEnd}) union all
select id - 1 from dummy where id - 1 >= #{rangeStart}
).......
The second part can be used as parameter, but, when trying the query as it is I get an exception:
[SQL0584] NULL or parameter marker in VALUES not allowed.
With plain JDBC I use MessageFormat:
PreparedStatement ps = connection.prepareStatement(
MessageFormat.format(MY_QUERY, currentRange.getRangeEnd()))
, but I haven't found a way how to do it with MyBatis.
It's really easy (answer from Dynamic Select SQL statements with MyBatis):
with dummy (id) as (
values (${rangeEnd}) union all
select id - 1 from dummy where id - 1 >= #{rangeStart}
).......
Use #SelectProvider annotation:
public interface SqlMapper {
static class PureSqlProvider {
public String sql(String sql) {
// Create your query here
return sql;
}
}
#SelectProvider(type = PureSqlProvider.class, method = "sql")
public List<Dummy> select(String sql);
}

Categories