Pass multiple user inputs from python into SQL query - python

I am working on a project that asks me to prompt the user to enter some ids in order to retrieve relevant data from database using SQL developer.
I knew how to just take one piece of user input and put it into one SQL query but struggle to tackle multiple user inputs.
For example, I can prompt the user to enter share_id for me to search for corresponding trade like this:
connection = cx_Oracle.connect("hr", "oracle", "localhost/orcl")
cursor = connection.cursor()
share_id_val = input("Enter share id to search: ")
cursor.execute("SELECT * FROM trades WHERE share_id = :share_id", share_id = share_id_val)
But if the user may enter one or more of [share_id, broker_id, date_range], then I can only think of building 6 SQL queries, one for each case (that's very inefficient for sure).
Specifically, I don't know how to construct the SQL query inside the cursor.execute to account for different scenarios (the user may just want to retrieve trade information by share_id, or by both broker_id and date_range).
PS: date range should include from_date and to_date of transaction_time.
Any help will be appreciated.

You need to use the inputs provided by user with a case statement with an escape clause (else part of case here) corresponding to the no input situation. This way you can handle more than one inputs independently. In this case, no input is mapped to input variable being null (not a default non-null value). You should be able to extend this to include date range inputs also.
Try
share_id_val = input("Enter share id to search: ")
broker_id_val = input("Enter broker id to search: ")
cursor.execute("
SELECT * FROM trades WHERE 1=1
and share_id = case when :share_id_bind_var is not null then :share_id_bind_var else share_id end
and broker_id = case when :broker_id_bind_var is not null then :broker_id_bind_var else broker_id end
",
share_id_bind_var = share_id_val,
broker_id_bind_var = broker_id_val
)

Related

Multiple SQL Queries with python & flask

I have a SQLite3 table that collects data from a gym booking form; all the data goes into one table - Name, Email, Day, Exercise Class, Class Time.
If it is possible, I would like to find a way to get all from Name if Day, Exercise Class & Class Time are equal to a selected value.
I am using Flask so once I can do this the data would then be used to generate a new HTML page (which would be the registration checklist page for the gym tutor).
I am pretty sure this is incorrect, but this is the general idea of what I would like to achieve..
db.execute("SELECT * FROM GymTable WHERE (Day == "Monday", Ex_Class == "BoxFit", Ex_Time == "0745-0845"))
the correct query in this case would be:
db.execute("SELECT * FROM GymTable WHERE Day = 'Monday' and Ex_Class = 'BoxFit' and Ex_Time = '0745-0845'")
You may find these two tutorials on the SQL WHERE clause and SQL AND, OR, NOT Operators helpful. Notice first that the equal operator is = instead of ==. This query needs AND between column filters. The WHERE clause should not be enclosed in (). You may find the python sqlite3 doc useful as well.
To better illustrate:
db.execute( "
SELECT name
FROM gymtable
WHERE day = 'Monday'
AND ex_class = 'BoxFit'
AND ex_time = '0745-0845'
");

Query executes on phpmyadmin, but not in python script

The statement is set-up so that when a record already exists, it doesn't add a record, else, it does.
I've tried changing the query, even though I don't see anything wrong with it.
I've let the script run on python, and print the query it executed. Then I pasted that query in phpmyadmin, where it executed succesfully.
I have also double checked all parameters.
Query (blank params):
INSERT INTO users (uname,pass) SELECT * FROM (SELECT '{}','{}') AS tmp WHERE NOT EXISTS(SELECT uname FROM users WHERE uname = '{}') LIMIT 1;
Query (filled in parameters):
INSERT INTO users (uname,pass) SELECT * FROM (SELECT 'john_doe','password') AS tmp WHERE NOT EXISTS(SELECT uname FROM users WHERE uname = 'john_doe') LIMIT 1;
Python script (the important part)
if action == "add_user":
username = form.getvalue('username')
password = form.getvalue('password')
query = """
INSERT INTO users (uname,pass) SELECT * FROM
(SELECT '{}','{}') AS tmp WHERE NOT EXISTS(SELECT uname FROM users WHERE uname = '{}') LIMIT 1;
""".format(username, password, username)
mycursor.execute(query)
I know a couple of things.
There is nothing wrong with the database connection.
The parameters are not empty (ex. username="john_doe" & password="secret")
The query actually executes in that specific table.
The query seems to add a record and delete it directly afterwards (as AUTO_INCREMENT increases each time, even when the python script executes and doesn't add anything)
A try except doesn't do anything, as mysql.connector.Error doesn't report any error (which is obvious, since the query actually executes succesfully)
phpMyAdmin practical example:
(Removed INSERT INTO part in order to be able to show the resulting tables)
The first time you enter the query (above query as example), it will result in a table with both values as both column names as column values.
Screenshot of table output: http://prntscr.com/nkgaka
Once that result is entered once, next time you will try to insert it, it will simply result in only column names, no values. This means it will insert nothing, as there is nothing to insert as there are no actual values.
Screenshot of table output: http://prntscr.com/nkgbp3
Help is greatly appreciated.
If you want to ensure any field is unique in a table, make that field a PRIMARY KEY or UNIQUE KEY. In this case you want name to be unique.
CREATE UNIQUE INDEX name ON users(name)
With this in place you only need to INSERT. If a duplicate key error occurs the name already exists.
To avoid SQL injection, don't use """SELECT {}""".format. It will be SQL injection vulnerable.
Also don't store plain text passwords, ever. Salted hashes at least. There's plenty of frameworks that do this well already so you don't need to invent your own.

pymysql SELECT query with field of table that the user gives as input

i wondering if it's possible to make a query with select with the user give the field of table and the value that want. For example:
field=input("Field: ")
value=input("Value: ")
cursorobject.execute('SELECT id FROM users WHERE {}=\'{}\'')
result=cursorobject.fetchall()
for x in result:
print(x)
and if it's not possible , there is any way to do it?
PS: this one not working
Of course you can construct the text of your query as you want using variables. E.g.
query = 'SELECT id FROM users WHERE {}=\'{}\''
print(query.format(field,value))
But, have in mind that you should validate very well the contents of the variables, before executing the query, to avoid SQL injections. For example the contents of the variables should not contain quotes.
E.g. the below code, with the specific values of the variables, will return the full list of users:
field='name'
value='name\' or \'1\'=\'1'
query = 'SELECT id FROM users WHERE {}=\'{}\''
print(query.format(field,value))
The produced query would be:
SELECT id FROM users WHERE name='name' or '1'='1'
Following your edit, you should replace your 3rd line with:
cursorobject.execute('SELECT id FROM users WHERE {}=\'{}\''.format(field,value))
And for making the best to avoid sql injections, you should use the built-in query parameterization features of your framework - pymysql:
cursorobject.execute('SELECT id FROM users WHERE {}=%s'.format(field),(value))
Simply format the query for field and pass value as a parameter in second argument of cursor.execute which must receive an iterable (i.e., tuple/list):
# PREPARED STATEMENT
sql = 'SELECT id FROM users WHERE {} = %s'
# EXECUTE QUERY
cursorobject.execute(sql.format(field), (value,))
result = cursorobject.fetchall()

Python Sqlite3 Database table isn't being updated

I'm creating a change-password page for a website, which requests the new password and the current password. The old password is hashed and salted using the scrypt library then compared to the password stored in the sqlite3 database, and if these are a match, the new password is hashed and the database is updated. However I am having difficulty executing the update command, as it throws a sqlite3.OperationalError: unrecognised token: "\" error. The execute statement currently has the following code:
c.execute("UPDATE users SET password = \'{0}\' WHERE memberID = \'{1}\'".format(newPas, memID))
Initially we believed this error to have been caused by the use of ' in the string formatting due to the presence of ' within the new password itself, so this was run again as:
c.execute("UPDATE users SET password = \"{0}\" WHERE memberID = \"{1}\"".format(newPas, memID))
This successfully runs, but doesn't actually change anything in the database. We also attempted to create a query string and then execute the string.
query = "UPDATE users SET password = {0} WHERE memberID = {1}".format(newPas, memID)
c.execute(query)
This caused a sqlite3.OperationalError: near "'\xa1\x91\x9f\x88\xfb\x81\x12\xd4\xc2\xf9\xce\x91y\xf0/\xe1*#\x8aj\xc7\x1d\xd3\x91\x14\xcb\xa4\xabaP[\x02\x1d\x1b\xabr\xc7\xe4\xee\x19\x80c\x8e|\xc0S\xaaX\xc6\x04\xab\x08\x9b\x8e\xd7zB\xc6\x84[\xfb\xbc\x8d\xfc'": syntax error. I believe that this is caused by the presence of ' and " characters within the password, but I am unsure how to get around this issue as these are added by the hashing process and thus removing them would change the password.
The password I would like to add is:
b'\xa1\x91\x9f\x88\xfb\x81\x12\xd4\xc2\xf9\xce\x91y\xf0/\xe1*#\x8aj\xc7\x1d\xd3\x91\x14\xcb\xa4\xabaP[\x02\x1d\x1b\xabr\xc7\xe4\xee\x19\x80c\x8e|\xc0S\xaaX\xc6\x04\xab\x08\x9b\x8e\xd7zB\xc6\x84[\xfb\xbc\x8d\xfc'
I was wondering if anyone could share some insights into why it isn't liking the "\" character or why it isn't updating the database, and point me in the right direction to making it work. If you need more information or code snippets or just want to yell at me, please don't hesitate to! Thank you in advance :)
A couple of things with your code:
You should not use format to build your queries like this. This leaves you liable to SQL injection and, whilst you might sanitise your inputs in this case, it's a bad habit that will bite you.
All changes need to be committed to the database to actually take effect. This is why your second query did not throw an error but equally did not make any changes to the database.
The correct formatting of this query would be:
conn = sqlite3.connect('my_db.db')
c = conn.cursor()
query = "UPDATE users SET password = ? WHERE memberID = ?"
c.execute(query, (newPas, memID))
conn.commit() # To finalise the alteration
As a side note, the cursor expects a tuple in this case, so a common stumbling block comes when passing single values:
query = "UPDATE users SET password = ? WHERE memberID = 'abc'"
c.execute(query, (newPas)) # Throws "incorrect number of bindings" error
# Use this instead i.e. pass single value as a tuple
c.execute(query, (newPas,))
You could use format to create variable field names in a query, since placeholders are not allowed in this case:
fields = ['a', 'b', 'c']
query = "UPDATE users SET {} = ?".format(random.choice(fields))
in addition to using it to help you build big queries where it would be tedious to manually type all the placeholders, and difficult to ensure that you had the correct number if your code changed:
my_list = ['a', 'b',...., n]
placeholders = ', '.join(['?' for item in my_list])
query = "INSERT .... VALUES = ({})".format(placeholders)
You should use parametrized queries something like this:
c.execute("""UPDATE users SET password = ? WHERE memberID = ?;""", (newPas, memID))
It will allow to avoid nasty things like SQL-injections.

first time to build a simple app by python

I am an undergraduate student and this is my first time to build a pretty simple app for database.
import cx_Oracle
import getpass
# Get username and password for connecting to the database
user = input("Username [%s]:" % getpass.getuser())
if not user:
user = getpass.getuser()
password = getpass.getpass()
# Connecting to the database by the following format
conString = user + "/" + password + "#XXXXXXX"
connection = cx_Oracle.connect(conString)
cursors = connection.cursor()
# Enter the SQL statement
stmt = "xxxxxxxxxx"
# Run the statement
cursors.execute(stmt)
# Enter and run the SQL query
query = "SELECT xxxx, FROM xxxx"
cursors.execute(query)
rows = cursors.fetchall()
for row in rows:
print(row)
# IMPORTANT: Close the cursors and connection
curs.close()
con.close()
These code above is all I know abt how to connect the database and basically run some SQL query.
We group members are all beginners in programming so it is new to us to build an app.
This project require 5 parts. I want to show you one of 5 parts and do not want you to write the code for me, I want some tips/hints. I will be online to wait for the help and work with the program once receive any useful tips and update my process.
New Vehicle Registration
This component is used to register a new vehicle by an auto registration officer. By a new vehicle, we mean a vehicle that has not been registered in the database. The component shall allow an officer to enter the detailed information about the vehicle and personal information about its new owners, if it is not in the database.
It all depends on how you expect to receive the data. If this is an interactive thing, just use raw_input (with python 2.x) and then put them into queries using string formatting:
license_number = raw_input("please insert the vehicels license number: ")
car_type = raw_input("what car type? ")
# etc.
# validate inputs here.
# note that with python 2.x the variables will always be strings
# if using python 3.x, use input() instead of raw_input()
# put them into a query using string formatting
query = "INSERT INTO VEHICLE VALUES('%s','%s','%s','%s')" % (license_number, 'null', car_type, owner_name)
Of course, you're going to have to do all validation yourself, and also - remember to be secure (i.e., even with password protection, it's still a good idea to check the input for SQL injection).

Categories

Resources