Python MySQLdb placeholders syntax - python

I'd like to use placeholders as seen in this example:
cursor.execute ("""
UPDATE animal SET name = %s
WHERE name = %s
""", ("snake", "turtle"))
Except I'd like to have the query be its own variable as I need to insert a query into multiple databases, as in:
query = """UPDATE animal SET name = %s
WHERE name = %s
""", ("snake", "turtle"))
cursor.execute(query)
cursor2.execute(query)
cursor3.execute(query)
What would be the proper syntax for doing something like this?

query = """UPDATE animal SET name = %s
WHERE name = %s
"""
values = ("snake", "turtle")
cursor.execute(query, values)
cursor2.execute(query, values)
or if you want group them together...
arglist = [query, values]
cursor.execute(*arglist)
cursor2.execute(*arglist)
but it's probably more readable to do it the first way.

Related

use row as variable with python and sql

I am trying to update some values into a database. The user can give the row that should be changed. The input from the user, however is a string. When I try to parse this into the MySQL connector with python it gives an error because of the apostrophes. The code I have so far is:
import mysql.connector
conn = mysql.connector
conn = connector.connect(user=dbUser, password=dbPasswd, host=dbHost, database=dbName)
cursor = conn.cursor()
cursor.execute("""UPDATE Search SET %s = %s WHERE searchID = %s""", ('maxPrice', 300, 10,))
I get this error
mysql.connector.errors.ProgrammingError: 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 ''maxPrice' = 300 WHERE searchID = 10' at line 1
How do I get rid of the apostrophes? Because I think they are causing problems.
As noted, you can't prepare it using a field.
Perhaps the safest way is to allow only those fields that are expected, e.g.
#!/usr/bin/python
import os
import mysql.connector
conn = mysql.connector.connect(user=os.environ.get('USER'),
host='localhost',
database='sandbox',
unix_socket='/var/run/mysqld/mysqld.sock')
cur = conn.cursor(dictionary=True)
query = """SELECT column_name
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'Search'
"""
cur.execute(query)
fields = [x['column_name'] for x in cur.fetchall()]
user_input = ['maxPrice', 300, 10]
if user_input[0] in fields:
cur.execute("""UPDATE Search SET {0} = {1} WHERE id = {1}""".format(user_input[0], '%s'),
tuple(user_input[1:]))
print cur.statement
Prints:
UPDATE Search SET maxPrice = 300 WHERE id = 10
Where:
mysql> show create table Search\G
*************************** 1. row ***************************
Search
CREATE TABLE `Search` (
`id` int(11) DEFAULT NULL,
`maxPrice` float DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
A column name is not a parameter. Put the column name maxPrice directly into your SQL.
cursor.execute("""UPDATE Search SET maxPrice = %s WHERE searchID = %s""", (300, 10))
If you want to use the same code with different column names, you would have to modify the string itself.
sql = "UPDATE Search SET {} = %s WHERE searchID = %s".format('maxPrice')
cursor.execute(sql, (300,10))
But bear in mind that this is not safe from injection the way parameters are, so make sure your column name is not a user-input string or anything like that.
You cannot do it like that. You need to place the column name in the string before you call cursor.execute. Column names cannot be used when transforming variables in cursor.execute.
Something like this would work:
sql = "UPDATE Search SET {} = %s WHERE searchID = %s".format('maxPrice')
cursor.execute(sql, (300, 10,))
You cannot dynamically bind object (e.g., column) names, only values. If that's the logic you're trying to achieve, you'd have to resort to string manipulation/formatting (with all the risks of SQL-injection attacks that come with it). E.g.:
sql = """UPDATE Search SET {} = %s WHERE searchID = %s""".format('maxPrice')
cursor.execute(sql, (300, 10,))

Sqlite unrecognized token: "'''"

I met problems while using sqlite3 in python.
def getEntryId(self, table, field, value, createNew=True):
cur=self.con.execute("select rowid from %s where %s = '%s'" % (table, field, value))
res=cur.fetchone()
if res==None:
cur=self.con.execute("insert into %s (%s) values('%s') " % (table, field, value))
return cur.lastrowid
else:
return res[0]
However, I met this:
OperationalError: unrecognized token: "'''". It seems that my 2nd line of codes is incorrect.
I can not figure out why, so I do the same thing:
cu.execute("select rowid from urllist where %s = '%s'" % ('url', 'yes'))
It came out without an error. Why? How could I fix it?
You should parameterize the query. You cannot though parameterize the table and field names, you can use string formatting to insert the table and field names into the query, but make sure you either trust the source, or validate the values properly:
query = "select rowid from {table} where {field} = %s".format(table=table, field=field)
cur = self.con.execute(query, (value, ))
res = cur.fetchone()
The parameterization not only helps to prevent SQL injection attacks, but also handles the data types conversions, escapes the parameters properly, which may fix your current problem as well.

What is the MySql Update equivalent of this?

What is the MySql UPDATE equivalent of this ?
INSERT INTO items (title, url) VALUES (%s, %s)", (listtitle[0], listlink[0]))
"update items
set title = '{0}',
url = '{1}'
where COLUMN = VALUE
and COLUMN2 = VALUE2".format(listtitle[0], listlink[0])
Replace the words in uppercase with the specific values or otherwise you would update the whole table.
Unknown column in 'field list' error on MySQL Update query
Try this
self.cursor.execute("UPDATE items SET descs ='{0}'".format(item['title'][0]))
instead of this
self.cursor.execute('UPDATE items SET descs =%s' % item['title'][0])
Try this:
"UPDATE items SET title = %s, url= %s" % listtitle[0], listlink[0]

In python, changing MySQL query based on function variables

I'd like to be able to add a restriction to the query if user_id != None ... for example:
"AND user_id = 5"
but I am not sure how to add this into the below function?
Thank you.
def get(id, user_id=None):
query = """SELECT *
FROM USERS
WHERE text LIKE %s AND
id = %s
"""
values = (search_text, id)
results = DB.get(query, values)
This way I can call:
get(5)
get(5,103524234) (contains user_id restriction)
def get(id, user_id=None):
query = """SELECT *
FROM USERS
WHERE text LIKE %s AND
id = %s
"""
values = [search_text, id]
if user_id is not None:
query += ' AND user_id = %s'
values.append(user_id)
results = DB.get(query, values)
As you see, the main difference wrt your original code is the small if block in the middle, which enriches query string and values if needed. I also made values a list, rather than a tuple, so it can be enriched with the more natural append rather than with
values += (user_id,)
which is arguably less readable - however, you can use it if you want to keep values a tuple for some other reasons.
edit: the OP now clarifies in a comment (!) that his original query has an ending LIMIT clause. In this case I would suggest a different approach, such as:
query_pieces = ["""SELECT *
FROM USERS
WHERE text LIKE %s AND
id = %s
""", "LIMIT 5"]
values = [search_text, id]
if user_id is not None:
query_pieces.insert(1, ' AND user_id = %s')
values.append(user_id)
query = ' '.join(query_pieces)
results = DB.get(query, values)
You could do it in other ways, but keeping a list of query pieces in the proper order, enriching it as you go (e.g. by insert), and joining it with some whitespace at the end, is a pretty general and usable approach.
What's wrong with something like:
def get(id, user_id=None):
query = "SELECT * FROM USERS WHERE text LIKE %s"
if user_id != None:
query = query + " AND id = %s"%(user_id)
:
:
That syntax may not be perfect, I haven't done Python for a while - I'm just trying to get the basic idea across. This defaults to the None case and only adds the extra restriction if you give a real user ID.
You could build the SQL query using a list of conditions:
def get(id, user_id=None):
query = """SELECT *
FROM USERS
WHERE
"""
values = [search_text, id]
conditions=[
'text LIKE %s',
'id = %s']
if user_id is not None:
conditions.append('user_id = %s')
values.append(user_id)
query+=' AND '.join(conditions)+' LIMIT 1'
results = DB.get(query, values)

How can I format strings to query with mysqldb in Python?

How do I do this correctly:
I want to do a query like this:
query = """SELECT * FROM sometable
order by %s %s
limit %s, %s;"""
conn = app_globals.pool.connection()
cur = conn.cursor()
cur.execute(query, (sortname, sortorder, limit1, limit2) )
results = cur.fetchall()
All works fine but the order by %s %s is not putting the strings in correctly. It is putting the two substitutions in with quotes around them.
So it ends up like:
ORDER BY 'somecol' 'DESC'
Which is wrong should be:
ORDER BY somecol DESC
Any help greatly appreciated!
paramstyle
Parameter placeholders can only be used to insert column values. They can not be used for other parts of SQL, such as table names, statements, etc.
%s placeholders inside query string are reserved for parameters. %s in 'order by %s %s' are not parameters. You should make query string in 2 steps:
query = """SELECT * FROM sometable order by %s %s limit %%s, %%s;"""
query = query % ('somecol', 'DESC')
conn = app_globals.pool.connection()
cur = conn.cursor()
cur.execute(query, (limit1, limit2) )
results = cur.fetchall()
DO NOT FORGET to filter first substitution to prevent SQL-injection possibilities
Not all parts of an SQL query can be parametrized. The DESC keyword for example is not
a parameter. Try
query = """SELECT * FROM sometable
order by %s """ + sortorder + """
limit %s, %s"""
cur.execute(query, (sortname, limit1, limit2) )
You could try this alternatively...
query = """SELECT * FROM sometable
order by {0} {1}
limit {2}, {3};"""
sortname = 'somecol'
sortorder = 'DESC'
limit1 = 'limit1'
limit2 = 'limit2'
print(query.format(sortname, sortorder, limit1, limit2))

Categories

Resources