let's say i have 2 queries and 2 ResultSet. the first one is members table query, while the second query is for other member datas. now i want to join the first resultset with the second one. for example it looks like this
ResultSet rsMember = psMembers.executeQuery();
ResultSet rsCustomValues = psCustomValues.executeQuery();
// object for mapping query results
MembersMapper memberMapper = new MembersMapper();
while (rsMember.next()) {
memberMapper.setId(rsMember.getString("id"));
memberMapper.setName(rsMember.getString("name"));
memberMapper.setUsername(rsMember.getString("username"));
memberMapper.setGroup(rsMember.getString("group_id"));
List strCustomValues = new ArrayList<>();
while(rsCustomValues.next()){
// map the custom values
Map<String, Object> mapTemp = new HashMap<String, Object>();
mapTemp.put(FIELD_ID, rsCustomValues.getString("custom_field_id"));
mapTemp.put(INTERNAL_NAME,
rsCustomValues.getString("custom_field_internalname"));
mapTemp.put(NAME,rsCustomValues.getString("custom_field_name"));
strCustomValues.add(mapTemp);
}
memberMapper.setCustomvalues(strCustomValues);
}
the problem is the second (inner while) query. what connects data between first and second resultset is member id, which is primary key in first table (first query) and foreign key in second query. so the second query will have member id in random order.
so how can i order the second query without having to put 'order by member_id' in the second query? i will have to avoid 'order by member_id' because it will take time to process.
Edit: here's the scripts
First script
select
mbr.*, usr.username, grp.name as groupname, grp.status
from members mbr
join users usr on mbr.id = usr.id
join groups grp on mbr.group_id = grp.id
where mbr.id > #id#
order by id asc
limit #limit#
Second script
select
cfv.member_id as 'member_id', cf.id as 'custom_field_id',
cf.internal_name as 'custom_field_internalname',
cf.name as 'custom_field_name', cfv.string_value as 'cfv_stringvalue',
cfv.possible_value_id as 'cf_possiblevalueid', cfvp.value as 'cfvpvalue'
from custom_field_values cfv
join custom_fields cf on cf.id = cfv.field_id
left join custom_field_possible_values cfvp on cfv.possible_value_id = cfvp.id
where exists(
select * from (select id from members where id > #id#
limit #limit#
) result where result.id = cfv.member_id)
and cf.subclass = #subclass#
order by cfv.member_id asc
It is better to fetch the second result set to an object representation and sort it out.
See a similar question here How can I sort ResultSet in java?
Related
SELECT NEW Map (PRODUCT_CATEGORY, COUNT(PRODUCT_CATEGORY) AS COUNTER) from Product WHERE USER_ID = (SELECT USER_ID FROM USERS WHERE USERNAME='burak123'
Hi everyone,
As hibernates document says here: https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html#queryhql-select
I am trying to map the query result into a hash map like this
#Query(value = "SELECT NEW Map( PRODUCT_CATEGORY , COUNT(PRODUCT_CATEGORY) AS COUNTER ) from Product WHERE USER_ID=(SELECT USER_ID FROM USERS WHERE USERNAME=(:username)) ",nativeQuery = true)
HashMap<Integer,Integer> getCategoryCountsWithUsername(#Param("username")String username);
But it throws an JdbcSyntaxErrorException. I am trying to solve this for like 1 hours already. Can someone help?
You are using a native query, not an HQL query. Check your SQL syntax.
With a native query, your named parameter won't work. You need to remove the nativeQuery = true
I have stored objects in a database using tables, I retrieve data from objects in following way:
String query = "SELECT * FROM Librarian WHERE (id = ?)";
Account ac = null;
try {
state = conn.prepareStatement(query);
state.setString(1,passport);
rs = state.executeQuery();
if(rs.next()) {
ByteArrayInputStream bais = new ByteArrayInputStream(rs.getBytes("Object"));
try {
ObjectInputStream ois = new ObjectInputStream(bais);
ac = (Account) ois.readObject();
and then I can access values e.g ac.getName etc..
But this gives me only one object. In a table(given below) I have stored 3 foreign keys and I want to join 3 tables to get information from them, but each table has Object i.e I want to retrieve information from those Objects, hence I want to join tables and get information from objects.
CREATE TABLE Orders
(OrderID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Passport VARCHAR(20) NOT NULL,
FOREIGN KEY (Passport) REFERENCES Guest(Passport) ON DELETE CASCADE,
ISBN INT NOT NULL,
FOREIGN KEY (ISBN) REFERENCES Books(ISBN) ON DELETE CASCADE,
LibPassport VARCHAR(20) NOT NULL,
FOREIGN KEY (LibPassport) REFERENCES Account(LibPassport) ON DELETE CASCADE,
Object LONGBLOB NOT NULL
);
If you need more explanations or code please let me know.
Regards,
I must be missing something...
String query = "SELECT *
FROM ORDERS O
INNER JOIN GUEST G
on O.Passport = G.Passport
INNER JOIN Books B
on B.ISBN = O.ISBN
WHERE (O.OrderID = ?)";
Assuming you only want records were all the keys match.
If you want all records from one table, and only those matching in others, then you have to use LEFT, Right or Full outer joins (later of which isn't supported in mySQL, so you have to use a left and right and a union)
You have to use aliases for the columns you specify in the SELECT part. your query should look like this:
SELECT
o.Id,
o.Whatever,
p.ID,
p.Name,
...
p.Object AS Passport_Object,
b.ID,
b.Name,
...
b.Object AS Books_Object,
a.ID,
...
a.Object AS Account_Object
FROM
Orders AS o
JOIN
Passport AS p ON ...
JOIN
Books AS b ON ...
JOIN
Account AS a ON ...
WHERE
-- some condition here
Do not use SELECT * in your queries, see the question What is the reason not to use select *?.
I need to create a query and I need COUNT(*) and HAVING COUNT(*) = x.
I'm using a work around that uses the CustomProjection class, that I downloaded somewhere.
This is the SQL that I try to achieve:
select count(*) as y0_, this_.ensayo_id as y1_ from Repeticiones this_
inner join Lineas linea1_ on this_.linea_id=linea1_.id
where this_.pesoKGHA>0.0 and this_.nroRepeticion=1 and linea1_.id in (18,24)
group by this_.ensayo_id
having count(*) = 2
This is the code, where I use the Projection Hibernate class:
critRepeticion.setProjection(Projections.projectionList()
.add( Projections.groupProperty("ensayo") )
.add( CustomProjections.groupByHaving("ensayo_id",Hibernate.LONG,"COUNT(ensayo_id) = "+String.valueOf(lineas.size()))
.add( Projections.rowCount() )
);
The error is:
!STACK 0
java.lang.NullPointerException
at org.hibernate.criterion.ProjectionList.toSqlString(ProjectionList.java:50)
at org.hibernate.loader.criteria.CriteriaQueryTranslator.getSelect(CriteriaQueryTranslator.java:310)
at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:71)
at org.hibernate.loader.criteria.CriteriaLoader.<init>(CriteriaLoader.java:67)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1550)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
at ar.com.cse.cseagro.controller.RepeticionController.buscarEnsayo(RepeticionController.java:101)
If I comment the line with CustomProjections class, the query work, but I don't get the HAVING COUNT(*) filter in the SQL ...
Basically the query try to retrieve, in a master - detail schema, all the master records where a list of details are simultaneously present, like if you want tho know "which invoices have both products, A and B".
That why if I got 3 items in the IN clause, I need to use HAVING COUNT = 3 clause.
Any idea or suggestion?
Best regards,
I figured out the problem. I replace CusotmProjections class, with:
.add( Projections.sqlGroupProjection("ensayo_id", groupBy , alias, types));
where groupBy, alias and types are:
String groupBy = "ensayo_id" + " having " + "count(*) = " + String.valueOf(lineas.size());
String[] alias = new String[1];
Alias[0] = "ensayo_id";
Type[] types = new Type[1];
types[0] = Hibernate.INTEGER;
and the magic is on groupby String. –
If someone needs to do it in grails it would be like:
projections {
groupProperty("id")
sqlGroupProjection(...)
rowCount()
}
Where sqlGroupProjection is available since 2.2.0
/**
* Adds a sql projection to the criteria
*
* #param sql SQL projecting
* #param groupBy group by clause
* #param columnAliases List of column aliases for the projected values
* #param types List of types for the projected values
*/
protected void sqlGroupProjection(String sql, String groupBy, List<String> columnAliases, List<Type> types) {
projectionList.add(Projections.sqlGroupProjection(sql, groupBy, columnAliases.toArray(new String[columnAliases.size()]), types.toArray(new Type[types.size()])));
}
http://grepcode.com/file/repo1.maven.org/maven2/org.grails/grails-hibernate/2.2.0/grails/orm/HibernateCriteriaBuilder.java/#267
Here is my sample, it works fine, maybe useful :
My sql query :
select COLUMN1, sum(COLUMN2) from MY_TABLE group by
COLUMN1 having sum(COLUMN2) > 1000;
And Criteria would be :
Criteria criteria = getCurrentSession().createCriteria(MyTable.Class);
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.property("column1"), "column1");
projectionList.add(Projections.sqlGroupProjection("sum(column2) sumColumn2 ", "COLUMN1 having sum(COLUMN2) > 1000" , new String[]{"sumColumn2"}, new org.hibernate.type.Type[]{StandardBasicTypes.STRING}));
criteria.setProjection(projectionList);
criteria.List();
criteria.add(Restrictions.sqlRestriction("1=1 having count(*) = 2"));
I'm new to hibernate and I've this SQL query which works perfectly
SELECT count(*) as posti_disponibili from occupazione t inner join
(select id_posto_park, max(date_time) as MaxDate from occupazione
group by id_posto_park) tm on t.id_posto_park = tm.id_posto_park and
t.date_time = tm.Maxdate and t.isOccupied = 0
which gives me all the last items with isOccupied = 0
I was porting it into Hibernate, I've tried to use
result = ( (Integer) session.createSQLQuery(query).iterate().next() ).intValue()
to return posti_disponibili but i got this exception
java.lang.UnsupportedOperationException: SQL queries do not currently support iteration
How can i solve this? I cannot find the equivalent HQL query
Thank you
I would suggest you to use
Query#uniqueResult()
which will give you single result.
select count(*) .....
will always return you a single result.
Hibernate support it's own iterator-like scroll:
String sqlQuery = "select a, b, c from someTable";
ScrollableResults scroll = getSession().createSQLQuery(sqlQuery).scroll(ScrollMode.FORWARD_ONLY);
while (scroll.next()) {
Object[] row = scroll.get();
//process row columns
}
scroll.close();
Following is my code(Re-constructed) which select & update STATUS field depending upon the conditions. (Using Servlets, Oracle as Backend and JDBC driver)
ResultSet rs=null;
String query = "select A.NAME, A.ADDRESS, A.STATUS, B.CLASS from TABLE_ONE A, TABLE_TWO B where A.STATUS='N'";
pstmt = con.prepareStatement(query,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
rs = pstmt.executeQuery();
while(rs.next())
{
String name = rs.getString("NAME");
String address = rs.getString("ADDRESS");
String class = rs.getString("CLASS");
String msg = //Other statements to check what status to be set
if(msg.equals("OK"))
rs.updateString("STATUS", "S");
else
rs.updateString("STATUS", "E");
rs.updateRow();
}
I am getting the error while updating:
java.sql.SQLException: Invalid operation for read only resultset: updateString
Any suggestions will be appreciated.
Update 1:
The same code was working when select statement was selecting data from single table, so is there any issue when selecting data from two tables in single query?
[Note: As #javaBeginner has mentioned in comments it will work only for one table.]
The following limitations are placed on queries for enhanced result sets. Failure to follow these guidelines will result in the JDBC driver choosing an alternative result set type or concurrency type.
To produce an updatable result set (from specification):
A query can select from only a single table and cannot contain any join operations.
In addition, for inserts to be feasible, the query must select all non-nullable columns and all columns that do not have a default value.
* A query cannot use "SELECT * ". (But see the workaround below.)
* A query must select table columns only. It cannot select derived columns or aggregates such as the SUM or MAX of a set of columns.
To produce a scroll-sensitive result set:
A query cannot use "SELECT * ". (But see the workaround below.)
A query can select from only a single table.
Try This :
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
//Execute a query
String sql = "select A.NAME, A.ADDRESS, A.STATUS, B.CLASS from TABLE_ONE A, TABLE_TWO B where A.STATUS='N'";
ResultSet rs = stmt.executeQuery(sql);
//Extract data from result set
rs.beforeFirst();
while(rs.next())
{
String name = rs.getString("NAME");
String address = rs.getString("ADDRESS");
String class = rs.getString("CLASS");
String msg = //Other statements to check what status to be set
if(msg.equals("OK"))
rs.updateString("STATUS", "S");
else
rs.updateString("STATUS", "E");
rs.updateRow();
}
Just changed Prepared statement to create statement
SELECT * makes the resultSet readonly. SELECT COLUMN_NAME makes it updatable.
So instead of SELECT * FROM TABLE use SELECT COLUMN1, COLUMN2, ... FROM TABLE.