I am trying to extract count(*) matching certain predicates. Every time I use createSQLQuery, I find myself having to write the code along the lines of,
// skipped code
Query q = session.createSQLQuery("select count(*) from A where id=1");
Scrollable results = q.scroll();
while ( results.next() )
{
Object[] row = Object[] results.get();
// Assign it
String str = row[0];
//set and persist
}
I have many such queries unioned over a single transaction. How do I get single result here? Am I missing something?
You can use this method instead:
Object[] row = (Object[]) query.uniqueResult();
If the query returns more than one result, this method will throw an exception
EDIT:
On top of that, you could use a ResultTransformer to convert the Object[] into an Integer. This would remove the need to get the result array and then extract it's first entry. See this example for more info
Related
I have a query:
Query q = em.createNativeQuery("select DISTINCT id, rating, random() as ordering FROM table\n" +
" WHERE id not in (1,2) ORDER BY ordering LIMIT 10");
List data = q.getResultList();
Every element of this list is array like object:
I want to retrieve that "8" and "16" and compose a comma separated string (to use it in my query in "not in" section in future):
for (Object x : data) {
System.out.println(Arrays.asList(x).get(0));
}
But it produces strings:
[Ljava.lang.Object;#ee93cd3
[Ljava.lang.Object;#62f3c3e1
I don't know how to get that IDs ("8" and "16")
1.I think this is what you are looking for...
Convert JPA query.getResultList() to MY Objects.
or
List<Object[]> rows = q.getResultList(); for (Object[] row : rows) { System.out.println(row[0]); }
in this line
List<Object[]> data = q.getResultList();
data is list of Object of form
[ [1,233, 0.000333], [1,233, 0.000333] ]
for (Object[] x : data) {
// x is [1,233, 0.000333]
System.out.println(x[0]);
}
If I understood it correctly, you are looking for comma separated string of ID's.
If so, then follow these steps might help you to solve the issue.
Create a constructor in table which has only one parameter ID. (If you want you can add more parameters as well but make sure the value which you want it must be in constructor as well as in query.)
Write sql query and execute it.
It returns result and gather it in List which contains the object of the table.
Get the string
dataList.stream().map(obj -> obj.getId()).collect(Collectors.joining(", "))
This will give you the comma separated string.
I have 6 columns in a table. I have a select query which selects some records from the table. While iterating over the result set, im using the following logic to extract the values in the columns:
Statement select = conn.createStatement();
ResultSet result = select.executeQuery
("SELECT * FROM D724933.ECOCHECKS WHERE ECO = '"+localeco+"' AND CHK_TOOL = '"+checknames[i]+"'");
while(result.next()) { // process results one row at a time
String eco = result.getString(1);
mapp2.put("ECO", eco);
String chktool = result.getString(2);
mapp2.put("CHECK_TOOL", chktool);
String lastchktime = result.getString(3);
mapp2.put("LAST_CHECK_TIME", lastchktime);
String status = result.getString(4);
mapp2.put("STATUS", status);
String statcmts = result.getString(5);
mapp2.put("STATUS_COMMENTS", statcmts);
String details = result.getString(6);
mapp2.put("DETAILS_FILE", details);
}
I have 2 questions here:
1. Is there any better approach rather than using result.getString()???
2. Lets say, another column gets added to the table at a later point. Is there any way my code handles this new addition without making change to the code at that point of time
You can use ResultSetMetaData to determine the number and names of the columns in your ResultSet and deal with it this way. Note however that changing the number of columns in the database - affecting your code - and having the code still work may not always be a good idea.
Additionally, note that you're overwriting the values in your map on each iteration of the loop. You probably want to add those maps to some sort of List?
Finally, you need to make sure that your getString methods will not return null anywhere, otherwise putting it into a map will throw an exception.
Statement select = conn.createStatement();
ResultSet result = select.executeQuery("SELECT * FROM D724933.ECOCHECKS WHERE ECO = '"+localeco+"' AND CHK_TOOL = '"+checknames[i]+"'");
ResultSetMetaData rsmd = result.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
List data = new ArrayList<Map>();
Map mapp2;
while(result.next()) { // process results one row at a time
mapp2 = new HashMap<String, String>();
for(int i=1; i<=numberOfColumns; i++) {
mapp2.put(rsmd.getColumnName(i), rs.getString(i));
}
data.add(mapp2);
}
Each of the get family of methods on ResultSet has an overloaded variant that takes a column name as argument. You can use this instead to reduce reliance on ordering of columns.
ResultSet results = ...;
results.getString(1);
You could do this:
results.getString("name");
But the preferred way of handling this sort of problem is to impose an ordering of your own on the result set, by explicitly selecting the columns you want in the initial query.
If your table adds a new column, then obviously you have to change your code, because in your code you use hardcoded value, I mean getString(1).
Instead use ResultSetMetaData's getColumnCount and do some other logic to get that many column values dynamically.
Another thing for your first question, ResultSet contains getXXX() methods with two types of parameters, String column name and int column index. You used the index instead of column name which will perform little faster.
It is bad practice to use SELECT *, instead you should select only the columns you are interested in. The reason is exactly what you mentioned: What happens if your DB changes. you don't want to go trhough the whole code and find and edit all SELECT * statements.
You don't need to put the result into your own map because you can already do:
result.getString("DETAILS_FILE");
But there are already other answers explaining that.
It would be further helpful to use a constant instead of the string "DETAILS_FILE". You can use the constant in the SELECT and in the result.getString(). In case your DB changes you only need to introduce a new constant or change an existing one.
I am building a report from information received from a muti-select form element in a jsp page.
In my repository class I am getting an array of objects from that element. I need to call the getId function for each one of these objects and send those ids to the NamedQuery.
Here is a code example to help explain. I know how to handle a single object but with an array of objects I get lost at the .setParameter(1, employees[].getId()) part.
public List<RequestByRequester> getFormInformation(
Employee[] employees)
throws NoDataFoundException {
List<RequestByRequester> resultList = getEm().createNamedQuery(
"requestByRequestor.getRequestsByRequesters", RequestByRequester.class)
.setParameter(1, employees[].getId())
.getResultList();
return resultList;
}
By request the query:
SELECT EMP.EMPL_FIRST_NAME || ' ' || EMP.EMPL_LAST_NAME REQUESTER,
R.RQST_ID RQST_ID,
R.TITLE TITLE,
R.DESCRIPTION DESCR,
DECODE(R.RESOLUTION_DATE, NULL, 'Open', 'Closed') STAT
FROM TARTS.REQUESTS R, SYS_EMPLOYEES EMP
WHERE R.EMPL_ID_REQUESTED_BY = EMP.EMPL_ID
AND EMP.EMPL_ID IN (?)
ORDER BY 1, 5 DESC, 2
I tried calling Madame Mystique to get help with finding out what your query actually was, but no luck, so I'm just going to go for it...
Your named query should look something like this:
select x
from MyClass x
where x.children.id in (:ids)
then get your ids into a list
List<Integer> ids = new ArrayList<Integer>();
ids.add(someid); // etc
then use this to specify it in your query
.setParameter("ids", ids)
I am new to JPA. So my question should be so simple to some.
Below is the Simple Query in SQL which i would like to convert to JPA. I already have an entity class called TimeEnt.
SELECT
SUM(TimeEntryActualHours) as UnBilledHrs,
SUM (TimeEntryAmount) as UnbilledAmount
FROM TimeEnt WHERE MatterID = 200
The JPA Query Language does support aggregates functions in the SELECT clause like AVG, COUNT, MAX, MIN, SUM and does support multiple select_expressions in the SELECT clause, in which case the result is a List of Object array (Object[]). From the JPA specification:
4.8.1 Result Type of the SELECT Clause
...
The result type of the SELECT
clause is defined by the the result
types of the select_expressions
contained in it. When multiple
select_expressions are used in the
SELECT clause, the result of the query
is of type Object[], and the
elements in this result correspond in
order to the order of their
specification in the SELECT clause
and in type to the result types of
each of the select_expressions.
In other words, the kind of query you mentioned in a comment (and since you didn't provide your entity, I'll base my answer on your example) is supported, no problem. Here is a code sample:
String qlString = "SELECT AVG(x.price), SUM(x.stocks) FROM Magazine x WHERE ...";
Query q = em.createQuery(qlString);
Object[] results = (Object[]) q.getSingleResult();
for (Object object : results) {
System.out.println(object);
}
References
JPA 1.0 Specification
4.8.1 Result Type of the SELECT Clause
4.8.4 Aggregate Functions in the SELECT Clause
Lets think we have entity called Product:
final Query sumQuery = entityManager
.createQuery("SELECT SUM(p.price), SUM(p.sale) FROM Product p WHERE p.item=:ITEM AND ....");
sumQuery.setParameter("ITEM","t1");
final Object result= sumQuery.getSingleResult(); // Return an array Object with 2 elements, 1st is sum(price) and 2nd is sum(sale).
//If you have multiple rows;
final Query sumQuery = entityManager
.createQuery("SELECT SUM(p.price), SUM(p.sale) FROM Product p WHERE p.item in (" + itemlist
+ ") AND ....");
// Return a list of arrays, where each array correspond to 1 item (row) in resultset.
final List<IEniqDBEntity> sumEntityList = sumQuery.getResultList();
Take a look at the EJB Query Language specification.
The idiom is very similiar to standard SQL
EntityManager em = ...
Query q = em.createQuery ("SELECT AVG(x.price) FROM Magazine x");
Number result = (Number) q.getSingleResult ();
Regards,
I do a query that returns a list of entities. How can I retrieve the entities from a ScrollableResults:
Session s = ....;
Query q = s.createQuery("....") # returns 100000s rows
ScrollableResults sr = q.scroll();
sr.scroll(45999); # just a number
Employee employee = ???
How do I get an employee in the last line of code
try the get(0) method, or get()[0]
Here's a link to API: ScrollableResults
get() returns the entire current row, get(index) returns object at index position without initializing the rest of them. There are also a bunch of convenience getXXX() methods that cast result to given type.
I do a query that returns a list of entities. How can I retrieve the entities from a ScrollableResults... How do I get an employee.
Just to improve the other answers, the ScrollableResults does the entity conversion for you although this isn't immediately clear from the Javadocs.
As #Bozho says, calling sr.get() will return the entity at the current location, but wrapped in an array. In looking at the code for ScrollableResultsImpl the current row's result is set with:
if ( result != null && result.getClass().isArray() ) {
currentRow = (Object[]) result;
} else {
currentRow = new Object[] { result };
}
So ScrollableResults.get() always returns an array of results and if your entity is not an array, it will be at get()[0].
So, with your code you would do something like:
while (sr.next()) {
// get the entity which is the first element in an Object[]
Employee employee = sr.get()[0];
...
}
To retrieve entities the simplest way would be to cast the object to whichever object you want:
E.g:
ScrollableResults sr = q.scroll();
while (sr.next()) {
CustomObject object = (CustomObject) sr.get()[0]; // Now CustomObject will have all the properties mapped
}
This works perfect for all the scenarios.