Query result with columns names - java

I'm using java, spring data jpa
Is there away to get as query result a map with column name and value?
something like: List<Map<String,object>> res = query.getResults();
EDIT:
I found this.
it uses JDBC statement.
String queryString = "Select auditTime From AuditPlayer ap Where ap.id = 1"
dbConnection = getDBConnection();
statement = dbConnection.createStatement();
// execute the SQL stetement
rs = statement.executeQuery(queryString);
rs.getString("auditTime")
this works, but is there a way to use * in the select:
Select * From AuditPlayer ap Where ap.id = 1
and now call a column name? `rs.getString("auditTime")
I keep getting error.

You can return a map of column-name: column-value pairs using JdbcTemplate. Example:
public List<Map<String, Object>> getCustomers() {
return this.jdbcTemplate.queryForList("SELECT customer_id, customer_name FROM customers");
}
This would return:
[{'customer_id': 4005, 'customer_name': 'John Smith'}, {...}, ... ]

Related

Translating HQL Query to executable SQL Query with list parameter

I am writing a util function to get the total record count based on any HQL that I get passed in without loading all data. The passed in HQL might be pretty complex with lots of selects, joins, where conditions, groupings and sortings. For that I want to wrap the query with a SELECT COUNT(*) FROM (<ORIGINAL_QUERY>) x. I found out, that this is not possible with HQL, because Hibernate does not allow subqueries in FROM elements.
Now, I am trying to translate this random HQL query which might have some named parameters (some of them might be simple parameters, some might be lists) to an executable SQL statement without inlining the parameter values. This seems to work with simple parameters, but does not work with list parameters.
The hqlString and the namedParameterMap comes from somewhere outside:
final String hqlString = "...";
final Map<String, Object> namedParametersMap = ...;
Code to translate HQL to SQL (and ParameterTranslations:
final QueryTranslatorFactory translatorFactory = new ASTQueryTranslatorFactory();
final SessionFactoryImplementor factory = getSessionFactory();
final QueryTranslator translator = translatorFactory.createQueryTranslator(hqlString, hqlString, Collections.EMPTY_MAP, factory, null);
translator.compile(Collections.EMPTY_MAP, false);
final String sqlString = translator.getSQLString();
final ParameterTranslations parameterTranslations = translator.getParameterTranslations());
Code to create a SQLQuery, set the Parameters and execute the Query:
SQLQuery sqlQuery = getCurrentSession().createSQLQuery(sqlString);
((Set<?>) parameterTranslations.getNamedParameterNames()).forEach(parameterName -> {
for (int position : parameterTranslations.getNamedParameterSqlLocations(parameterName)) {
sqlQuery.setParameter(position, namedParametersMap.get(parameterName));
}
});
final Long rowCount = ((BigInteger) query.uniqueResult()).longValueExact();
This query works an expected:
final String hqlString = "SELECT p.firstname, p.surname FROM Person p WHERE p.id = :param1";
final Map<String, Object> namedParametersMap = Maps.newHashMap(ImmutableMap.<String, Object>of("param1", Integer.valueOf(1));
This query does not work:
String hqlString = "SELECT p.firstname, p.surname FROM Person p WHERE p.id IN (:param1)";
final Map<String, Object> namedParametersMap = Maps.newHashMap(ImmutableMap.<String, Object>of("param1", Lists.newArrayList(Integer.valueOf(1)));
Exception:
org.hibernate.exception.SQLGrammarException: could not extract ResultSet at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:106) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79) at org.hibernate.loader.Loader.getResultSet(Loader.java:2313) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2096) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2072) at org.hibernate.loader.Loader.doQuery(Loader.java:941) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:352) at org.hibernate.loader.Loader.doList(Loader.java:2813) at org.hibernate.loader.Loader.doList(Loader.java:2796) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2625) at org.hibernate.loader.Loader.list(Loader.java:2620) at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:322) at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:1996) at org.hibernate.internal.AbstractSessionImpl.list(AbstractSessionImpl.java:322) at org.hibernate.internal.SQLQueryImpl.list(SQLQueryImpl.java:125) at org.hibernate.internal.AbstractQueryImpl.uniqueResult(AbstractQueryImpl.java:966) at HQLQueryUtils.getCount(HQLQueryUtils.java:350)
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: integer = bytea HINT: No operator matches the given name and argument type(s).
You might need to add explicit type casts. Position: 301 at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2433) at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2178) at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:306) at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441) at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365) at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:155) at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:118) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70) ... 49 more
Environment:
Java 8
Hibernate 5.1.8
Postgres-JDBC 42.2.2
PostgreSQL Server 10.5
In HQL you can use query parameter and set Collection with setParameterList method.
Query q = session.createQuery("SELECT entity FROM Entity entity WHERE name IN (:names)");
q.setParameterList("names", names);
You can use direct sql
String sql="your query"
Query query = sessionFactory.getCurrentSession().createSQLQuery(sql);
query.setParameter("paramterName", parameterValue);
List<Object[]> resultSet = query.list();
List<YouClass > data= new ArrayList<>();
for (Object[] row : resultSet) {
YouClass yourObject=new YouClass ();
yourObject.setDate((Date) row[0]);
yourObject.setAmount((BigDecimal) row[1]);
data.add(yourObject);
}
Suppose Yourclass has two element date and amount

Prepared statement with set null in query doesn't return any record

I use prepared statements to read/write data in my DB (SQLite). In my table INVENTORY, there are records which have null value in the column paleta (the column is defined as VARCHAR in the table). I want to select these records and I tried:
sq = "SELECT * FROM INVENTORY WHERE paleta = ? AND product = ? AND lot = ?";
//...
stm = c.prepareStatement(sq);
stm.setNull(1, java.sql.Types.VARCHAR);
stm.setString(2, "theIdOftheProduct");
stm.setString(3, "theLotOftheProduct");
ResultSet rs = stm.executeQuery();
The above query doesn't return anything.. I removed the paleta = ? and I get the records I want.. How can I define the query like SELECT * FROM INVENTORY WHERE paleta is null etc.. using the query parameters?
What you are trying to do is equivalent to writing SELECT * FROM INVENTORY WHERE paleta = NULL ..., which doesn't work.
Since you are essentially searching for rows having a constant value in the paleta column (which happens to be NULL), you can eliminate the first query parameter and explicitly check for null:
sq = "SELECT * FROM INVENTORY WHERE paleta IS NULL AND product = ? AND lot = ?";
stm = c.prepareStatement(sq);
stm.setString(1, "theIdOftheProduct");
stm.setString(2, "theLotOftheProduct");
I found my answer in https://stackoverflow.com/a/4215618/1052284
You'll have to decide upon an unused value. I simply kept it at '' since I don't have empty values.
sq = "SELECT * FROM INVENTORY WHERE IFNULL(paleta, '') = ? AND product = ? AND lot = ?";
//...
stm = c.prepareStatement(sq);
stm.setString(1, ""); // '' for NULL, otherwise a specific value
stm.setString(2, "theIdOftheProduct");
stm.setString(3, "theLotOftheProduct");
But beware if you many queries, it's VERY slow. I clock in at about 4000 times slower, on average, than queries without IFNULL. ~50ms instead of microseconds.

How do i form a query for jdbcTemplate

am trying to form a query based on parameters, if the parameters for WHERE clause is null or not. it seems to be a huge code if i do this on if and else. Is there any other smart way to this??
example :
String query = "SELECT CUSTOMER_NAME FROM CUSTOMER_TABLE WHERE ";
if(cust_id !=null && !(cust_id.trim().equalsIgnoreCase("")))
{
query = query + "cust_id='"+cust_id+"'";
}
else
{
}
checking all the columns like this, the code is looking like a mess, please let me know if there is an other way to do this
adding to the above question :
I also have the parameters for like operator
example
if(strCustName!=null)
{
String query = "SELECT * FROM CUSTOMER WHERE CUSTOMER_NAME LIKE '"+strCustName+"';
}
You can use NamedParameterJDBCTemplate
And your query could be
... WHERE (cust_id=:custIdParam OR :custIdParam is null)
AND (another_column=:another_param OR :another_param is null)
UPDATE:
String sqlstr = "select * from the_table where lastname like :lastname or :lastname is null"
NamedParameterJdbcTemplate jt = new NamedParameterJdbcTemplate(datasource);
Map namedParameters = new HashMap();
namedParameters.put("lastname", "%test%");
SqlRowSet result = jt.queryForRowSet( sqlstr ,namedParameters );
from the link

Pass list of values on query parameter

String hql = "select * from myTable where isActive IN (:isActive)";
Query query = session.createQuery(hql);
query.setString("school","");
query.setString("isActive", "Y");//working
query.setString("isActive", "N");//working
query.setString("isActive", "Y","N"); // not working
query.setString("isActive", "'Y','N'"); // not working
return query.list();
I have no idea if the code below should work, I was wondering if i can pass list of values to my search string parameter so there's no need for me to create to queries ; one for select all data regardless of status and another to select only active data.
Use Query.setParameterList() to pass in a List as a parameter:
String hql = "select * from myTable where isActive IN (:isActive)";
Query query = session.createQuery(hql);
List<String> isActiveList = new ArrayList<>();
isActiveList.add("Y");
isActiveList.add("N");
query.setParameterList("isActive", isActiveList);
return query.list();

Merging three queries that use 1:* relationships into one query

Lets say i have four tables i want to read from:
customer
customer_id, customer_name
1 Joe Bolggs
customer_orders
customer_id, order_no
----------------------------
1 1
1 2
1 3
customer_addresses
customer_id address
----------------------------
1 11 waterfall road
1 23 The broadway
customer_tel_no
customer_id number
----------------------------
1 523423423432
1 234342342343
The customer information shown above (for the customer with id=1) is to be stored in a Java object as shown below
public class Customer{
String customer_id;
String customerName;
ArrayList<String> customerOrders;
ArrayList<String> customerAddress;
ArrayList<String> customerTelephoneNumbers;
}
The only way i can think of to get the above information is by using three queries. The reason is that there is a 1:* relationship between the customer table and each of the other tables. To get the data i am doing something like this:
Customer customer = new Customer()
String customerSQL = "Select * from customer where customer_id = ?";
statement = getConnection().prepareStatement(contactsQuery);
statement.setString(1,1);
resultSet = statement.executeQuery();
while (resultSet.next()){
customer.customer_id = resultSet.get(1); //No getters/setters in this example
customer.customerName = resultSet.get(2);
}
String customerOrdersSQL = "Select * from customer_orders where customer_id = ?";
statement = getConnection().prepareStatement(customerOrdersSQL);
statement.setString(1,1);
resultSet = statement.executeQuery();
customer.customerOrders = new ArrayList();
while (resultSet.next()){
customer.customerOrders.add(resultSet.getString(2); // all the order numbers
}
String customerAddressesSQL = "Select * from customer_addresses where customer_id = ?";
statement = getConnection().prepareStatement(customerAddressesSQL );
statement.setString(1,1);
resultSet = statement.executeQuery();
customer.customerAddresses = new ArrayList();
while (resultSet.next()){
customer.customerAddresses.add(resultSet.getString(2); // all the addresses
}
String customerTelSQL = "Select * from customer_tel_no where customer_id = ?";
statement = getConnection().prepareStatement(customerTelSQL);
statement.setString(1,1);
resultSet = statement.executeQuery();
customer.customerTelephoneNumbers = new ArrayList();
while (resultSet.next()){
customer.customerTelephoneNumbers.add(resultSet.getString(2); // all the order numbers
}
The problem with the above is that i am making three calls to the database. Is there a way i can merge the above into a single query please?
I cant see how a join would work because for example, a join between customer and customer_orders will return a customer row for each row in customer_orders. Is there anyway i can merge the above three queries into one?
I would think that something like this would work:
SELECT c.customer_id, c.customer_name, o.order_no, a.address, t.number
FROM customer c LEFT JOIN customer_orders o ON c.customer_id = o.customer_id
LEFT JOIN customer_addresses a ON c.customer_id = a.customer_id
LEFT JOIN customer_tel_no t ON c.customer_id = t.customer_id
WHERE c.customer_id = ?
Then, in your code, after you execute the query:
while (resultSet.next())
{
customer.customerOrders.add(resultSet.getString(3));
customer.customerAddresses.add(resultSet.getString(4));
customer.customerTelephoneNumbers.add(resultSet.getString(5));
}
Of course, this does not take into account the fact that you will have null values along the way, so I'd advise checking for nulls to make sure that you aren't adding a lot of junk to your array lists. Still, that's probably a lot less costly than 3 separate queries.
Nothing prevents you from iterating and processing the joined result into your customer object. If your application is complex enough, you could look into ORM frameworks which would do that for you under the covers. If you are working with JavaEE, have a look at JPA.
use this query and reduce the number of call. And, in while loop process on data.
select customer.customer_id,customer.customer_name,order_no,address,number
from customer,customer_orders,customer_addresses,customer_tel_no
where customer.customer_id = customer_orders.customer_id
AND
customer.customer_id = customer_addresses.customer_id
AND
customer.customer_id = customer_tel_no.customer_id

Categories