I am currently working on a school project where I must develop a database application with a graphical user interface using Python, Tkinter, and SQLite3. The user enters the ProductID and quantity into a form, and I am trying to get the program to select the price of the product from the product table using the ProductID, and multiply this price by the quantity input by the user to give the total cost of the order and insert this result into the total field on the order table.
I am receiving the following error:
File "c:\Users\Ryan\OneDrive - C2k\A2 2020-2021\Computer Science\A2 Unit 5\Code\OrderForm.py", line 81, in CalculatePrice
price = ((int(quantity)*(int(x) for x in results)))
TypeError: unsupported operand type(s) for *: 'int' and 'generator'
I have carried out research into this error, however, I still cannot understand how to get this to work or if it is even possible. If anybody could take a look at my code below and try help me out with doing this, I would really appreciate it.
def CalculatePrice(self):
orderid = self.OrderIDEntry.get()
productid = self.ProductIDEntry.get()
quantity = self.QuantityEntry.get()
with sqlite3.connect("LeeOpt.db") as db:
cursor = db.cursor()
searchprice = ('''SELECT Price FROM Products WHERE ProductID = ?''')
cursor.execute(searchprice, [(productid)])
results = cursor.fetchall()
if results:
for i in results:
price = ((int(quantity)*(int(x) for x in results)))
addprice = ('''INSERT INTO Orders(OrderTotal)
VALUES (?)''')
cursor.execute(addprice, [(price)])
self.ClearEntries()
else:
tkinter.messagebox.showerror("Error", "No product was found with this ProductID, please try again.")
self.ClearEntries()
You are mixing an external loop over the results iterable, inserting 1 value at a time, and an execution of the same INSERT query over an iterable of values.
First way, external loop (I have removed some useless parentheses):
for i in results:
price = int(quantity)*int(i)
addprice = ('''INSERT INTO Orders(OrderTotal)
VALUES (?)''')
cursor.execute(addprice, [price])
Second way, using executemany:
prices = ([int(quantity)*int(x)] for x in results) # prices is an iterable of lists
addprice = ('''INSERT INTO Orders(OrderTotal)
VALUES (?)''')
cursor.executemany(addprice, prices)
But if you are learning SQL and database accesses, you could directly use joined queries:
addprice = '''INSERT INTO Orders(OrderTotal)
SELECT :quantity * Price FROM Products
WHERE Products.ProductID = :productid'''
cursor.execute(addprice, {'quantity': quantity, 'productid': productid})
And as your code contains an (unused) orderid variable, I think that what you want is:
addprice = '''INSERT INTO Orders(OrderID, OrderTotal)
SELECT :orderid, :quantity * Price FROM Products
WHERE Products.ProductID = :productid'''
cursor.execute(addprice, {'quantity': quantity, 'productid': productid,
'orderid': orderid})
Your expressions (int(x) for x in results) and (int(quantity)*(int(x) for x in results)) evaluates to a generator objects as you have enclosed it within parenthesis. See here
>>> (quant for quant in range(5))
<generator object <genexpr> at 0x1021e1780>
>>>
So remove your parenthesises and break it down into smaller chunks.
Also there should only be one price returned for a single productId, so you're looping multiple times and don't have to use tuples unless you're input itself is multiple product ids and you're multiplying each price and product and computing order total.
A simplified version might look like this
cursor.execute('SELECT Price FROM Products WHERE ProductID = ?', (productid,))
result = cursor.fetchone()
if result:
price = quantity * float(result[0])
cursor.execute('INSERT INTO Orders(OrderTotal) VALUES (?)', (price,))
self.ClearEntries()
else:
tkinter.messagebox.showerror("Error", "No product was found with this ProductID, please try again.")
self.ClearEntries()
Related
I should be searching based on two WHERE clauses at the same time. One is a simple clause, the other is MAX (text). How to solve?
x = cursor.execute('SELECT product FROM electronics WHERE brand = ? AND MAX(price)' [combo_brand])
Price is a column of a database. I want to take the highest value of the column records. I would like to select the product with the maximum price, and search by it and by brand at the same time.
I am getting this error:
TypeError: string indices must be integers
If you want to select the product having the max price for a given brand, then use:
sql = '''SELECT product
FROM electronics
WHERE brand = ? AND price = (SELECT MAX(e.price)
FROM electronics e
WHERE e.brand = electronics.brand)'''
x = cursor.execute(sql, (combo_brand,))
records = cursor.fetchall()
print("Total rows are: ", len(records))
for row in records:
print(row)
If instead you want the product with the maximum price across all brands, then use:
sql = '''SELECT product
FROM electronics
WHERE brand = ? AND price = (SELECT MAX(price) FROM electronics)'''
x = cursor.execute(sql, (combo_brand,))
But I suspect the first version is what you want.
I believe that I need to to expand the sql statement as the current one I have:
SELECT OrderID FROM Orders WHERE UserID = (?)
is likely to cause problems in the future when there are users with multiple orders. Is there a way that I can select and use the autoincrementing orderID in my orders table in combination?
For reference, my DB looks like this:
And the python I currently have is like this however I feel that it may have to be rewritten entirely.
results[0][0] is the ID of the current user from the Users table
elif userinput == "5":
basket = []
print(pd.read_sql_query('SELECT * FROM Products', conn))
shopping = True
while shopping:
itemToAdd = input("Please enter the ID of the item to add to the basket: ")
basket.append(itemToAdd)
print(basket)
continueShop = input("Continue shopping?(y/n): ")
if continueShop == "n":
conn.execute("INSERT INTO Orders (UserID) VALUES (?)", (results[0][0],))
conn.commit()
counter = 0
for items in basket:
createOrderItems = "INSERT INTO OrderItems (OrderID, ProductID) VALUES (?,?)"
currentOrder = ("SELECT OrderID FROM Orders WHERE UserID = (?) ", (results[0][0]))
conn.execute(createOrderItems, (currentOrder[0], basket[counter]))
counter = +1
conn.commit()
Because the database is built using the DB Browser application, I really have no clue how to access the parts of it that I need to ensure I am selecting the right record. Any help is appreciated, thanks.
Also, since the primary key of each table is autoincrementing I need a way to select only the record that was created just now using
conn.execute("INSERT INTO Orders (UserID) VALUES (?)",
However, I cannot think of a way to do so even though the record is unique in the orders table, as there is no way of knowing which order is the one that needs to be looked at as far as I can tell
You can use the lastrowid attribute of the cursor object to find the id of the inserted order. Then use a compound WHERE in the select statement (ie WHERE userid = something and orderid = something_else).
I've been working most of today on a function that creates a record in an sqlite table. I believe I am finally making some progress and it currently looks like this:
shopping = True
while shopping:
itemToAdd = input("Please enter the ID of the item to add to the basket: ")
basket.append(itemToAdd)
print(basket)
continueShop = input("Continue shopping?(y/n): ")
if continueShop == "n":
conn.execute("INSERT INTO Orders (UserID) VALUES (?)", (results[0][0],))
lastID = conn.execute("SELECT last_insert_rowid()")
conn.commit()
counter = 0
for items in basket:
createOrderItems = "INSERT INTO OrderItems (OrderID, ProductID) VALUES (?,?)"
conn.execute(createOrderItems, (lastID, basket[counter]))
counter = +1
conn.commit()
However, I am now encountering this error to do with lastID if I am reading the error correctly.
line 107, in
conn.execute(createOrderItems, (lastID, basket[counter])) sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type.
I have 2 tables that I am currently attempting to use:
Orders - contains only an orderID and userID
OrderItems- contains OrderItemsID, OrderID (which i need to be the same as the OrderID Just added) and ProductID(which needs to be taken from the list created and looped to make a record for each item in the "basket".
When you do
lastID = conn.execute("SELECT last_insert_rowid()")
lastID gets bound to an sqlite3.Cursor:
To retrieve data after executing a SELECT statement, you can either treat the cursor as an iterator, call the cursor’s fetchone() method to retrieve a single matching row, or call fetchall() to get a list of the matching rows.
The cursor cannot be converted automatically to the raw ID. You'll have to pull it out yourself, e.g. by doing something like
row = lastID.fetchone()
row_id = row[0]
Then use row_id in your query instead of lastID.
I am retrieving a value from a SQLITE table and then using this value to retrieve data from another table using a SELECT FROM WHERE statement. I cannot use the retrieved value to query the other table even though the values appear to match when I retrieve this value independently from the table I am querying. I get Error binding parameter 0 - probably unsupported type. I am passing the value I believe correctly from what I've read in the docs, but there is obviously something wrong.
Edit: The ulitmate goal is to select the Name and EndTime then insert the EndTime value in another table in the same db if a column value = Name in that table. Added Update code below that gives an idea of what I'm attempting to accomplish.
When I print nameItem it appears this is a unicode string, (u'Something') is how it appears. I don't know if this is an encoding issue, but I have used similar queries before and not run into this issue.
I have tried to use the text I am searching for directly in the SELECT query and this works, but when passing it as a variable I still get unsupported type.
c.execute('SELECT Name FROM Expected WHERE Timing = 1')
timeList = c.fetchall()
for i in range(len(timeList)):
nameItem = timeList[i]
c.execute('SELECT "EndTime" FROM Expected WHERE "Name" = ?', (nameItem,))
end = c.fetchone()
conn = sqlite3.connect(otherDb)
c = conn.cursor()
c.execute('UPDATE Individuals SET Ending = end WHERE NAME = NameItem')
I expect this to retrieve a time associated with the current value of nameItem.
The first fix to try is to use string instead of tuple (note timeList is list of tuples):
nameItem = timeList[i][0]
But better is to not use len, something like:
c.execute('SELECT Name FROM Expected WHERE Timing = 1')
timeList = c.fetchall()
for elem in timeList:
nameItem = elem[0]
c.execute('SELECT "EndTime" FROM Expected WHERE "Name" = ?', (nameItem,))
end = c.fetchone()
And even better is to fetch EndTime in the first query (looks acceptable in given context):
c.execute('SELECT Name, EndTime FROM Expected WHERE Timing = 1')
timeList = c.fetchall()
for elem in timeList:
name = elem[0]
end_time = elem[1]
I've managed to query and get results for values from a list. But say i have the genres ["Action", "Comedy", "Romance"] in the list I am using to query. My code below returns all the records which are action, romance and comedy whereas I want it to return only the records that meet all three genres. How can I do this?
The database has a field called genre in which there are multiple genres for each record.
Code:
with sqlite3.connect("animeData.db") as db: #anime database
c = db.cursor()
c.execute("select * from t where genre in %s" % repr(self.genreResults).replace('[','(').replace(']',')') ) #self.genreResults is the list containing the genres i want to query
results = c.fetchall()
print(results)
db.commit()
db.close()
Output:
Database:
It's returning all animes which have genres of action and adventure whereas I only want it to return animes which have both. Any suggestions?
If I understand correctly, 'like' clauses meet your requirements but you don't know how to convert list to 'like' clauses.
So the codes will be like below:
import sqlite3
with sqlite3.connect("animeData.db") as db: #anime database
c = db.cursor()
#self.genreResults is the list containing the genres i want to query
user_input = self.genreResults # for example: ['Action','Drama']
convert_to_like_conditions = ' and '.join(list(map(lambda item : "genre like '%{0}%'".format(item), user_input)))
print(convert_to_like_conditions) #Output: genre like '%Action%' and genre like '%Drama%'
c.execute("select * from t where %s" % convert_to_like_conditions )
results = c.fetchall()
print(results)
db.commit()
You can refer to the documents on map, string join.
And you probably notice I removed the last line (db.close) of your codes, you can refer to Understanding Python's "with" statement.