I have a stored procedure call
call get(id);
in my database that would return a single row in a ResultSet object (it is basically a very long SELECT statement inside). Now in Java, I have a
int[] ids = {1,2,3}
and for each id in the list I want to call the stored procedure to get the record. So eventually I want a list of records corresponding to each id in ids. I attempted
Connection conn = ...;
PreparedStatement ps = conn.prepareCall("call get(?)");
for(int id : ids) {
ps.setInt(1, id); ps.addBatch();
}
ps.executeBatch();
with only the result of call
get(3);
is kept.
I also tried to move the SELECT statement directly as a String in Java, so it looks like
String stmt = "SELECT ... WHERE id=?"
PreparedStatement ps = conn.prepareStatement(stmt);
... // the for loop same as above
ps.executeBatch();
with a "Can not issue executeUpdate() for SELECTs". I tried
ps.executeQuery();
as the last line, but it also only has the result of the last SELECT.
I want to avoid a for loop that executes a SELECT a time because transferring data from the database to my computer has a very heavy overhead.
Can anyone help? Thank you in advance!
EDIT: I read Running the same select query multiple times with different parameters: Mysql , but in my case it is a little bit different, because in my select statement the id actually needs to be referenced several times; the code looks like this
SELECT * FROM
(SELECT ... FROM ... WHERE id=? AND ...),
(SELECT ... FROM ... WHERE id=? AND ...);
so it seems impractical to use the IN method. Also I have another call
call get2(aid, userId)
and a list of {{1, 1000}, {2, 2000}} which also does not fit this issue. Can anyone help? Thank you!
Related
I have a table called Coupon.
This table has a column called query which holds a string.
The query string has some logical conditions in it formatted for a where statement. For example:
coupon1.query
=> " '/hats' = :url "
coupon2.query
=> " '/pants' = :url OR '/shoes' = :url "
I want to write a stored procedure that takes as input 2 parameters: a list of Coupon ids and a variable (in this example, the current URL).
I want the procedure to look up the value of the query column from each Coupon. Then it should run that string in a where statement, plugging in my other parameter (current url), then return any Coupon ids that matches.
Here's how I would expect the procedure to behave given the two coupons above.
Example 1:
* Call procedure with ids for coupon1 and coupon2, with #url = '/hats'
* Expect coupon1 to be returned.
Example 2:
* Call procedure with ids for coupon1 and coupon2, with #url = '/pants'
* Expect coupon2 to be returned.
Example 3:
* Call procedure with ids for coupon1 and coupon2, with #url = '/shirts'
* Expect no ids returned. URL does not match '/hats' for coupon1, and doesn't match '/pants or /shoes' for coupon2.
It's easy to test these out in ActiveRecord. Here is just example 1.
#url = '/hats'
#query = coupon1.query
# "'/hats' = :url"
Coupon.where(#query, url: #url).count
=> 2
# count is non-zero number because the query matches the url parameter.
# Coupon1 passes, its id would be returned from the stored procedure.
'/hats' == '/hats'
#query = coupon2.query
# " '/pants' = :url OR '/shoes' = :url "
Coupon.where(#query, url: #url).count
=> 0
# count is 0 because the query does not match the url parameter.
# Coupon2 does not pass, its id would not be returned from the stored procedure.
'/pants' != '/hats', '/shoes' != '/hats'
You could write this as a loop (I'm in ruby on rails with activerecord) but I need something that performs better - I could potentially have lots of coupons so I can't just check each one directly with a loop. The queries contain complex AND/OR logic so I can't just compare against a list of urls either. But here's some code of a loop that is essentially what I'm trying to translate into a stored procedure.
# assume coupon1 has id 1, coupon2 has id 2
#coupons = [coupon1, coupon2]
#url = '/hats'
#coupons.map do |coupon|
if Coupon.where(coupon.query, url: #url).count > 0
coupon.id
else
nil
end
end
=> [1, nil]
Ok, I've been pondering this one.
Big picture:
A. You have a #url you want to search for to find a match among many potential Coupons
B. A coupon has a URL that might match #url
If that's the true extent of the problem, I think you've really over-complicated things.
coupon1.query
=> ["/hats"]
coupon2.query
=> ["/pants", "/shoes"]
#url = '/hats'
Coupon.where('FIND_IN_SET(:url, query) <> 0')
Or something similar, I'm not a mySQL user myself.
However, this is very possible to achieve and may even have a much better ActiveRecord way to do the query.
UPDATE
Ok, I'm missing something. I can't actually reproduce this in console.
#url = '/hats'
#query = coupon1.query
# "'/hats' = :url"
Coupon.where(#query, url: #url).count
> SELECT * FROM 'coupons' WHERE ( '/hats' = '/hats' )
As you can see from the select statement, this will always return all records. It's the same as writing SELECT * FROM 'coupons' WHERE ( true )
How are you actually performing a valid query?
Sorry to post this in my answer, I wanted good formatting.
If I've got something wrong here, maybe we need to move this to a chat room.
I think you have just enough reputation for me to invite you to a room.
UPDATE2
Since you have to compare #query to each record individually, I think you'll have to loop.
But, I don't think you need to use Coupon.where to accomplish this since you are only comparing one record at a time.
#coupons.map do |coupon|
# don't bother putting nil in the array
next unless coupon.query == #url
coupon.id
end
However, your original question was about performance when scaled, and you know you aren't going to solve that with a loop.
Maybe JSONB instead of String so that you could actually do some SQL.
But, even with JSONB, this is still complicated by wanting your conditions to be evaluated properly.
{
"url": {
"AND": ["/hats", "/shoes"],
"OR": ["/pants"]
},
"logged_in": true,
"is_gold_member": false
}
{
"logged_in": false,
"url": "/hats"
}
{
"url": {
"OR": ["/pants", "/shoes"]
}
}
Ultimately, I think what you're doing with query attributes is going to continue to be your stumbling block. It's very clever, but it's not simple.
If it were my app, I think I would go back to considering my use case and try to find a different strategy to map specific coupons to specific parameters in a more on-the-rails way.
When I execute a SQL query from Java and store the boolean returned, the query always returns true which shouldn't be the case at all. So I emptied the table and fired the query again, and yet it returns true for the emptied table. I have attached a picture of the table. I want the query to return true or false, so I can store it in Java. Can someone please specify an alternate code for this, please?
This is my code on java for the query.
boolean avail = st.execute("SELECT EXISTS(SELECT * from sales WHERE product='"+n+"' AND ord_date='"+sqlDate+"');");
And this is my code for result set
Statement st = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
This is the table, name of the table is 'sales'
I'm new to MySQL, a more specific approach is appreciated.
Statement.execute will return true regardless of what the query returns. You are still supposed to retrieve the actual result of the query.
Returns
true if the first result is a ResultSet object; false if it is an update count or there are no results
As you execute an EXISTS statement, there will always be a result (true or false). The actual value still has to be retrieved:
You must then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s).
For reference: https://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html#execute-java.lang.String-String
Also note that you are directly embedding strings into your query, this will leave you vulnerable to SQL injections. Please read: How can prepared statements protect from SQL injection attacks?. Recommended reading: Introduction to JDBC
The return value of Statement.execute() signals whether the query produces a result set (true) or - possibly - an update count (false). The query you execute is a select which will always produce a result set (even if empty). In other words, it will always return true for a select.
If you want to get the result of your query, then the recommend approach is to use executeQuery. However, you are also concatenating values into your query string, which is a bad idea because it leave you vulnerable to SQL injection. The recommended approach is to switch to prepared statements:
try (PreparedStatement pstmt = con.prepareStatement(
"SELECT EXISTS(SELECT * from sales WHERE product = ? AND ord_date = ?)")) {
pstmt.setString(1, n);
pstmt.setDate(2, sqlDate);
try (ResultSet rs = st.executeQuery() {
boolean avail = rs.next() && rs.getBoolean(1);
// use avail...
}
}
I have been trying to retrieve data from my database. I was successful, however, this time inside an if statement. The code looks like:
cur_msql = conn_mysql.cursor(cursor=pymysql.cursors.DictCursor)
select_query = """select x,y,z from table where type='sample' and code=%s"""
cur_msql.execute(select_query, code)
result2 = cur_msql.fetchone()
if(result2==None):
insert_func(code)
select_query = f"""select x,y,z from table where type='sample' and code='{code}'"""
mycur = conn_mysql.cursor(cursor=pymysql.cursors.DictCursor)
print(select_query)
mycur.execute(select_query)
result3 = mycur.fetchone()
if(result2==None):
result2=result3
Now I see that insert_func does successfully insert into the 'table'. However, on trying to fetch that row, immediately after the insertion, it returns None as if the row is absent. On debugging I find that result3 is also None. Nothing looks wrong to me but it's not working.
you donĀ“t execute it in the right way, in the cur_msql.execute, you the to send the query and a tuple of values, and you are sending just a value:
cur_msql = conn_mysql.cursor(cursor=pymysql.cursors.DictCursor)
select_query = "select learnpath_code,learnpath_id,learnpath_name from contentgrail.knowledge_vectors_test where Type='chapters' and code=%s"
cur_msql.execute(select_query, (meta['chapter_code'],))
result2 = cur_msql.fetchone()
I wish to select an array of records with id 2, 4, 6 from a mysql database file. I am trying to pass an array of integers to a Mysql store procedure. But I fail to create a working stored procedure.
Would you help me compose one?
This is the C# code
public static List<PhotoComment> GetPhotos(int[] _ids)
{
MySqlConnection _con = Generals.GetConnnection();
List<PhotoComment> _comments = new List<PhotoComment>();
try
{
MySqlCommand _cmd = new MySqlCommand("Photos_GetPhotosByIDs", _con);
_cmd.CommandType = CommandType.StoredProcedure;
_cmd.Parameters.AddWithValue("#_ids", _ids);
_con.Open();
MySqlDataReader _reader = _cmd.ExecuteReader();
while (_reader.Read())
{
PhotoComment _comment = new PhotoComment(_reader.GetInt32("cID"), _reader.GetInt32("cFID"), _reader.GetString("cUser"), _reader.GetString("cContent"), _reader.GetDateTime("cDate"), _reader.GetBoolean("cChecked"));
_comments.Add(_comment);
}
_con.Close();
}
catch (Exception _ex)
{
_con.Close();
ReportMgr.ReportException(_ex.Message);
}
return _comments;
}
this is the mysql
CREATE DEFINER=root#localhost PROCEDURE Photos_GetPhotosByIDs(in _ids int[])
BEGIN
select * from tbl_photos where ID in _ids;
END
There are no array types in MySQL. You can use table (temporary table) instead. Fill the bale with id values and join tables to get desired result.
I'm not sure if I'm getting your question right but what I think you're asking is how to send multiple values into an input parameter of a stored procedure.
If that's what you're asking, the following link may help. Not sure if such a feature exists in MySql but in SQL Server, it's called "Table-Valued Parameters" - TVP in short.
TVP allows you to pass multiple values into a single input parameter. Hope this helps: https://msdn.microsoft.com/en-us/library/bb675163(v=vs.110).aspx
Hi i have this managed bean where it makes MySQL queries, the problem here is the SQL statement makes a '=' condition instead of 'LIKE'
Here is the code in my managed bean.
Connection con = ds.getConnection();
try{
if (con == null) {
throw new SQLException("Can't get database connection");
}
}
finally {
PreparedStatement ps = con.prepareStatement(
"SELECT * FROM Clients WHERE Machine LIKE '53'");
//get customer data from database
ResultSet result = ps.executeQuery();
con.close();
List list;
list = new ArrayList();
while (result.next()) {
Customer cust = new Customer();
cust.setMachine(result.getLong("Machine"));
cust.setCompany(result.getString("Company"));
cust.setContact(result.getString("Contact"));
cust.setPhone(result.getLong("Phone"));
cust.setEmail(result.getString("Email"));
//store all data into a List
list.add(cust);
}
return list;
Here the SELECT command does not pull all the numbers in 'Machine' column which is like 53, but if i enter a whole value, such as the complete number (53544) in place of 53 then the result is pulled up. I am confused !!
Also if i replace the above select statement with SELECT * FROM Clients the entire database is stored in list. Any ideas ?
Use wildcards:
Like '%53%'
...means everything that contains '53'.
Like '%53' - it ends with 53
LIKE '53%' - it starts with 53
You can also use _ if You want to replace a single character.
You can find a descriptipn HERE
You sql query should be
"SELECT * FROM Clients WHERE Machine LIKE '%53%'