Optimization: Getting SQL Query out of loop - java

I have two tables with a 1 to n relationship.
table hobbies has a foreign key to table users called "userid"
SELECT * FROM hobbies WHERE userid = 7
can have multiple results.
table users contains a list of user profile data and table hobbies contains a list of user hobbies. I want to print a list of profile info of multiple users with hobbies of each user. (hobbies concatenated into one String)
i currently have the following sql queries: (pseudocode):
ResultSet result = executeQuery("SELECT * FROM users;");
for each returned row: executeQuery("SELECT * FROM hobbies WHERE userid =" + result.getInt("ref"));
how do I get the SQL queries out of the loop to optimize performance with a big list of users?
I was trying to do a LEFT JOIN and then doing the WHERE ref= check in java instead of in SQL
problem is that I then get duplicate users and i only want to print one row for each user when processing the result set
also Im not sure if the JOIN is really an improvement in performance, because I have to process more rows.
table users
+--------+------+---------+--------+
| userid | name | country | telno |
+--------+------+---------+--------+
| 1 | John | USA | 123456 |
| 2 | Max | Germany | 345678 |
+--------+------+---------+--------+
+--------------+------------+
| userid |hobby |
+--------------+------------+
| 1 | football |
| 1 | basketball |
| 2 | TV |
| 2 | Music |
| 2 | football |
+--------------+------------+
example output:
John, USA, 123456, {football, basketball}
Max, Germany, 345678, {TV, Music, football}

This is most probably the fastest solution
SELECT name, country, telNo, GROUP_CONCAT(hobby)
FROM users u LEFT JOIN hobbies h ON u.id = h.userId
GROUP BY name, country, telNo
See https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_group-concat for formatting options.
It's only good for the final output, e.g., if your hobbies contain commas, you wont't be able to parse them uniquely.

You can try :
SELECT h.userid, h.allyouneed FROM hobbies h, users u WHERE h.userid =u.userid
and get the info in one query

"SELECT * FROM hobbies h join users u on h.userid = u.userid WHERE userid = ?"
preparedStatement.setInt(result.getInt("ref"));
You can then save all the hobbies to a list similar to the 'Book' example below.
public static List<String> selectAll() throws SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
// THE LIST OF BOOKS YOU WILL RETURN
List<String> books = new ArrayList<>();
String sql = "SELECT BOOK FROM BOOKs";
try(Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bookshop", "root", "");){
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while(rs.next()){
String book= rs.getString ("BOOK");
// ADD BOOK TO THE LIST
books.add(book);
}
}
finally{
ps.close();
rs.close();
}
// RETURN LIST OF ALL BOOKS
return books;
}

SELECT u.userid,u.name,u.country GROUP_CONCAT(hobby SEPARATOR ',')
FROM hobbies as h join users as u on h.userid=u.userid
where h.userid = ? GROUP BY u.userid,u.name,u.country;
assumming you have relationship on hobbies to users. the query will concat the columns of hobby of the join tables, and there will be one unique user per row.

Related

Query MySQL with multiple identifier

I have a MySQL table with more than a million rows like this:
id (BIGINT) | id_other (INT)
24334501 | 20123
24334501 | 20324
24334501 | 20111
24334500 | 20123
24334500 | 20324
24334510 | 20111
....
From this table, I want to build a map from a list of ids like this:
id_other -> count of id
my query is: "select * from lsh where id = ?"
To perform those queries, I created an index for the column ìd
Now I want to get a list of all id_other from a list of id.
Currently I have this code:
for (Long id : ids{ // ids has a size between 2000 and 8000
statement.setLong(1, id);
ResultSet rs = statement.executeQuery();
while(rs.next()) {
int idOther = rs.getInt("id_other");
if(!map.containsKey(idOther)){
map.put(idOther, new AtomicInteger(0));
}
map.get(idOther).incrementAndGet();
}
}
any ideas how to perform this?
UPDATE:
Now I have this query: select id_other, count(*) FROM lsh WHERE id ? GROUP BY id_other .
I execute the query with:
Array array = connection.createArrayOf("BIGINT", values.toArray());
statement.setArray(1, array);
final ResultSet rs = statement.executeQuery();
But now I get this exception for connection.createArrayOf: java.sql.SQLFeatureNotSupportedException
thank you
I think you want something like the following (SQL Fiddle):
SELECT id_other, COUNT(*) AS total_ids , GROUP_CONCAT(id) AS list_id
FROM lsh
WHERE id_other IN (20111, 20123, 20324)
GROUP BY id_other
ORDER BY id_other;
Result:
id_other total_ids list_id
20111 2 24334501,24334510
20123 2 24334500,24334501
20324 2 24334500,24334501

SQL Query works in SQL Developer, but not on the Java side

I'm trying to figure this but without success. I'm trying to find every row in a specific table that contains a value.
For example, let's consider this Employee table:
| Id | First_name | Last_name | Date_of_birth | Car_number |
|------------------|------------|------------|---------------|------------|
| 10001 | John | Washington | 28-Aug-43 | 5 |
| 10083 | Arvid | Sharma | 24-Nov-54 | null |
| 10034 | David | Johnson | 12-May-76 | |
I'm building this query on the Java side (this is what I print in the log):
Select * From Employee WHERE Id LIKE ? OR First_name LIKE ? OR Last_name LIKE ? OR Date_of_birth LIKE ? OR Car_number LIKE ?
then I use a prepared statement so that, if I search for the string 'oh' it becomes:
Select * From Employee WHERE Id LIKE '%oh%' OR First_name LIKE '%oh%' OR Last_name LIKE '%oh%' OR Date_of_birth LIKE '%oh%' OR Car_number LIKE '%oh%'
Here's the corresponding code:
String wantedQuery = "Select * From " + tableName + " WHERE";
PreparedStatement preparedStatement;
try(ResultSet rsColumns = columnsForTable(tableName)) {
String keyword = keywordField.getText();
int limit = 0;
while (rsColumns.next()) {
wantedQuery += " " + rsColumns.getString(1) + " LIKE ? OR";
limit++;
}
wantedQuery = wantedQuery.substring(0, wantedQuery.length()-3);
preparedStatement = con.prepareStatement(wantedQuery);
System.out.println(wantedQuery);
System.out.println("\'%"+keyword+"%\'");
for(int i = 1; i <= limit; i++) {;
preparedStatement.setString(i, "\'%"+keyword+"%\'");
}
}
try(ResultSet rs = preparedStatement.executeQuery()) {
//now get the results from here
ResultSetMetaData metaData = rs.getMetaData();
while (rs.next()) {
System.out.println("Fetching row");
...
}
Now the problem is that when I try to get the results, it gives me 0 rows (I never see "Fetching row" printed) but the query works in SQL Developer. So I guess the error is on the Java side but I have any clue what it can be. Any ideas?
When you are using setString(), JDBC knows that it must be a String, so it puts the single quotes around the String as needed, you don't have to do it yourself. But because you do so, it actually a different one, than what you expect.
Try below mentioned methods
Add spaces at the start and at the end in the query in java code
Remove ; from the end of the sql in java code as whenever java code executes sql it appends ; to it.

Hibernate Join Mapping

I have two db tables:
TARGET_TABLE (composite key on USER_ID and TARGET_ID)
USER_ID | TICKET_NO | TARGET_USER
---------------------------------
A11 | 12345 | A22
A11 | 12346 | A33
A44 | 12347 | A55
USER_DETAILS_TABLE
CORP_ID | USER_NAME
------------------
A11 | Steve
A22 | Jon
A33 | Paul
A44 | Dave
A55 | James
I want to be able to join these tables when I'm using select statements only.
For example I would like to do:
Select USER_ID, USER_NAME, TICKET_NO FROM TARGET_TABLE INNER JOIN USER_DETAILS ON TARGET_TABLE.USER_ID = USER_DETAILS_TABLE.CORP_ID
I can't seem to find the best way to do this. I have looked at the Hibernate examples for mapping but these are examples on how to write to both tables I simply want to get a user name from a table I can't touch!
I currently have two separate mappings for each table and run a separate query to get the user name but this doesn't seem like the best way to do it.
This HQL would work select tt.userId, tt.ticketNo, u.userName from TargetTable tt, User u where tt.userId = u.corpId.
However, this would return a List<Object[]> where each list element represents one row with 3 columns. You could extract these manually, or for example have some my.package.UserVO object with constructor public UserVO(String userId, String ticketNo, String userName) { ... }. In that case, this
session.createQuery("select new my.package.UserVO(tt.userId, tt.ticketNo, u.userName) from TargetTable tt, User u where tt.userId = u.corpId", UserVO.class).list()
would return instances of UserVO.

Hibernate - Distinct Query returning two columns result

Sometime back I asked the question regarding how to do a Distinct query using Hibernate. Now that I'm past that milestone, there is another thing that I require. And that is, given the table,
---------------------------------------
| user_id | user_name | user_type |
---------------------------------------
| 1 | mark taylor | admin |
| 2 | bill paxton |co-ordinator|
| 1 | tony brooks | admin |
| 3 | ali jahan | developer |
---------------------------------------
I want to create a distinct query which returns the distinct user_type along with it's corresponding user_id. Please do note that the user_id for a particular user_type is same. So for example,
admin = 1
co-ordinator = 2
developer = 3
So the return I'm expecting is somewhat like a ArrayList or that sort which contains both values like
user_id,user_type
The code I've written to get Distinct UserType is as follows and I'm hoping there could be some modification to it to get the desired result.
public List<String> findDistinctUserName() throws HibernateException {
List<String> returnVal = new ArrayList<String>();
Criteria c = this.createCriteria();
c.setProjection(Projections.distinct(Projections.property("userType")));
c.addOrder(Order.asc("userType"));
List<String> userTypeList = c.list();
for(String userType : userTypeList) {
if(!userType.equalsIgnoreCase("")) {
returnVal.add(userType);
}
}
return returnVal;
}
Thank you for your answers in advance.
Try this:
criteria.setProjection(Projections.distinct(Projections.property("userType")), "userType");
Also u don't have to check for blank strings, try this:
criteria.add(Restrictions.ne("userType",""));

JAVA mySQL JOIN 2 tables

Hey guys I'm looking to get information out of 2 tables to create a JTABLE with that information.
The tables I am look at are 'shipments' and 'customers'
Where shipments takes the form of
shipNumber | shipperID | destID | size | weight
and customers takes the form of
ID | lastName | firstName | street | city | state | zip
The shipperID and destID both refer to a customer ID.
I am trying to get the city/state information out of the customers table that corresponds to the shipperID and destID.
I have tried the following
query = "SELECT shipments.shipNumber, customers.city, customers.state, customers.city, customers.state FROM shipments, customers WHERE shipments.shipperID = customers.ID";
Realizing that the duplicate customers.city/customers.state is populating the same information twice.
As previously said, I am trying to get the shipper city/state and destination city/state.
I also tried
query = "SELECT shipments.shipNumber, customers.city, customers.state, customers.city, customers.state, shipments.size"
+ " FROM shipments"
+ " INNER JOIN customers ON customers.id = shipments.shipperID";
Where this gives the same information.
I am not sure how to reference the destID = customer.id
Thanks,
Mike
The usual trick is to join with the customers table twice, once for the shipper and once for the destination:
SELECT shipments.shipNumber,
shipper.city, shipper.state,
dest.city, dest.state,
shipments.size
FROM shipments
INNER JOIN customers shipper ON shipper.id = shipments.shipperID
INNER JOIN customers dest ON dest.id = shipments.destID

Categories