Unable to get table alias working with spring jdbcTemplate - spring

I am trying select statement on a table with alias name. When I retrieve the resultset the alias doesn't seem to work with it.item_id. It works with item_id. Any idea where I am going wrong?
getJdbcTemplate().query((connection) -> {
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM some_item_table AS it WHERE it.item_id = ?");
preparedStatement.setString(1, 123);
return preparedStatement;
}, (rs, i) -> product()
.setId(rs.getInt("it.item_id"))// NOT WORKING
//.setId(rs.getInt("item_id")) THIS WORKS!
...
);

In the result set the aliases are not available so it does not work.
You could change your SQL query like SELECT it.item_id AS some_item_id * FROM some_item_table AS it then you can do rs.getInt("some_item_id").
In your query you do not really need an alias as you have only one table.

Related

How to get Distinct record from JPA

I have implemented a method which gives me specification, but what I want is the query should be as below:
Select Distinct *
From (another select query)
I generate query dynamically.
How do I perform the same using specification in Spring Boot?
Try something like this
Specification<T> spec = getSpecification();
Specification<T> distinctSpec = (root, query, cb) -> {
query.distinct(true);
return spec.toPredicate(root, query, cb);
};
if you want to get distinct records, you have to write a query like this in the repository.
The below query gives the distinct author from the post table.
#Query("select distinct author from Post")
List<String> findUniqueAuthor();
Write this in the repository
#Query(value = "Select Distinct * From (another select query)", nativeQuery = true)
List<Object> findUniqueData();

java Spring JDBCTemplate - where clause

In my JDBC training, I have a question on the use of the where clause.
Suppose that i have a table in my db that i want manage with a spring application using a jdbc template, let's assume "Logbase", with this column: host, user, clientip. Suppose now that i want allow query db based on a single column for all column, that is:
Select * from Logbase where host = x
and
Select * from Logbase where user = y
and
Select * from Logbase where clientip = z
I suppose I must write a separated java method for every of this query, something like this:
public Logbase getLogbaseFromHost(String id)
{
String SQL = "select * from Logbase where host = ?";
Logbase logbase = (Logbase) jdbcTemplate.queryForObject(SQL, new Object[]{id},
(rs, rowNum) -> new Logbase(rs.getString("host"), rs.getString("user"),
rs.getInt("clientip")));
return logbase;
}
public Logbase getLogbaseFromUser(String id)
{
String SQL = "select * from Logbase where user = ?";
Logbase logbase = (Logbase) jdbcTemplate.queryForObject(SQL, new Object[]{id},
(rs, rowNum) -> new Logbase(rs.getString("host"), rs.getString("user"),
rs.getInt("clientip")));
return logbase;
}
public Logbase getLogbaseFromClientIP(String id)
{
String SQL = "select * from Logbase where clientip = ?";
Logbase logbase = (Logbase) jdbcTemplate.queryForObject(SQL, new Object[]{id},
(rs, rowNum) -> new Logbase(rs.getString("host"), rs.getString("user"),
rs.getInt("clientip")));
return logbase;
}
Now, if i want allow query db based on 2 parameters, i suppose i must write a method for the 3 possible pair of parameters (one for clientip-user, another for clientip-host and the last for user-host).
Finally, if i want allow query db selecting all the parameters, i must write another method with the where clause in the query that ask for all variables.
If I did not say heresies and everything is correct, i have 7 method. But, i the number of parameters and combinations grow, this may be a problem. There is a way to get around it?
Note: for work reasons, i cant use Hibernate or other ORM framework. I MUST use jdbc.
Tnx to all for patience and response.
The solution could be based on SQL
Select *
from Logbase
where
(? is null or host = ?)
AND (? is null or user = ?)
AND (? is null or clientip = ?)
jdbcTemplate.queryForObject(SQL, new Object[]{host, host, user, user, clienttip, clienttip}
So e.g. if user is not specified (user is null - true) all the records are included
So, you also can use org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
** Select *
from Logbase where
(:host is null or host = :host)
AND (:user is null or user = :user)
AND (:clientip is null or clientip = :clientip)**
And java code:
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("host", host);
params.addValue("user", user);
params.addValue("clientip", clientip);
namedParameterJdbcTemplate.queryForObject(sqlQuer, params);

selecting from data base according user inputs

servlets, oracle SQL developer .. i want to select data from database but accoeding to user inputs .. here is my code
public ResultSet f_items(Connection conn,String price) throws SQLException {
String query = "select * from items where price=? ";
Statement st=conn.createStatement();
ResultSet set=st.executeQuery(query);
return set;
}
the price is a column in the table ... but this code gives me an SQL exception which is
: ORA-01008: not all variables bound
any help ??
You do not set the expected price on the statement. It should look sth. like this:
....
String query = "select * from items where price='" + price + "'";
ResultSet set=st.executeQuery(query);
EDIT: like Multisync suggested, but with an explanation :)
String query = "select * from items where price=? ";
PreparedStatement st=conn.prepareStatement(query);
st.setString(1, price);
ResultSet set=st.executeQuery(query);
Why is using a prepared statement better?
concatenating user input into DB queries is a recipe for disaster, known as SQL injection.
methods of PreparedStatement like setString will escape the string value for you, preventing SQL injection.
public ResultSet f_items(Connection conn,String price) throws SQLException {
String query = "select * from items where price=? ";
PreparedStatement st=conn.prepareStatement(query);
st.setString(1, price);
ResultSet set=st.executeQuery(query);
return set;
}

How to use prepared statement that returns resultset with jdbcTemplate in spring mvc 3?

Here is my code which uses jdbcTemplate
String SQL = "select branch from branchTable where branch_name = '" + branch + "'";
ArrayList<String> branchList = (ArrayList<String>) jdbcTemplateObject.query(SQL, new RowMapper() {
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString("city_desc");
}
});
return branchList;
Now i want to be able to use preparedstatement with a query like "select branch from branchTable where branch_name = ?"
How can i do that with jdbcTemplate ?
Examples i searched show demonstration on how to use it with update or insert query, but not with select query..
Please help.
JdbcTemplate has another query() method which takes arguments of the prepared statement as parameter:
jdbcTemplateObject.query(SQL, new Object[] {branchName}, new RowMapper() {...});
Note that:
SQL should be named sql
You should use List and not ArrayList. Nothing in the javadoc guarantees that an ArrayList is returned. And you shouldn't care about the concrete type of list returned.
You should use a RowMapper<String> and not a raw RowMapper.

Resultset Metadata from Spring JDBCTemplate Query methods

Is there any way I can get resultset object from one of jdbctemplate query methods?
I have a code like
List<ResultSet> rsList = template.query(finalQuery, new RowMapper<ResultSet>() {
public ResultSet mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs;
}
}
);
I wanted to execute my sql statement stored in finalQuery String and get the resultset. The query is a complex join on 6 to 7 tables and I am select 4-5 columns from each table and wanted to get the metadata of those columns to transform data types and data to downstream systems.
If it is a simple query and I am fetching form only one table I can use RowMapper#mapRow and inside that maprow method i can call ResultsetExtractor.extractData to get list of results; but in this case I have complex joins in my query and I am trying to get resultset Object and from that resultset metadata...
The above code is not good because for each result it will return same resultset object and I dont want to store them in list ...
Once more thing is if maprow is called for each result from my query will JDBCTemplate close the rs and connection even though my list has reference to RS object?
Is there any simple method like jdbcTemplate.queryForResultSet(sql) ?
Now I have implemented my own ResultSet Extractor to process and insert data into downstream systems
sourceJdbcTemplate.query(finalQuery, new CustomResultSetProcessor(targetTable, targetJdbcTemplate));
This CustomResultSetProcessor implements ResultSetExtractor and in extractData method I am calling 3 different methods 1 is get ColumnTypes form rs.getMetaData() and second is getColumnTypes of target metadata by running
SELECT NAME, COLTYPE, TBNAME FROM SYSIBM.SYSCOLUMNS WHERE TBNAME ='TABLENAME' AND TABCREATOR='TABLE CREATOR'
and in 3rd method I am building the insert statement (prepared) form target columntypes and finally calling that using
new BatchPreparedStatementSetter()
{
#Override
public void setValues(PreparedStatement insertStmt, int i) throws SQLException{} }
Hope this helps to others...
Note that the whole point of Spring JDBC Template is that it automatically closes all resources, including ResultSet, after execution of callback method. Therefore it would be better to extract necessary data inside a callback method and allow Spring to close the ResultSet after it.
If result of data extraction is not a List, you can use ResultSetExtractor instead of RowMapper:
SomeComplexResult r = template.query(finalQuery,
new ResultSetExtractor<SomeComplexResult>() {
public SomeResult extractData(ResultSet) {
// do complex processing of ResultSet and return its result as SomeComplexResult
}
});
Something like this would also work:
Connection con = DataSourceUtils.getConnection(dataSource); // your datasource
Statement s = con.createStatement();
ResultSet rs = s.executeQuery(query); // your query
ResultSetMetaData rsmd = rs.getMetaData();
Although I agree with #axtavt that ResultSetExtractor is preferred in Spring environment, it does force you to execute the query.
The code below does not require you to do so, so that the client code is not required to provide the actual arguments for the query parameters:
public SomeResult getMetadata(String querySql) throws SQLException {
Assert.hasText(querySql);
DataSource ds = jdbcTemplate.getDataSource();
Connection con = null;
PreparedStatement ps = null;
try {
con = DataSourceUtils.getConnection(ds);
ps = con.prepareStatement(querySql);
ResultSetMetaData md = ps.getMetaData(); //<-- the query is compiled, but not executed
return processMetadata(md);
} finally {
JdbcUtils.closeStatement(ps);
DataSourceUtils.releaseConnection(con, ds);
}
}

Resources