Two SELECT Statements NESTED - python

I have been trying to execute the following query, but it doesn't give me any output.
self.db.execute("SELECT * FROM patients WHERE patients.doctorid = (SELECT id FROM doctors WHERE username = '%s' % (usr)), callback=self.add_response)
I tried to execute the same query by hardcoding the values and it gives me the correct output.
select * from patients where patients.doctorid = (select id from doctors where username = 'admin');
Can someone tell whats the error?

Try to execute it like this:
self.db.execute("SELECT * FROM patients WHERE patients.doctorid = (SELECT id FROM doctors WHERE username = '%s')" % (usr), callback=self.add_response)
I closed the SQL query with " and fixed the parentheses.
You can also try as shown here:
self.db.execute("SELECT * FROM patients WHERE patients.doctorid = (SELECT id FROM doctors WHERE username = '%s';", (usr), callback=self.add_response)

Related

How to protect SELECT * FROM var1 WHERE var2 statements from SQLInjection

I am making a website in django where I want the user to put in a table id and group id and then return the table and group that the put in. However, I have only found statements that are prone to SQL injection. Does anybody know how to fix this?
mycursor = mydb.cursor()
qry = "SELECT * from %s WHERE group_id = %i;" % (assembly_name, group_id)
mycursor.execute(qry)
return mycursor.fetchall()
Or do something that achieves the same thing?
I have tried doing something like this:
assembly_id = 'peptides_proteins_000005'
group_id = 5
mycursor = mydb.cursor()
mycursor.execute("SELECT * FROM %s WHERE group_id = %s", [assembly_id, group_id])
myresult = mycursor.fetchall()
but I get this error:
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 ''peptides_proteins_000005' WHERE group_id = 5' at line 1
It's typically not possible to bind table names. For SELECT statements, the easiest way is to sanitize table name candidates by whitelisting.
Check whether the overhead of using abstraction or some way of constraining user input to the finite set of valid names as part of the user interface may be justified.

Executemany SELECT queries with psycopg2

I have a large postgresql DB of users that I connect with using psycopg2. I need to retrieve (SELECT) the information of a specific large subset of users (>200). I am provided with a list of ids and I need to return the age of each of those users. I put down a working solution:
conn = psycopg2.connect("dbname= bla bla bla")
cur = conn.cursor()
for user_id in interesting_users:
qr = "SELECT age FROM users WHERE country_code = {0} AND user_id = {1}".format(1, user_id)
cur.execute(qr)
fetched_row = cur.fetchall()
#parse results
This solution works fine, however it is not ideal when the length of interesting_users is large. I am looking for a more efficient approach than executing multiple queries. One solution would be to create a single query by appending all the user ids:
for user_id in interesting_users:
query += "OR user_id {0}".format(user_id)
But I was hoping for a more elegant solution.
I found that psycopg2 provides the executemany() method. So, I tried to apply to my problem. However, I can't manage to make it work. This:
cur.executemany("SELECT age FROM users WHERE country_code = %s AND user_id = %s",[(1, user_id) for user_id in interesting_users])
r = cur.fetchall()
returns:
r = cur.fetchall()
psycopg2.ProgrammingError: no results to fetch
So, can executemany() be used for a SELECT statement? If yes, what's wrong with my code? If no, how can I perform multiple SELECT queries at once?
Note: ids in interesting_users have no order so I can't use something like WHERE id < ...
SOLUTION:
query = "SELECT age FROM users WHERE country_code = {0} AND user_id IN ({1});".format(1, ",".join(map(str, interesting_users)))
cur.execute(query)
fetched_rows = cur.fetchall()
executemany works only with INSERT, not SELECT. Use IN:
cur.executemany("SELECT age FROM users WHERE country_code = %s AND user_id IN ({})".format(','.join(['%s'] * len(interesting_users)),
[1] + interesting_users)
r = cur.fetchall()

MySQL + python table FETCH module

name=input("input CUSTOMERID to search :")
# Prepare SQL query to view all records of a specific person from
# the SALESPRODUCTS TABLE LINKED WITH SALESPERSON TABLE.
sql = "SELECT * selling_products.customer \
FROM customer \
WHERE customer_products.CUSTOMERID == name"
# Execute the SQL command
cursor.execute(sql)
# Fetch all the rows the sql result of SQL1.
results = cursor.fetchall()
print("\n\n****** TABLE MASTERLIST*********")
print("CUSTOMERID \t PRODUCTID \t DATEOFPURCHASE")
print("**************")
for row in results:
print (row[0],row[1],row[2])
Python would compile the code above, but it will not return any output. Help would be very much appreciated :)
i think you sql should be:
sql = """SELECT * selling_products.customer
FROM customer
WHERE customer_products.CUSTOMERID == {name}""".format(name=name)

Python: Create Sql raw query with In clause with list data

Recently I stuck for a moment while preparing the raw Sql Query having In clause to it and the In clause data is a python list.
Okay Let me put my example here.
Sql Query that I wanted
sql_query = 'SELECT * FROM student WHERE first_name IN ("Dean");'
From the data I was having
data = ["Dean"]
query = 'SELECT * FROM student WHERE first_name IN %s;' % str(tuple(data))
# result was "SELECT * FROM student WHERE first_name IN ('Dean',) "
# see the *Comma* just before close parentheses which is a Sql error
But After doing some practice I came up with a solution of something like this
str_data = ','.join(repr(x) for x in data)
query = 'SELECT * FROM student WHERE first_name IN (%s);' % str_data
# Gives proper result i.e "SELECT * FROM student WHERE first_name IN ('Dean');"
Now my question is, is this a elegant solution or we have several other optimized approaches out there in python. Would be appreciable to have your views on this :).
Edit
Reached to another solution
data = tuple(data) if len(data) > 1 else "('%s')" % data[0] # Assumption: data should not be empty (in my case it is true)
query = 'SELECT * FROM student WHERE first_name IN {};'.format(data)
Note: Still looking for some views from you guys if it can be optimized further.
I used this in python3 on a postgres database, specifically if you want strings
after the IN operator. please pay attention to the double quotes vs single quotes:
data = ['test', 'test2', 'test3']
data_str = "', '".join(data)
query = "SELECT * FROM student WHERE first_name IN ('{}');".format(data_str))
or like this if you prefer f-strings:
print(f"SELECT * FROM student WHERE first_name IN ('{data_str}');")

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)

Categories

Resources