How do I allow placeholders to be empty in SQLite3 in Python? - python

I am writing a "Sales Order" database right now and I am supposed to implement a search function that allows the user to enter in data like, customer first name, last name, order ID, customer ID, etc. The problem I am having is that the customer does not have to enter anything for the fields and instead just press enter to leave it blank to skip. But SQL seems to be taking that as an empty input and looking for an empty field. How can I make it so that the program instead allows anything to be accepted by the placeholder rather than looking for a blank. Thanks!
initialSearchInformation = [input("Enter Customer Last Name (To skip, press ENTER)"),
input("Enter Customer Email (To skip, press ENTER)"),
input("Enter Customer Number (To skip, press ENTER)"),
input("Enter Order Number (To skip, press ENTER)"),
input("Enter Order Amount Greater Than (To skip, press ENTER)"),
input("Enter Order Amount Less Than (To skip, press ENTER)")]
conn = create_connection()
cur = conn.cursor()
cur.execute("""SELECT *
FROM SalesOrder
INNER JOIN Customer
ON Customer.CustomerID = SalesOrder.CustomerID
WHERE SalesOrderID=?
AND SalesOrder.CustomerID=?
AND Amount > ?
AND Amount < ?
AND Customer.CustomerName LIKE ?""", (initialSearchInformation[3], initialSearchInformation[2], initialSearchInformation[4], initialSearchInformation[5], '%'+initialSearchInformation[0]+'%',))
rows = cur.fetchall()
print("\nInfo Found: ")
for row in rows:
print(row)

Check for an empty value in your SQL. E.g. replace
SalesOrderId = ?
with
(? = '' OR SalesOrderID = ?)
Since there are now two placeholders, you'll need to duplicate the corresponding element in the parameter tuple:
initialSearchInformation[3], initialSearchInformation[3]
The full query becomes
cur.execute("""SELECT *
FROM SalesOrder
INNER JOIN Customer ON Customer.CustomerID = SalesOrder.CustomerID
WHERE (? = '' OR SalesOrderID=?)
AND (? = '' OR SalesOrder.CustomerID=?)
AND (? = '' OR Amount > ?)
AND (? = '' OR Amount < ?)
AND (? = '' OR Customer.CustomerName LIKE ?)""",
(initialSearchInformation[3], initialSearchInformation[3],
initialSearchInformation[2], initialSearchInformation[2],
initialSearchInformation[4], initialSearchInformation[4],
initialSearchInformation[5], initialSearchInformation[5],
initialSearchInformation[0], '%'+initialSearchInformation[0]+'%',))

Related

SQL Type Casting

I am trying to make a mock database to store film timings and allow the user to make bookings from the list. I have run into a problem where I am trying to take the ticket price from a table and multiply it by the number of tickets to get a final price. When I try to run the code it says that you cannot multiply a list by and int. Has anyone an idea on how to cast the value in a table in SQL into an int? Here is the relevant code:
showTime = input("Enter showtime: ")
filmRequest = input("Enter the film you want to watch: ").title()
priceSelection_ = "SELECT price FROM films WHERE film = ? AND timings = ?"
parSel_ = (filmRequest, showTime)
cursor.execute(priceSelection_, parSel_)
x = cursor.fetchall()
priceCalc_ = numTick_ * x
print(priceCalc_)
You do not cast it. You must select the appropriate value from the result set. In your case, it should be
x = cursor.fetchall()[0][0]
But you may need to further cast/process the value depending on how it is stored.

FIX "Check the manual that corresponds to your MySQL server version for the right syntax to use near '%s"

The following code works with insert query, but not with update and delete.
prono=int(input("Enter the poduct no :"))
sql_1="select * from product where prno=%s"
mycursor.execute(sql_1,prono)
myresult=mycursor.fetchall()
mydb.commit()
for x in myresult:
print(x)
#details printed
#req. details for updation
print("Please enter the new details of the product")
a=str(input("Enter the new name : "))
b=int(input("Enter the new price : "))
sql_2="update product set name=%s ,price=%s where prno=%s"
set1=(a,b,prono)
mycursor.execute(sql_2,set1)
mydb.commit
print("Product modified")
The error I'm getting is 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 '%s'
You seem to be trying to convert a string to an int:
a=int(input("Enter the new name : "))
This probably is not working with your table layout.
Try:
a=input("Enter the new name : ")
Also you are using "No" and "NO" in your queries.
It's not the spelling of no, it's a reserved word. This seems to be valid:
UPDATE
product
SET
myname = 'string',
myprice = 123
WHERE
myno = 1;
(of course you need to change your column names in the database table for this to work)
You are using NO as column name, but is a MySql reserved word, you should use backticks for it like this for sql_1 & sql_2:
sql_1="select * from product where `No`=%s"
sql_2="update product set name=%s ,price=%s where `NO`=%s"
But the better solution it is not using reserved words as column names.
EDIT
Also, your sql_1 query is wrong, you donĀ“t need to use (). If you do it, you get a touple with a string, not a string

ValueError: invalid literal for int() with base 10: 'NewFilmLikes' in Python

I am trying to get a value from an SQLite3 database and put that into a variable called FilmLikes, I then want to add one to it and I store that in the variable NewFilmLikes. I then try to change the value of this box in my database to the 'NewFilmLikes', however I always get this problem:
ValueError: invalid literal for int() with base 10: 'NewFilmLikes'
Here is the code showing that:
FilmLikes=i[2]
NewFilmLikes=(int(FilmLikes))+1
filmUpdate=("UPDATE HORRORALL SET likes = ? WHERE number = 1"(NewFilmLikes))
c.execute(filmUpdate)
conn.commit()
Here is the code for i:
for i in find_film:
print('')
print('Number',(i[0]))
print(i[1])
filmChoice=int(input('Please choose which number you would like to like: '))
if filmChoice==1:
find_film=c.execute("SELECT * FROM HORRORALL")
for i in find_film:
if i[0]==filmChoice:
## FilmLikes=i[2]
try:
x=(int(i[2]))+1
except:
pass
## FilmLikes=i[2]
## NewFilmLikes=(int(str(FilmLikes)))+1
filmUpdate=("UPDATE HORRORALL SET likes = ? WHERE number = 1"(x))
c.execute(filmUpdate)
conn.commit()
Without knowing much more about your setup, it's hard to answer this properly.
Mind you, the specific error you refer to (ValueError: invalid literal for int() with base 10: 'NewFilmLikes') often occurs when you get a decimal rather than an integer.
Here's a sort of general answer.
It's good practice not to use SELECT * because it hides what you are trying to retrieve. Specify, e.g SELECT film_id, file_name, no_of_likes FROM horrorall as this way you can see what you are retrieving and the positions.
You're retrieving the entire list of films with find_film and then looping through to find which one. SQL has a find function, it's called WHERE and you are using it in the film_update section. If you have the ID or Name inputted by the user, you can then call only the record you need. E.g. "SELECT film_id, file_name, no_of_likes FROM horrorall WHERE film_id = ?" (filmChoice,)
Note that parameterised queries use a tuple, even if there is only one parameter - hence it is (filmChoice,) with a comma (and for filmUpdate you would need (x,))
filmUpdate will only ever update the first film. I assume that because your if ... loop continues through all the possible options? You can shortly this by putting another ? in there for your WHERE e.g. filmUpdate=("UPDATE HORRORALL SET likes = ? WHERE number = ?"(x,i[0]))
How does the user know what film to select? You aren't retrieving the list until they give you a number!
Putting all of this together, here is an example. Note this is far from the ideal way of doing it, I don't want to throw too many ideas at you in one go!
# Get the whole list of films to show to the user
find_film = c.execute("SELECT film_id, film_name FROM HORRORALL")
# Present the list for selection
for films in find_film:
print(str(films[0]) + '. ' + films[1])
# Get the users input as an integer
filmChoice = int(input('Please choose which number you would like to like: '))
# Fetch the number of likes of the selected film
film_likes = c.execute('SELECT likes FROM HORRORALL WHERE film_id = ?' (filmChoice,))
# Send the update back to the database
c.execute("UPDATE HORRORALL SET likes = ? WHERE film_id = ?"(int(film_likes[0]) + 1, filmChoice)
conn.commit()

Unique Keys and Python Dictionary

Here is the code for the relevant function:
def populateSubscribers(csvfile, db):
conn = sqlite3.connect(db)
conn.text_factory = str #bugger 8-bit bytestrings
cur = conn.cursor()
subscriber_dict = {}
# read values from tab-delimited csv file
reader = csv.reader(open(csvfile, "rU"), delimiter = '\t')
for Number, Name, Message, Datetime, Type in reader:
if str(Number)[:1] == '1':
tmpNumber = str(Number)[1:]
Number = int(tmpNumber)
# check to ensure name/number not null
if Number and Name:
# add unique subscribers to dictionary
subscriber_dict[Number] = Name
else:
print 'Subscriber missing name or number'
# insert unique subscribers into subscriber table
for number, name in subscriber_dict.items():
cur.execute('INSERT OR IGNORE INTO subscriber (name, phone_number) VALUES (?,?)', (name, number))
conn.commit()
cur.close()
conn.close()
print '...Successfully populated subcriber table.'
It is reading subscriber names and phone numbers from a csv file and then it is supposed to write an entry for each unique subscriber into the database. I wanted the phone number to be the key in key/value pairs since it is unique. But for some reason, it is not reading all of the numbers from the data, it is missing some subscribers. If I make the name the key it misses as would be anticipated (de-duplicates all the Unknowns), but the phone number as key is missing some numbers altogether. Any ideas on how to fix the logic here?
Looks to me like if str(Number)[:1] == '1': is probably filtering out some of your data.
Add an else to that and print out any it's rejecting. Those are probably the ones which are going wrong.
Either way, pare down your input data and find which one's aren't being used. Without seeing the data and the alternative you've said which does work, it's hard to pin down the exact cause here.

Python SQL select row from specific variable field

I'd like to grab a specific value from a row based on a random variable. Here's an example table the PID column is an "auto-increment primary key integer" and the other 2 columns are TEXT
example-table
PID NAME PHONE
--- ---- -----
1 bill 999-9999
2 joe 888-8888
I'd like to throw a random variable at the table
randomVariable = raw_input('Enter something: ')
> 1
and have the code return the name
> bill
I know I can use something like...
randomVariable = raw_input('Enter something: ')
sql = ("SELECT name FROM example_table WHERE pid='%s'" % randomVariable)
result = cursor.execute(sql)
print result
> bill
Apparently using '%s' isn't secure and it is suggested to use '?' in it's place.
randomVariable = raw_input('Enter something: ')
sql = ("SELECT name FROM example_table WHERE pid=?", randomVariable)
result = cursor.execute(sql)
print result
But this doesn't seem to work for me. I end up with...
"ValueError: operation parameter must be str or unicode"
I realize I could just grab all the rows and put them into a variable which I could then iterate over till I find what I'm looking for but I'm thinking that wouldn't be very efficient with a large database. can anyone help point me in the right direction with this?
I believe you're meant to use it like this
randomVariable = raw_input('Enter something: ')
sql = "SELECT name FROM example_table WHERE pid=?"
result = cursor.execute(sql, randomVariable)
print result
Validate the user input, and %s is fine. Storing your rows and putting them into a list is not a good idea at all, since the amount of rows will grow over time, taking up a huge amount of memory when not even in use. To guard against SQL injection, you could validate input using something like a typecast to an int, put that in a try/except block, and this would stop all malicious input such as ' OR 1=1--

Categories