compose mysql query in python - python

I want to fetch all rows from MySQL table with
query = "SELECT * FROM %s WHERE last_name=%s"
cursor.execute(query, ("employees","Smith"))
but I'm getting
You have an error in your SQL syntax. When I try
query = "SELECT * FROM employees WHERE last_name=%s"
cursor.execute(query, ("Smith",))
all is fine.
Documentation says
cursor.execute(operation, params=None, multi=False)
The parameters found in the tuple or dictionary params are bound to the variables in the operation.link on docs

The first will generate an SQL like this:
SELECT * FROM 'employees' WHERE last_name='smith'
The parameters are SQL quoted.
If you really need to have a table name as param, you must proceed in 2 steps:
table_name = 'employees'
query_tpl = "SELECT * FROM {} WHERE last_name=%s"
query = query_tpl.format(table_name)
cursor.execute(query, ("Smith",))

you need to add the quote symbol. So the query will be like
SELECT * FROM employees WHERE last_name='Smith'
Change both your query to
query = "SELECT * FROM %s WHERE last_name='%s'"
query = "SELECT * FROM employees WHERE last_name='%s'"

You can't use a parameter for the table name in the execute call.
But you can use Python string interpolation for that:
query = "SELECT * FROM %s WHERE last_name=%s" %("employees","Smith")
cursor.execute(query)

You can't use a table name as a parameter. you are generating invalid sql with your code that is putting quotes around each string. the table name cannot have quotes around it.
sql you are generating
select * from 'employees' where last_name = 'Smith'
What sql you want
select * from employees where last_name = 'Smith'
you would have to format the string first like the example below.
query = "SELECT * from {} wherre last_name ='{}'"
cursor.execute(query.format("employees","Smith"))
using code like this does open up the possibility of SQL injection. so please bear that in mind.

query="SELECT * FROM %s WHERE name=%s",(employees,smith)
cursor.execute(query)
rows = cursor.fetchall()
Try this one. Hopefully it works for you.

Related

How to format a formatted string in Python? Either with .format or f-string

I have a string (sql query) in which I want to pass a variable at one point, then pass another variable at another point (list of variables, but just focusing on one for now).
The expected would be something like this:
sql_query = 'SELECT {{field}} FROM {table} WHERE {{field}} IS NULL'.format(table=table_name)
sql_query should now be: 'SELECT {field} FROM table_name WHERE {field} IS NULL'
Then format for field
sql_query = sql_query.format(field_name)
In theory I want sql_query to now be: 'SELECT field_name FROM table_name WHERE field_name IS NULL'
But the above ignores the .format and I get: 'SELECT {field} FROM table_name WHERE {field} IS NULL'
I have tried combining f-strings and .format in multiple ways and the closest to my goal is:
field = field_name
sql_query = f'SELECT {field} FROM {{0}} WHERE {field} IS NULL'.format(table_name)
# Works and I get sql_query : 'SELECT field_name FROM table_name WHERE field_name IS NULL'
The above works but it happens all in the same place and separating where each one happens is the true goal of mine.
sql = "SELECT {{column}} FROM {table}"
sql = sql.format(table="my_table")
print(sql)
sql = sql.format(column="my_column")
print(sql)
Or...
sql = "SELECT {column} FROM {table}"
sql = sql.format(table="my_table", column="{column}")
print(sql)
sql = sql.format(column="my_column")
print(sql)
That said, I'd recommend not actually passing the string around and doing partial replacements on it.
Instead, pass a dictionary around, add the replacements to the dictionary, and call format just once...
Then you don't need to add arbitrary {} around the token you don't want to replace, or be aware that it exists in order to replace it with itself.
sql = "SELECT {column} FROM {table}"
parts = dict()
parts["table"] = "my_table"
# more code here
parts["column"] = "my_column"
print(sql.format(**parts))
NOTE:
As per other warnings here...
NEVER do this with user supplied text.
Literal values should be supplied using parameterisation / prepared statements.
Only ever do this when you are in complete control of the potential values in the dictionary, such as deriving the columns, etc, from ORM meta-data, or some other white list.

Passing variables into a MySQL query using python

I have a database with some records that have a date field of "05221999". I am trying to do a SQL query from the input of the user based on just the month and year. In this case I am interested in all the records with the month of 05 and the year of 1999.
Unfortunately, I can't get the Python/SQL syntax correct. Here is my code so far:
def submitact(self):
date = self.md.get()
month = date[0:2]
year = date[2:7]
db = pymysql.connect("localhost", "username", "password", "database")
cursor = db.cursor()
cursor.execute("SELECT * FROM `table` WHERE `Code` = 'RM' AND `Date` LIKE %s'_'%s", (month, year))
results = cursor.fetchall()
print(results)
cursor.close()
db.close()
I've done several variations on the SELECT statement and they either return errors or nothing.
Thanks!
In the code snippet below, I used f-string style to format the query string
[...]
query = f"SELECT * FROM `table` WHERE `Code` = 'RM' AND LEFT(`Date`, 2) = '{month}' AND RIGHT(`Date`, 4) = '{year}'"
cursor.execute(query)
[...]
try with this:
query = "SELECT * 'table' WHERE 'Code' = 'RM' AND 'Date' LIKE '%{0}_{1}'".format(month, year)
cursor.execute(query)
In this way, 'query' variable value will be:
"SELECT * FROM 'table' WHERE 'Code' = 'RM' AND 'Date' LIKE '%05_1999'"
For more information about string formatting, let's have a look to Python String Formatting Best Practices - Real Python

Pass a python variable into an SQL query

I am working on Databricks and I am trying to pass a python variable into a SQL query:
series_name "LogTest"
query = """SELECT * FROM results_table
WHERE name = $series_name
"""
spark.sql(query).toPandas()
I tried with $ but it does not work.
How do I do this?
Regards
In this case, your variable and queries are just strings. You can do:
query = f"""SELECT * FROM results_table
WHERE name = '{series_name}'
"""
... in python 3. Remember that your query string needs the single quotes around the inserted variable. However, for certain variables, you may need to pass the variable directly to the spark module so it can interpret it. I use pyodbc a lot and would do this:
query = f"""SELECT * FROM results_table
WHERE name = ?"""
cursor.execute(query, series_name)
Following will also work,
series_name = "LogTest"
spark.sql("SELECT * FROM results_table WHERE name = " + series_name).toPandas()
we can also try the following.
series_name = "LogTest"
query = "SELECT * FROM results_table WHERE name = {}".format(series_name)
spark.sql(query).toPandas() #

Psycopg2 query remove \n from args

Im using python3 and postgres 11.5.
This is the script :
a = cursor.execute("SELECT tablename FROM pg_catalog.pg_tables limit 5")
for table in a:
cursor.execute("SELECT * FROM pg_prewarm(public.%s)", [table[0]])
a query gets some table names , and the loop query should run table name as the %s.
but for some reason i get the arg table[0] with // /n in the query and its messing it up.
if i print a results i get table names as tuple:
[('sa1591354519',), ('sa1591397719',), ('sa1591397719',)]
so [table[0]] is a string.
the error i get:
1574683839 [16177], ERR, execute ({'Error while connecting to PostgreSQL': SyntaxError('syntax error at or near "\'sa1591440919\'"\nLINE 1: SELECT * FROM pg_prewarm(public.\'sa1591440919\')\n ^\n')},)
what can i do ?
The errors don't have anything to do with the newlines you see, which are just an artifact of the error message. If you were to print out the error, would see:
syntax error at or near "'sa1591440919'"
LINE 1: SELECT * FROM pg_prewarm(public.'sa1591440919')
^
In other words, Postgres doesn't like the table name you're passing because it contains quotes. This is happening because you're trying to treat the table names like a normal query parameter, which causes psycopg to quote them...but that's not what you want in this case.
Just replace your use of query templating with normal Python string substitution:
a = cursor.execute("SELECT tablename FROM pg_catalog.pg_tables limit 5")
for table in a:
cursor.execute("SELECT * FROM pg_prewarm(public.%s)" % (table[0]))
But this won't actually work, because cursor.execute doesn't return a value, so a will be None. You would need to do something like:
cursor.execute("SELECT tablename FROM pg_catalog.pg_tables limit 5")
a = cursor.fetchall()
for table in a:
...

Python/pg8000 WHERE IN statement

What is the correct method to have the tuple (names) be available via %s in the SQL statement?
names = ('David', 'Isaac')
sql = 'SELECT * from names WHERE name IN %s'
cur.execute(sql,(names,))
The response in https://stackoverflow.com/a/28117658/5879128 works for psycopg2 but does not work in pg8000.
Thanks!
Generate the proper number of placeholders. In pg8000 the placeholder defaults to %s.
Interpolate placeholders to the query string.
Execute SQL-injection-safe query.
Like so:
sql = 'SELECT * from names WHERE name IN ({})'.format( ','.join(['%s']*len(names)) )
# results in -> 'SELECT * from names WHERE name IN (%s,%s)'
cur.execute(sql,(names,))

Categories