I am writing a small program that lets me search a sqlite database, assets by asset number, serial number, etc. The problem is that I'm not sure has to pass user input, a variable assetNum, into my sqlite SELECT statement. I would like it to take the user-queried assetNum and return that row from the sqlite table.
First, I defined my function:
def search_asset_num(conn):
cur = conn.cursor()
cur.execute("SELECT * FROM assets WHERE AssetNumber = '{}'".format(assetNum))
rows = cur.fetchall()
for row in rows:
print(row)
In the program I utilize user-input to move through menus, so later on in the program when I get to the "search by asset menu" I have:
elif selection == '2':
menu2 = {}
menu2[' 1'] = "Search Assets by Name"
menu2[' 2'] = "Search Assets by Asset Number"
menu2[' 3'] = "Search Assets by Serial Number"
menu2[' 4'] = "Search Assets by Ownership"
menu2[' 5'] = "Go back!"
choices2 = menu2.keys()
for entry in choices2:
print(entry, menu2[entry])
selection2 = input("Enter number: ")
if selection2 == '2':
assetNum = input("Enter Asset Number: ")
search_asset_num(conn)
The problem, from what I can tell, is that assetNum is present in the search_asset_num() function above where it is actually defined in the if statement as assetNum = input("Enter Asset Number: "). I'm not sure how to work around this. I have tried making assetNum global at the very top of my code and setting it to equal 0 as a placeholder, but that did not work. It just outputs 0 to the terminal.
Add assetNum as parameter to your function,
def search_asset_num(conn, assetNum):
cur = conn.cursor()
cur.execute("SELECT * FROM assets WHERE AssetNumber = ?", (assetNum,))
rows = cur.fetchall()
for row in rows:
print(row)
in your menu, you can change as below:
if selection2 == '2':
assetNum = input("Enter Asset Number: ")
search_asset_num(conn, assetNum)
also use "Parameter Substitution" as stated in Python sqlite3 - DB-API documentation
Related
I am working on a project and in that, I've to work on sql. In the code, I've to work on a single row to match the values of a person.
def userid():
os.system('cls')
ii = input("enter your User ID: ")
curs.execute("SELECT ID FROM users") #shows ID row of users table
rows = curs.fetchall() #fetch all data of ID row
if (ii,) in rows: #if value of ii is in the row, condition evaluates
password()
else:
exit()
def password():
ps = getpass.getpass("enter your pin: ")
curs.execute("SELECT pin FROM users") #shows PIN row of users table
row = curs.fetchall() #fetch all data of pin row
if (ps,) in row: #if data in row matches with data in ps, condition evaluates
main()
else:
exit()
this is the code and you can see, in the first function, I am successful in fetching user ID but when it comes to passwords, I want to match the password in the row containing the UserId entered by the user. But instead, all passwords it contains is getting matched and error is occurring.
recently I discovered a keyword fetchone() but am not sure how to use it or it would work or not.
Please help me, how can I work on only one row in sql using python.
You need to use WHERE clauses to filter the query results before the database returns them. For example
SELECT ID, PIN FROM users WHERE ID = 42
will return only the id and pin for the user with id 42, or nothing if there is no row with this id.
Using WHERE clauses, we can change your code like this:
def userid():
os.system('cls')
ii = input("enter your User ID: ")
# I'm guessing ID is an integer value in the database?
id_ = int(ii)
# fetch matching id
curs.execute("SELECT ID FROM users WHERE ID = %s", (id_,))
row = curs.fetchone() #fetch all data of ID row
if row: # if the query returned a row, the id exists
password(id_)
else:
exit()
def password(id_):
ps = getpass.getpass("enter your pin: ")
# Fetch the PIN only for our user's ID
curs.execute("SELECT pin FROM users WHERE ID = %s", (id_,))
row = curs.fetchone() #fetch all data of pin row
# if data in row matches with data in ps, condition evaluates
if (ps,) in row:
main()
else:
exit()
Note that when checking credentials like this, it's common to get the id and password and check them both in a single query:
id_ = int(input('What is your id number?'))
password = getpass.getpass('What is your PIN?')
cur.execute("""SELECT id, password FROM users WHERE id = %s AND password = %s""",
(id_, password))
This is more efficient, because only one query is sent to the database, and potentially more secure, because if it fails the users does not know whether the id or password is wrong.
I am currently creating a main menu that acts like a bank account.
def main_menu():
print("Main Menu")
print("0 - Quit")
print("1 - Open Account")
print("2 - Check Balance")
print("3 - Close Account")
loop = True
while loop:
main_menu()
choice = input("Enter your choice: ")
choice = int(choice)
if choice == 0:
exit(loop)
elif choice == 1:
name_on_account = input("Name on account: ")
balance = float(input("Enter Initial Balance: "))
print("---Account successfully created---")
print("Account number:", account_no())
print("Name on account:", name_on_account)
print("Balance:", balance)
print("Account opened on:", now)
cur.execute("""
INSERT INTO account(name_on_account, balance) VALUES
("%s", "%s");""", (name_on_account, balance))
connection.commit()
elif choice == 2:
print("Checking account balance")
account_number = input("Enter account number: ")
print("---Checking account balance---")
print("Account number:", account_number)
cur.execute("""SELECT * from account;
""")
account_no1 = cur.fetchone()
for i in account_no1[0]:
if account_number == i:
cur.execute("""select name_on_account from account where account_no = "%s";
""", (account_number,))
name1 = cur.fetchone()
print(name1)
name2 = ''.join(map(str,name1))
name3 = int(name2)
print("Name on account:", name3)
cur.execute("""select balance from account where account_no = "%s";
""", account_number)
balance1 = cur.fetchone()
balance2 = ''.join(map(str,balance1))
balance3 = int(balance2)
print("Balance:", balance3)
cur.expecute("""select account_open_date from account where account no = "%s";
""", account_number)
date1 = cur.fetchone()
date2 = ''.join(map(str, date1))
date3 = int(date2)
print("Account opened on:", date3)
connection.commit()
else:
print("Error: Invalid account number")
I'm not worried about option 3 as of right now, but I am having trouble with option 2.
When a person pick option 1, they will input their name and the amount of money deposited in their bank account.
This information will be stored in the mysql table account(account_no, name_on_account, balance, account_open_date, account_status).
This means that account_no is auto-incremented, account_open_date is default as curdate(), and account_status is default to be "open").
In option 2 however, when a person input their account number; it should return back all of their information how it is displayed in the option 1.
What I am having trouble with is, how do you efficiently iterate over the person's information using fetchone() and be able to get the specific column information with (account_no = account_number) (if you do have a better suggestion on a better way to implement this, please comment below)
This is the error message that I get:
Traceback (most recent call last):
File "(deleted for privacy purposes)"
for i in account_no1[0]:
TypeError: 'int' object is not iterable
Thank you for the help!
pymysql (and most other python mysql clients) is returning a tuple when you invoke fetchone(), and each entry in the tuple matches up to the datatypes defined in the table that you're querying. So let's look at your code:
elif choice == 2:
print("Checking account balance")
account_number = input("Enter account number: ")
print("---Checking account balance---")
print("Account number:", account_number)
cur.execute("""SELECT * from account""")
account_no1 = cur.fetchone()
for i in account_no1[0]:
Here you're querying all columns and all rows from the account table, reading the first row, and then iterating over whatever is in the first column of that row. But that's probably just an id column, which is probably why you're getting the error that you're getting: integers are not iterable. That'd be like writing for i in 10, Python doesn't understand what that means
If you want to iterate over all of the returned rows, you can do that like this:
cur.execute("""SELECT * from account;
""")
for row i in cur.fetchall():
# Each iteration "row" is a tuple of values corresponding to the table's columns
That's kind of silly though. You'd returning all of the rows from the database and then iterating over them and looking for a specific account number. Why not just do that as part of your query?
nrows = cur.execute("SELECT * from account where account_no=%s", (account_number,))
if nrows == 0:
# Account number not found, do something
else:
row = curs.fetchone()
# row now contains all of the values from the discovered
Note that you don't need to put quotation marks around %s placeholders, and you don't need semicolons. The client does all of this conversion for you.
Also note that you should not select * from tables. What if the table definition changes to include more columns? Just select the handful of columns that you actually need, then if more columns are added to the table later your code won't need to be changed at all and you won't be requesting more data than you need. So more like:
nrows = cur.execute("SELECT name, balance, date_opened from account where account_no=%s", (account_number,))
if nrows > 0:
name, balance, date_opened = curs.fetchone()
Function using sqlite3 to bring back data from a table and return #results based on criteria is only returning zero. Running the #function through Visual Studio brings back the expected results but #when I try to run it from the terminal it is interpreting the table #as being an empty list.
import sqlite3
con = sqlite3.connect('test2.db')
cur = con.cursor()
small table to illistrate the problem. Table output is [('Jane', 300.0), ('Joe', 100.0), ('Joe', 50.0)]
total_bal = """SELECT name, amount FROM customers2"""
user_name = input("What is your name? ")
def account_balance(name):
cur.execute(total_bal)
table = cur.execute(total_bal)
total = 0
name = user_name
for t in table:
if t[0] == name:
total += t[1]
return total
print(account_balance(user_name))
expecting to return 150 if user_name input = 'Joe' or 300 if 'Jane'
You could actually just do this with your query and avoid the account balance function all together.
statement = "SELECT name, account FROM customers2 WHERE name = ?;"
name = input("Enter your name: ")
cur.execute(statement, (str(name),))
results = cur.fetchone()
if results:
print(f"Name: {results[0]}\nAccount Balance: {results[1]}"
else:
print("Your name is not in the database")
I have a function within my "students' test" program.
This function reads out either the "highest score", "lowest score" or "average score" when you enter the student's name and class number.
The first two parts work but i can't seem to get the average working, when i read a value from a database it never returns like i would prefer it to, it returns it like: [(6,) , (3,)].
This is the function below:
def readScore():
selection = input("What score would you like the read ? \n 1 - Lowest score \n 2 - Highest score \n 3 - Average score... ")
name = input("Please enter the name of the pupil...")
classNo = input("Please enter the class of the pupil...")
myFile = sqlite3.connect("scores.db")
c = myFile.cursor()
c.execute('SELECT score FROM scores WHERE name = (?) AND classNo = (?)', (name, classNo,))
row = c.fetchall()
print(row)
try:
if selection == "1":
print (min(row))
if selection == "2":
print (max(row))
if selection == "3":
print (sum(row) /len(row))
except:
print("No scores for that student")
myFile.commit()
myFile.close()
You could compute the average in your program, but it would be a better idea to avoid fetching all rows, and to let the database compute these values:
c.execute('SELECT MIN(score) FROM ...') # or
c.execute('SELECT MAX(score) FROM ...') # or
c.execute('SELECT AVG(score) FROM ...')
row = c.fetchone()
print(row[0])
I'm trying to enter details into an SQL database through Python. I have already created the database with fields customerID, firstname, surname, town and telephone.
When running this function, I get the error 'str' object is not callablefor the line where I am trying to INSERT the values of the variables.
import sqlite3
#function used to add a new customer, once confirmed save the customer in a
#customer list
def add_customer():
#open up the clients database
new_db = sqlite3.connect('clients.db')
#create a new cursor object to be able to use the database
c = clients_db.cursor()
print("Add customer")
firstname = ""
while len(firstname) == 0:
firstname = input("Enter the customer's first name: ")
surname = ""
while len(surname) == 0:
surname = input("Enter the customer's surname: ")
town = ""
while len(town) == 0:
town=input("Enter the customer's town: ")
telephone = '1'
while len(telephone) != 11:
while telephone[0] != '0':
telephone = input("Please enter the customer's telephone number: ")
if telephone[0] != '0':
print ("telephone numbers must begin with zero")
elif len(telephone) != 11:
print("must have 11 numbers")
#check that data has been entered
print(firstname,surname,town,telephone)
#insert data into the customer table
c.execute('INSERT INTO Customer VALUES (NULL, ?,?,?,?,)'(firstname, surname, town, telephone))
print("Customer added successfully ...")
clients_db.commit()
clients_db.close()
if choice ==1:
another = input("Would you like to add another? yes [y] or no [n] --> ")
if another=='y':
add_customer()
else:
main_menu()
You forgot a comma between the SQL statement string and the parameters:
c.execute('INSERT INTO Customer VALUES (NULL, ?,?,?,?,)'(firstname, surname, town, telephone))
# ^
so you effectively do this: "some string"(arg1, arg2, ...), trying to treat the string as a function.
Simply insert a comma there:
c.execute(
'INSERT INTO Customer VALUES (NULL, ?,?,?,?,)',
(firstname, surname, town, telephone))