Python Model:
class SYSLocation(SYSModel):
__tablename__ = 'sys_location'
rank = db.Column(db.Integer)
Call:
db.session.add(model)
It generate mysql script:
INSERT INTO `sys_location` ( rank) VALUES (13000)
sql error :
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 'rank)
VALUES (13000)' at line 1
I check this query run error mysql version 8.0.11 because rank is keyword.
But this sql can run mysql version 10.1.25-MariaDB.
How to fix my Sqlalchemy model run all version of mysql?
As always, when dealing with reserved keywords wrap it in backticks like you did for sys_location:
INSERT INTO `sys_location` (`rank`) VALUES (13000)
You can escape everything if you want, but it's often not necessary. Keywords are a case where it might be necessary because these keywords do change, if infrequently.
Related
I'm using Python + MySQL and want to use parameterized query. I'm stuck. I've encountered an error and can't figure out how to solve it. I've spent a day, checked dozens of articles, used various options (sinle quotes, double quotes, prepared statements) and still no luck.
Requirements: use Parameterized Query
Here is basic demo of the issue:
#!/usr/bin/python3
import mysql.connector as mysql
conn = mysql.connect(host=server, user=username, passwd=password, autocommit=True)
try:
create_database_query = "CREATE DATABASE %s;"
db_name = "BOOKS"
cursor = conn.cursor()
print(f"Creating {db_name} database... ", end='')
cursor.execute(create_database_query, (db_name,))
print("Success")
except mysql.Error as error:
print("Parameterized query failed {}".format(error))
Output:
Creating BOOKS database... Parameterized query failed 1064 (42000): 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 ''BOOKS'' at line 1
So it looks like it uses too many quotes (2 single quotes on each side). The code above works fine if I change the following line:
create_database_query = "CREATE DATABASE %s;"
and put backtick around %s
The problem that now it creates a database but with invalid chars - 'BOOKS' (quotes are now part of db name). Duh...
If I use prepared statements then the same issue occurs but slightly different error message:
1064 (42000): 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 '?' at line 1
Environment:
MacOS Catalina
Python 3.8
PyCharm 2019.3 IDE
MySQL 8.0.19
mysql-connector-python module 8.0.19
What is going on? Any ideas?
Thanks
You can't use query parameters for identifiers (like a database name or table name or column name).
Query parameters can be used only in place of a constant value — a quoted string, quoted date/time, or a numeric value. Not identifiers, expressions, SQL keywords, etc.
To combine a database name with your CREATE DATABASE statement, you have to format it into the string in a way that forms the full statement before it is sent to MySQL.
db_name = "BOOKS"
create_database_query = "CREATE DATABASE %s;" % db_name
cursor.execute(create_database_query)
Because this creates a risk of SQL injection when you format variables into your string, it's up to you to make sure the db_name is safe.
Update: Thanks to #Parfait for the reminder about current best practices of string-formatting.
Prefer:
db_name = "BOOKS"
create_database_query = "CREATE DATABASE {};".format(db_name)
Or F-strings:
db_name = "BOOKS"
create_database_query = f"CREATE DATABASE {db_name};"
(In other words, Python has become Ruby ;-)
I am new in using python API to send a query to mysql.
My issue is very easy to reproduce. I have a table named "ingredient" and I would like to select the rows from python using parameters
If I do cursor.execute("select * from ?",('ingredient',)) I get the error message : Error while connecting to MySQL Not all parameters were used in the SQL statement MySQL connection is closed
I I do cursor.execute("select * from ?",'ingredient') I get the error message : Error while connecting to MySQL 1064 (42000): 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 '?' at line 1
Same issues using %s instead of ?. Using the other type of single quote on 'ingredient' instead of 'ingredient' does not give results either.
How is this supposed to work here ?
You just can't pass a table name as parameter to a query. The parameterization mechanism is there to pass literal values, not object names. Keep in mind that the database must be able to prepare the query plan from just the parameterized string (without the actual parameter value), which disqualifies using metadata as parameter.
You need string concatenation instead:
cursor.execute("select * from " + yourvar);
Note that, if the variable comes from outside your program, using such contruct exposes your code to SQL injection. You need to manually validate the value of the parameter before execting the query (for example by checking it against a fixed list of allowed values, or by querying the information schema of the database to ensure that the table does exist).
Does your query work if you just write:
cursor.execute("SELECT * FROM ingredient")
?
I have tried everything and keep getting this error:
pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax;
check the manual that corresponds to your MariaDB server version for the right syntax to use near
'INSERT INTO tabSingles (doctype, field, value) VALUES ('Bank Reconciliation', 'a' at line 2")
Expanded query (after python format expansion):
SELECT value INTO #var FROM tabSingles WHERE doctype = 'Bank Reconciliation' AND field = 'bank_account';
INSERT INTO tabSingles (doctype, field, value) VALUES ('Bank Reconciliation', 'account', #var);
DELETE FROM tabSingles WHERE doctype = 'Bank Reconciliation' AND field = 'bank_account';
Can anyone see the problem? Is there some issue with multi-line queries? I have tried the individual lines on the mariadb command line and they appear to work as expected. I've also tried both frappe.db.sql and multisql (thought it meant multiline sql but doesn't). If I comment line 2 out, it also errors on line 3. Sorry to disturb but I've been staring at this for hours and cannot figure it out!
EDIT:
The obvious answer is this, but I'd still like to know why it doesn't like the original query:
UPDATE tabSingles SET field='{new_name}' WHERE doctype='{doctype}' AND field='{old_name}';
For security reasons (mainly SQL injection) MariaDB (and MySQL) servers don't support the execution of multiple SQL statements by default.
For supporting multiple statements execution the client needs to send COM_SET_OPTION command and MYSQL_OPTION_MULTI_STATEMENTS_ON flag to the server, which is not supported by PyMySQL.
Do not try to run more than one statement in a call.
Do use BEGIN and COMMIT.
Do use FOR UPDATE.
You need 5 separate commands:
BEGIN;
SELECT ... FOR UPDATE; -- to keep other connections from messing with the row(s).
UPDATE ...;
DELETE ...
COMMIT; -- do all of the above "atomically"
I am using flask-sqlalchemy to perform a ranking query on a PlayerKillData table, which has 4 columns: ref_id (Primary Key), kill, all_kill and lvl. Specifically, what I want to achieve is to Rank by kill for player on the same lvl and add a Rank column
#Columns define in Create Table SQL statement and resolved by reflection at runtime
class PlayerKillData(db.Model):
__tablename__ = "player_kill_data"
The following python snippet is that I have tried but no matter how I have tried, it always return sqlite3.OperationalError:
subquery = excDB.db.session.query(
PlayerKillData,
excDB.db.func.rank().over(
order_by = PlayerKillData.kill.desc(),
partition_by = PlayerKillData.lvl).label('RANK')
)
subquery.all()
The SQL statement printed by the error message is:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) near "(": syntax error
[SQL: SELECT player_kill_data.ref_id AS player_kill_data_ref_id, player_kill_data.kill AS player_kill_data_kill, player_kill_data.all_kill AS player_kill_data_all_kill, player_kill_data.lvl AS player_kill_data_lvl, rank() OVER (PARTITION BY player_kill_data.lvl ORDER BY player_kill_data.kill DESC) AS "RANK"
FROM player_kill_data]
I have also tried running the SQL statement directly using Db Browser for SQLite and it returned the table successfully without any error.
I am really puzzled by this and would like any help I can get to solve this.
Your version of SQLite might be smaller than 3.25.0.
As mentionned here and confirmed in the Release History of SQLite, SQLite supports window function (RANK() OVER ...) since version 3.25.0, which was released on 2018-09-15.
To check your version of SQLite in python:
import sqlite3
print(sqlite3.sqlite_version)
# returns '3.22.0' for me
If many people work on the same codebase and you'd like to have a more explicit error message for other developers, you can assert:
assert sqlite3.sqlite_version_info >= (3,25,0), """sqlite3 version must be >= 3.25.0 because that's when it started to support window functions"""
I am attempting to write a SQL in python using PYMYSQL, which searches a table for a certain record with a set value, however while this sounds simple I cannot seem to do it below is my query:
SELECT Series_ID FROM series_information WHERE Series_Name "'+data +'"'
where the data is the value that I am searching for however the following error occurs:
pymysql.err.ProgrammingError: (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 \'"Spice And Wolf"\' at line 1')
The problem I believe is that I am not sure how to properly escape the data value if it has spaces in it and therefore would require quotation marks in the SQL query.
You're missing a comparison (like, =, etc) between Series_Name and data, as well as a ';' on the end of the query.
`'SELECT Series_ID FROM series_information WHERE Series_Name = "'+data +'";'
`SELECT Series_ID FROM series_information WHERE Series_Name "'+data +'"'`
Is not a valid SQL query did you mean:
`'SELECT Series_ID FROM series_information WHERE Series_Name like "'+data +'"'`