Python MySql SELECT query formatting

Question:

I am unable to execute the following statement I keep getting SQL syntax errors.
According to all the examples I can find this should work

Any help will be greatly appreciated.

d2 = df.iloc[-1,:]
q = symbol+'_ivol'
 
query = """SELECT close FROM %s WHERE date = %s"""
VALUES= (q, d2[1])

cursor.execute(query, VALUES)
ivol = cursor.fetchall()
conn.close()
Asked By: BTT

||

Answers:

Query parameters in SQL are not just string substitution. You can’t use a query parameter for a table identifier. Parameters can only be used where you would normally use a quoted string literal or numeric literal.

Stated another way, all the identifiers must be fixed in the query string before you prepare it, because identifiers must be validated during the prepare phase, to make sure the table is a valid identifier, and that the table exists. You can’t pass the name of a table identifier after the query has been prepared.

The Python driver unfortunately makes this more confusing because it uses %s instead of MySQL’s own ? symbol for the parameter placeholder. This makes developers naturally think that %s is simply string substitution, like it is for Python string formatting.

So there’s %s and there’s %s, and they are handled differently. I know, it’s confusing.

So you can do a plain string-formatting substitution to put your table into the query string:

query = """SELECT close FROM %s WHERE date = %%s""".format(q)

But it’s more idiomatic for modern Python to use f-string formatting:

query = f"""SELECT close FROM `{q}` WHERE date = %s"""

I put back-ticks around the table name, just in case it’s a SQL reserved keyword or something.

Then the other %s is an actual query parameter, because it works as a scalar value in the SQL expression. In this query, there is just one query parameter.

VALUES= [ d2[1] ]

cursor.execute(query, VALUES)
Answered By: Bill Karwin
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.