When I try to pass a tuple to the IN argument of a WHERE clause, it gets double-quoted so my query fails. For example, if I do this,
# Connect to DB
import MySQLdb
cnxn = MySQLdb.connect(connectString)
curs = cnxn.cursor()
# Setup query
accounts = ('Hyvaco','TLC')
truck_type = 'fullsize'
query_args = (truck_type, accounts)
sql ='SELECT * FROM archive.incoming WHERE LastCapacity=%s AND Account IN %s'
# Run query and print
curs.execute(sql, query_args)
print(curs._executed)
then I get zero rows back, and the query prints out as
SELECT * FROM archive.incoming WHERE LastCapacity='fullsize'
AND Account IN ("'Hyvaco'", "'TLC'")
Switching accounts from a tuple to a list does not affect the result. How should I be passing these arguments?
How about you create the accounts as a string and then do this:
accounts = "('Hyvaco','TLC')"
sql ='SELECT * FROM archive.incoming WHERE LastCapacity=%s AND Account IN '+ accounts
Related
I'm aware that the best way to prevent sql injection is to write Python queries of this form (or similar):
query = 'SELECT %s %s from TABLE'
fields = ['ID', 'NAME']
cur.execute(query, fields)
The above will work for a single query, but what if we want to do a UNION of 2 SQL commands? I've set this up via sqlite3 for sake of repeatability, though technically I'm using pymysql. Looks as follows:
import sqlite3
conn = sqlite3.connect('dummy.db')
cur = conn.cursor()
query = 'CREATE TABLE DUMMY(ID int AUTO INCREMENT, VALUE varchar(255))'
query2 = 'CREATE TABLE DUMMy2(ID int AUTO INCREMENT, VALUE varchar(255)'
try:
cur.execute(query)
cur.execute(query2)
except:
print('Already made table!')
tnames = ['DUMMY1', 'DUMMY2']
sqlcmds = []
for i in range(0,2):
query = 'SELECT %s FROM {}'.format(tnames[i])
sqlcmds.append(query)
fields = ['VALUE', 'VALUE']
sqlcmd = ' UNION '.join(sqlcmds)
cur.execute(sqlcmd, valid_fields)
When I run this, I get a sqlite Operational Error:
sqlite3.OperationalError: near "%": syntax error
I've validated the query prints as expected with this output:
INSERT INTO DUMMY VALUES(%s) UNION INSERT INTO DUMMY VALUES(%s)
All looks good there. What is the issue with the string substitutions here? I can confirm that running a query with direct string substitution works fine. I've tried it with both selects and inserts.
EDIT: I'm aware there are multiple ways to do this with executemany and a few other. I need to do this with UNION for the purposes I'm using this for because this is a very, very simplified example fo the operational code I'm using
The code below executes few INSERTS at once
import sqlite3
conn = sqlite3.connect('dummy.db')
cur = conn.cursor()
query = 'CREATE TABLE DUMMY(ID int AUTO INCREMENT NOT NULL, VALUE varchar(255))'
try:
cur.execute(query)
except:
print('Already made table!')
valid_fields = [('ya dummy',), ('stupid test example',)]
cur.executemany('INSERT INTO DUMMY (VALUE) VALUES (?)',valid_fields)
engine = sqlalchemy.engine.create_engine('mysql://py:123#localhost/py', echo=True)
con = engine.connect()
res = con.execute("insert into user set name = %s", 'A')
How do I write this query to a (.sql) file (or how do I assign it to a variable)?
I'd rather not do all the escaping myself.
You can use literal_binds to produce an SQL statement with the values embedded:
import sqlalchemy as sa
# …
user = sa.Table("user", sa.MetaData(), autoload_with=engine)
user_insert = sa.insert(user).values(name="A")
compiled_text = str(
user_insert.compile(compile_kwargs={"literal_binds": True})
)
print(compiled_text)
# INSERT INTO "user" (name) VALUES ('A')
However, be careful about using that with untrusted inputs as there is still the possibility of SQL injection issues.
I am trying to write python script which calls mysql SQL.
I am relying on first query result to run second query. Problem is that it's throwing error.
Error : cursor2.execute(field_sql,id)
import boto3
import importlib
import psutil
import pymysql
import pymysql.cursors
import subprocess
import sys
rdsConn = pymysql.connect(host = 'XXXX'),
db = 'XXXX',
user = 'XXXX',
password = 'XXXX',
charset = 'utf8mb4',
cursorclass=pymysql.cursors.DictCursor)
cursor1 = rdsConn.cursor()
cursor2 = rdsConn.cursor()
name = 'Test'
sql = "select id from Table1 where name = %s"
cursor1.execute(sql,name)
result = cursor1.fetchall()
for id in result:
field_sql= "select columnname from Table2 where id = %s"
cursor2.execute(field_sql,id)
fieldresult = cursor2.fetchall()
for fieldrow in fieldresult:
print(fieldrow)
cursor1.close()
cursor2.close()
rdsConn.close()
Your query uses a dict cursor, so it will return a list of dicts, e.g:
[{'id': 1}, {'id': '2'}, ...]
Which means your id* will be a dict, not a tuple as it would be otherwise. Which means you're passing your arguments to the second query as a dict. If you do so, you need to use named parameters using the pyformat style:
for rowdict in result:
field_sql = "select columnname from Table2 where id = %(id)s"
cursor2.execute(field_sql, rowdict)
fieldresult = cursor2.fetchall()
for fieldrow in fieldresult:
print(fieldrow)
You'll see that the printed fieldrows are also dicts.
Also, query parameters should be passed either as dict (named parameters) or as tuple (positional parameters). pymysql accepts the form cursor.execute(sql, "name"), other dbapi2 connectors don't. The canonical form would be cursor.execute(sql, ("name",)).
*btw, you shouldn't use id as name, it hides the builtin id function
I have an existing access query for example called *RunExampleQuery:
select name from table_x where date = [start];
But I can't seem to find the sql code that will run this query i.e
sql = """SELECT * FROM *RunExampleQuery WHERE [start] = ?"""
params = (datetime.date(2016,11,25))
cursor.execute(sql,params)
Thanks for your help in advance.
Couple of items are the issue:
[start] field must exist in RunExampleQuery in order to use it in WHERE clause
To bind parameters to prepared SQL statements, you must pass values in tuple or list. This requires converting scalar strings to these type:
RunExampleQuery
select name, [start] from table_x;
Tuple Parameterization
sql = """SELECT * FROM [RunExampleQuery] WHERE [start] = ?"""
params = datetime.date(2016,11,25)
cursor.execute(sql, (params,))
List Parameterization
sql = """SELECT * FROM [RunExampleQuery] WHERE [start] = ?"""
params = datetime.date(2016,11,25)
cursor.execute(sql, [params])
I am trying to query the records for a specific ID in an Oracle table based on what the user inputs.
Here is my code:
import cx_Oracle
con = cx_Oracle.connect('dbuser/dbpassword#oracle_host/service_ID')
cur = con.cursor()
id_number = raw_input('What is the ID Number?')
cur.execute('select id, info from oracle_table_name where id=:id_number')
for result in cur:
print "test", result
cur.close()
con.close()
The following error pops up: cx_Oracle.DatabaseError: ORA-01008: not all variables bound
When I remove the user input and the variable substitution and run the query, everything works fine.
:id_number in your SQL is a parameter (variable). You need to provide its value.
execute method accepts parameters as the second argument.
Example:
query = "select * from some_table where col=:my_param"
cursor.execute(query, {'my_param': 5})
Check the documentation at http://cx-oracle.readthedocs.org/en/latest/cursor.html#Cursor.execute
I assigned a name to the user_value:
user_value = raw_input('What is the ID Number?')
And then referenced it in the execute statement:
cur.execute(query, {'id': (user_value)})
Thanks to Radoslaw-Roszkowiak for the assist!!