Query runs fine in MySQL, but returns empty list in Python

In summary, the issue of a query running fine in MySQL but returning an empty list in Python often stems from discrepancies between the database configuration and the Python environment. Common causes include differences in data types, case sensitivity, or connection settings. It's essential to ensure that the query is executed correctly in Python, check for any filtering conditions, and verify that the data being queried exists in the database. Debugging steps include printing the executed query, checking the database connection, and examining the returned results.
  • #1
Wrichik Basu
Science Advisor
Insights Author
Gold Member
2,161
2,719
I have a database that looks like this:

1709852202892.png


I want to get the "leaderboard position" of a particular member. The idea is to order the data by the score column, and then retrieve the row position of that particular member id. This is my query in MySQL:
MySQL:
SET @rowNum := 0;
SELECT rowNum
FROM(
  SELECT (@rowNum := @rowNum + 1) AS rowNum, member_id
  FROM members
  ORDER BY score DESC) tmp
WHERE member_id = 288745911563241;

This works as I want in MySQL, returning the appropriate row number:
1709852458956.png


But, when I try to do the same via mysql.connector in Python 3.12, I get an empty list. This is my code in Python:
Python:
import mysql.connector

mydb = mysql.connector.connect(host="localhost", user="user_name",
                               password="pwd", database="db_name")
mycursor = mydb.cursor()


def main():
    mycursor.execute("SET @rowNum := 0; "
                     "SELECT rowNum FROM( "
                     "SELECT (@rowNum := @rowNum + 1) AS rowNum, member_id "
                     "FROM members "
                     "ORDER BY score DESC) tmp "
                     "WHERE member_id = 288745911563241;")
    print(mycursor.fetchall())
    mycursor.close()
    mydb.close()


if __name__ == '__main__':
    main()

Any idea why I am facing this?

In case anyone wants to test, this is the code for the dummy database:
SQL:
CREATE DATABASE db_name;

USE db_name;

CREATE TABLE members (
    member_id BIGINT PRIMARY KEY NOT NULL,
    score BIGINT NOT NULL,
    correct BIGINT NOT NULL,
    wrong BIGINT NOT NULL,
    highest_valid_count BIGINT NOT NULL
);

INSERT INTO members VALUES
    (115366974582, 5, 12, 7, 20),
    (588412336974, 25, 78, 53, 105),
    (144865512587, 2, 98, 96, 50),
    (255418963314, 31, 51, 20, 65),
    (5221479632215, 12, 25, 13, 52),
    (25596418873641, 23, 81, 58, 31),
    (75532184413259, 41, 51, 10, 96),
    (288745911563241, 9, 23, 14, 10);
 
Technology news on Phys.org
  • #3
Could be all sorts of reasons why it doesn't work, but a robust (and probably more efficient) way to do this is to use two queries, one to get the member's score and another to COUNT the number of rows with a higher (or higher-or-equal) score.
 
  • Love
Likes Wrichik Basu
  • #4
jedishrfu said:
My first thought can execute() function process multiple sql statements?
I tried splitting into two execute() statements, but it was not working. Now I tried it again and it is working. Programming can be spooky at times!
pbuk said:
a robust (and probably more efficient) way to do this is to use two queries, one to get the member's score and another to COUNT the number of rows with a higher (or higher-or-equal) score.
Indeed, that's the best approach. Selecting less data means lesser memory overhead, especially for a bot that's supposed to be online all the time. Thanks a lot!
 
  • #5
I'm not a python expert but don't you need an iterator to process the result as in:

Code:
iterator = cursor.execute(operation, params=None, multi=True)


See:

Code:
operation = 'SELECT 1; INSERT INTO t1 VALUES (); SELECT 2'
for result in cursor.execute(operation, multi=True): 
if result.with_rows:   
    print("Rows produced by statement '{}':". format(result.statement))   
    print(result.fetchall()) 
else:   
    print("Number of rows affected by statement '{}': {}".format(result.statement, result.rowcount))

https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html

?

This would probably be a statement handle in ODBC.

Regards.
 
  • #6
Wrichik Basu said:
I have a database that looks like this:

View attachment 341440

I want to get the "leaderboard position" of a particular member. The idea is to order the data by the score column, and then retrieve the row position of that particular member id.

How do you resolve ties? The RANK() or DENSE_RANK() window functions will resolve ties for you (see here), but you will have to rank all the scores before querying results for individual members. If you need to do that multiple times, then it makes sense to do the calculation once in a temporary table and then query that.

Code:
DROP TEMPORARY TABLE IF EXISTS ranked_by_score;
CREATE TEMPORARY TABLE ranked_by_score AS
SELECT 
member_id,
score,
RANK() OVER w AS 'rank',
DENSE_RANK() OVER w AS 'dense rank',
ROW_NUMBER() OVER w AS 'row_number' 
FROM members 
WINDOW w AS (ORDER BY score DESC);
 
  • #7
My advice here is for you to abstract this into a higher-level representation of your data (using an ORM or even a query builder). My recommendation here is https://www.sqlalchemy.org/

This will be the first of many if you don't migrate your code to a more maintainable and repeatable structure
 
  • #8
As other's have suggested, by default, executor does not handle multiple statements. The mysql docs: https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html show that there is a multi=True parameter that you can pass into it, but it's also just as easy to just split them into two execute statements:


Python:
import mysql.connector

mydb = mysql.connector.connect(host="localhost", user="user_name",
                               password="pwd", database="db_name")
mycursor = mydb.cursor()

def main():
    mycursor.execute("SET @rowNum := 0;")
   
    mycursor.execute("SELECT rowNum FROM( "
                     "SELECT (@rowNum := @rowNum + 1) AS rowNum, member_id "
                     "FROM members "
                     "ORDER BY score DESC) tmp "
                     "WHERE member_id = 288745911563241;")
   
    print(mycursor.fetchall())
   
    mycursor.close()
    mydb.close()

if __name__ == '__main__':
    main()

Honestly, from a code readability perspective, I like this more, anyway.
 

FAQ: Query runs fine in MySQL, but returns empty list in Python

1. Why does my SQL query return results in MySQL but not in Python?

This discrepancy often occurs due to differences in how the database connection is established or how the results are fetched in Python. Ensure that you are using the correct connection parameters and that the query is being executed properly in your Python code.

2. How can I check if the query is being executed correctly in Python?

You can check for errors in your query execution by adding error handling in your Python code. Use try-except blocks to catch exceptions and print out any error messages. Additionally, you can print the SQL query before execution to confirm it is formatted correctly.

3. Are there any differences in how data types are handled between MySQL and Python?

Yes, there can be differences in data types between MySQL and Python. For example, MySQL may return NULL values that need to be handled in Python as None. Ensure that you are correctly interpreting the data types returned by your query in your Python code.

4. What should I do if the connection to the database is not established correctly?

Check your database connection parameters such as host, user, password, and database name. Make sure that your database server is running and accessible from your Python environment. You can also test the connection using a simple query to see if it succeeds.

5. How can I debug the empty result set in Python?

To debug an empty result set, first verify that the query returns results directly in MySQL. Then, log the executed query and any parameters used. You can also print the length of the result set after fetching the data in Python to confirm whether it is indeed empty or if there was an issue with fetching the data.

Back
Top