Multiple sql queries to single query using inner join - java

i have this java code:
ArrayList<MessageMap> ids = getNewMail(UserID, type, maxIdMessage);
Message[] message = new Message[ids.size()];
if(ids.size()>0){
ResultSet rs;
int j =0;
for(MappaMessaggi i : ids){
pstmt = conn.prepareStatement("SELECT * FROM Messaggi WHERE MessageID = ?");
pstmt.setInt(1, i.getMessageID());
rs = pstmt.executeQuery();
rs.next();
.
.
.
}
where getNewMail is:
public synchronized ArrayList<MessageMap> getNewMail(int UserID,int type,int max){
ArrayList<MessageMap> map = new ArrayList<MessageMap>();
try {
pstmt = conn.prepareStatement("SELECT * FROM MessageMap WHERE UserID = ? AND TipoID = ? AND MessageID > ?");
.
.//fill arraylist with resultSet
.
}
I know that is possible to do the same with just one query but i don't know how.. can someone open my eyes? :) thanks!!!
EDIT: i try:
SELECT i.*
FROM Messaggi AS i
INNER JOIN MessageMap AS p i.MessageID = p.MessageID
WHERE p.MessageID = 1 AND p.UserID = 1 AND p.TipoID = 2
BUT I RETRIEVE:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'i.MessageID = p.MessageID WHERE p.MessageID = 1 AND p.UserID = 1 AND p.TipoID = ' at line 3

Try this:
SELECT i.*, p.*
FROM Messaggi i
INNER JOIN MessageMap p ON i.MessageID = p.MessageID
WHERE i.MessageID = ? AND p.UserID = ? AND p.TipoID = ?

Based in your question and queries, the simple solution I find could be this query (maybe there are another columns that relate your tables)
SELECT A.*
FROM MessageMap A
INNER JOIN Message B on A.MessageId = B.MessageId
WHERE
A.UserId = ?
AND A.TipoID = ?
AND A.MessageId = ?
Also, please specify if you need those 3 parameters or you could not send any of them.

Related

Alternative for COALESCE when all its parameters is null

I am developing a web application (java-maven project) and there is a problem with the query I use. The UI of my web app has 2 search fields: PTT and ID.
The user needs to fill at least one of the fields to make a search. So both fields are nullable but not at the same time.
Before, I had only one field: PTR and it was showing a result array of size 52. (also getting the same number if
I execute select * from users where ptr='smthing' ). After that I added ID field and updated my query as below:
I execute this query in my webservice:
String query= "SELECT t.ptr, t.id ";
query+= "FROM users t ";
query+= "WHERE t.ptr = COALESCE(?, t.ptr) AND " ;
query+= "t.id = COALESCE(?, t.id) ";
and set the fields with the help of Prepared Statement.
Now if the ptr field is filled, but id field is left blank (this can be null or empty string) on the UI and user makes a search, result array size becomes 30. I compared with database
and it does not fetch the rows where ID is null. So coalesce is not what I need when both of its parameters (?, t.ptr) is null.
How can I fix this problem, any suggestions?
I think the logic you want is:
WHERE (t.ptr = ? OR ? IS NULL) AND
(t.id = ? OR ? IS NULL)
I would recommend using named parameters, so you don't have to pass them in twice.
Check this statement:
String query= "SELECT t.ptr, t.id ";
query+= "FROM users t ";
query+= "WHERE (t.ptr = ? OR 1 = ?)"
query+= " AND " ;
query+= "(t.id = ? OR 1 = ?)";
You see that for each of t.id and t.ptr there is a counterpart parameter. In total there will be 4 parameters.
You say that at least 1 of t.id or t.ptr has a valid value, so there are 2 cases:
[1] t.id and t.ptr both have valid values.
For both the counterpart parameters you pass 0 and the query becomes:
"SELECT t.ptr, t.id FROM users t WHERE (t.ptr = valueptr OR 1 = 0) AND (t.id = valueid OR 1 = 0)"
In the WHERE part:
t.ptr = valueptr OR 1 = 0 is equivalent to t.ptr = valueptr, and
t.id = valueid OR 1 = 0 is equivalent to t.id = valueid,
and the query finally becomes:
"SELECT t.ptr, t.id FROM users t WHERE t.ptr = valueptr AND t.id = valueid"
[2] from t.id or t.ptr only one has a valid value, let's say this is t.ptr.
For the counterpart of t.ptr you pass 0, for t.id you pass -1 (or any other non existing value) and for the counterpart of t.id you pass 1 and the query becomes:
"SELECT t.ptr, t.id FROM users t WHERE (t.ptr = valueptr OR 1 = 0) AND (t.id = -1 OR 1 = 1)"
In the WHERE part:
t.ptr = valueptr OR 1 = 0 is equivalent to t.ptr = valueptr, and
t.id = -1 OR 1 = 1 is equivalent to true because 1 = 1 is always true,
and the query finally becomes:
"SELECT t.ptr, t.id FROM users t WHERE (t.ptr = valueptr OR 1 = 0)"
equivalent to:
"SELECT t.ptr, t.id FROM users t WHERE (t.ptr = valueptr)"
(In the case where only t.id has a valid value then you pass an invalid value for t.ptr and 1 for its counterpart and for the counterpart if t.id you pass 0.)
Maybe it seems complicated but it's working and it can be extended for more than 2 columns.
Oracle has build function for this. But it's hard to understand how to use its.
lnnvl(a = b) = true if (a != b ) or ( a = null ) or (b = null)
in your case
WHERE lnnvl(t.ptr != ? ) AND lnnvl( t.id != ?)
LNNVL

Java MYSQL Query , get 2 variables from different tables

Got a question, how can i get 2 different variables from different tables using mysql? Is it possible to make it work from 1 query using prepared statement? I'm new at mysql database programming with java, so that's my problem.
I'm trying to get:
user_key from user table
project_key from project table
and yes, I know, table names should be in non singular form.
I'm trying :
String project_key = null;
String user_key = null;
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://mysql:" + Config.getPortDB() + "/" + Config.getDatabase() + "?"
+ "user=" + Config.getUsername() + "&password=" + Config.getPassword());
String query ="SELECT user_key,project_key FROM user, project WHERE user_key = ? AND project_key = ?";
PreparedStatement preparedStatement = con.prepareStatement(query);
for(int i = 0; i < auths.size() ; i++ ) {
preparedStatement.setString(i+1, auths.get(i));
}
ResultSet rs = preparedStatement.executeQuery();
while(rs.next()) {
project_key = rs.getString("project_key");
user_key = rs.getString("user_key");
}
System.out.println(project_key); // null
System.out.println(user_key); // null
What am I doing wrong here?
SELECT u.user_key,
p.project_key
FROM (select user_key from user WHERE user_key = ?) u,
(select project_key from project WHERE project_key = ?) p
If the tow tables has no relation at all you still can get the 2 values using subqueries
This is your current query:
SELECT user_key,project_key
FROM user, project
WHERE user_key = ?
AND project_key = ?
To get results from 2 tables use JOIN, like this:
SELECT u.user_key, p.project_key
FROM user u
JOIN project p ON p.userId = u.id
WHERE u.user_key = ?
AND p.project_key = ?

column is invalid in select list because it is not contained in an aggregate function or group by clause

I have a Java method that looks like this:
public ArrayList<Orders> GetOrders(Connection connection, int id) throws Exception
{
ArrayList<Orders> feedData = new ArrayList<Orders>();
ArrayList<Integer> itemsId = new ArrayList<Integer>();
try
{
PreparedStatement ps = connection.prepareStatement("SELECT o.id, o.userId FROM dbo.Orders o join dbo.Items I on o.itemId = I.id join dbo.Users u on o.UserId = u.Id where o.userId = ? group by o.id, o.userId");
ps.setInt(1, id);
ResultSet rs = ps.executeQuery();
while(rs.next())
{
Orders o = new Orders();
o.setId(rs.getInt("id"));
ps = connection.prepareStatement("SELECT o.ItemId, SUM(price) as price FROM dbo.Orders o join dbo.Items I on o.itemId = I.id WHERE o.UserId= ? GROUP BY o.id");
ps.setInt(1, id);
ResultSet rs2 = ps.executeQuery();
while(rs2.next()){
itemsId.add(rs2.getInt("ItemId"));
//total = total + rs2.getInt("price");
}
o.setItem(itemsId);
o.setUserId(rs.getInt("userId"));
o.setTotalAmount(rs2.getInt("total"));
feedData.add(o);
}
return feedData;
}
}
In the second prepared statement, where I have this query:
SELECT o.ItemId, SUM(price) as price FROM dbo.Orders o join dbo.Items
I on o.itemId = I.id WHERE o.UserId= ? GROUP BY o.id
I get above mentioned exception.
i.e
com.microsoft.sqlserver.jdbc.SQLServerException: Column 'dbo.Orders.ItemId' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
The problem is that you are selecting sum(price) as total in your second snippet, hence the result set column is named total. Since you're grouping by item id you get the sum of prices per item and need to do the total calculation yourself or use another query.
Try using total += rs2.getInt("total"); and o.setTotalAmount(total) after the while loop.
This appears to be the query you are referring to:
SELECT ItemId, price
FROM dbo.Orders o join
dbo.Items I
on o.itemId = I.id
WHERE o.UserId= ?
GROUP BY o.id, o.ItemId;
Your query does not work because price is not in the group by clause.
If you want the sum of prices by item, then I would think you want:
SELECT o.ItemId, SUM(price) as price
FROM dbo.Orders o join
dbo.Items I
on o.itemId = I.id
WHERE o.UserId= ?
GROUP BY o.ItemId;
You've ran into a fundamental requirement of SQL. Any time you have a a "group by" clause, SQL only permits the columns that are groupped on, or aggregates.
The reason is simple: you're groupping on id, so there will be a single group per value of id, and that translates into a single row in the result of select - per value of id. Now supppose there are multiple itemIdvalues for given id, say the rows with id = 5 have itemId values of 10, 20 and 30.
The SQL engine cannot put 3 different values into one row!
And that's why, when you do group by the select result can only include columns from group by and aggregates.
(Some databases relax this requirement a little, and it leads to really messy and hard to understand results)

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

How to reduce query time using JDBC?

I am fetching records from MySQL database using Java (JDBC). I have tables -
Stop_Times with 1.5 Million records and
Stops with 1 lac records.
I am using following code
ResultSet rs = stm.executeQuery("select distinct(stop_id) from Stop_Times force index (idx_stop_times) where agency_id = '" + agency_id + "' and route_type = " + route_type + " order by stop_id");
while(rs.next())
{
stop_id.add(rs.getString("stop_id"));
}
JSONArray jsonResult = new JSONArray();
String sql = "select * from Stops force index (idx_Stops) where stop_id = ? and agency_id = ? and location_type = 0 order by stop_name";
PreparedStatement pstm = con.prepareStatement(sql);
int rid = 0;
for(int r = 0; r < stop_id.size(); r++)
{
pstm.setString(1, stop_id.get(r).toString());
pstm.setString(2, agency_id);
rs = pstm.executeQuery();
if(rs.next())
{
JSONObject jsonStop = new JSONObject();
jsonStop.put("str_station_id", rs.getString("stop_id"));
jsonStop.put("str_station_name", rs.getString("stop_name") + "_" + rs.getString("stop_id"));
jsonStop.put("str_station_code", rs.getString("stop_code"));
jsonStop.put("str_station_desc", rs.getString("stop_desc"));
jsonStop.put("str_station_lat", rs.getDouble("stop_lat"));
jsonStop.put("str_station_lon", rs.getDouble("stop_lon"));
jsonStop.put("str_station_url", rs.getString("stop_url"));
jsonStop.put("str_location_type", rs.getString("location_type"));
jsonStop.put("str_zone_id", rs.getString("zone_id"));
jsonResult.put((rid++), jsonStop);
}
}
The first query returns 6871 records. But it is taking too much time - on server side it is taking 8-10 seconds and at client side 40-45 seconds.
I want to reduce these times as for server side 300-500 milliseconds and at client side around 10 sec.
Please can anybody help me for how to to this?
Your strategy is to use a first query to get IDs, and then loop over these IDs and execute another query for each of the IDs found by the first query. You're in fact doing a "manual" join instead of letting the database do it for you. You could rewrite everything in a single query:
select * from Stops stops
inner join Stop_Times stopTimes on stopTimes.stop_id = stops.stop_id
where stops.stop_id = ?
and stops.agency_id = ?
and stops.location_type = 0
and stopTimes.agency_id = ?
and stopTimes.route_type = ?
order by stops.stop_name
Try to get the explain plan associated with your request (Cf. http://dev.mysql.com/doc/refman/5.0/en/using-explain.html) ; avoid full table scan (Explain join ALL). Then add relevant indexes. Then retry.

Categories