sqlite withdraw/deposit function in python - python

The last stretch of my banking project I've been working on is the deposit/withdraw function. I've gotten most of the other bits working (outside of cleaning up the code) I'm not fully understanding how one adds and subtracts a number from a sql statement inside of python...so here's the part of the code I'm struggling with:
here are my tables:
sqlite_file = 'banking2_db.sqlite'
table_1 = 'Bartertown'
table_2 = 'PINs'
id_column = 'Card_Numbers'
column_1 = 'Character_PINs'
column_2 = 'Balances'
column_3 = 'Card_Numbers'
column_4 = 'Characters'
class LoginPrompt:
def Login(self):
while True:
print(menu[1])
self.Card_number=str(input('>> '))
print(menu[2])
while True:
try:
self.Character_PINs = getpass.getpass('>> ')
self.one_row = c.execute('SELECT * FROM {tn} WHERE {cn}=? and {cnn}=?'.\
format(tn=table_1, cn=column_1, cnn=column_3), (self.Character_PINs, self.Card_number,))
for row in self.one_row.fetchone():
print('Welcome: ', row)
input('Press any key to continue... ')
return
except:
print('PIN incorrect; try again')
break
#MINOR ISSUE, ONLY QUERIES CHAR COLUMN
def loginMenu(self):
while True:
print(menu[5])
print("\n1 - Deposit funds")
print("2 - Withdraw funds")
print("3 - Check balance")
print("4 - Reset Pin")
print("5 - Exit")
while True:
try:
choice = int(input("Please enter a number: "))
except ValueError:
print("Please choose a valid entry")
if choice >= 1 and choice <=5:
choice == 1:
amount = input("\nPlease enter the deposit amount: ")
if amount != '' and amount.isdigit():
int(amount)
balance = c.execute('UPDATE {tn} SET {cn} = Balances +:amount WHERE Card_Numbers =:self.Card_number' .\
format(tn=table_1, cn=column_2,))
new_bal = balance + (int(amount))
print('${} has been deposited to account {} and the new balance is ${}'.\
format(amount, self.Card_number, balance + (int(amount))))
for row in self.Balances.fetchone():
print('Your new balance is: ', new_bal)
return self.loginMenu()
basically, I'm trying to make sure the program can only pull the balance where the PIN and the Card Number are specified. It selects the balance (This part is working, it is another option in the menu) however, the UPDATE function is still a mystery to me. I understand how to update both the ENTIRE column...on accident, and also how to change the value presented in the Balance field to the value the user submitted ie: the user selects to deposit 100 caps, and then their balance becomes 100 caps. The column I'm trying to update is called Balances, Card_Numbers is the column containing the users "credit card" and amount is the value the user just entered.
Thank you for your help.
edit: added tables, and initial input of the data.

If you want to update the column Balances then your statement should be:
...SET Balances = Balances + :amount...
so do it like this:
c.execute("UPDATE " + table_1 + " SET Balances = Balances + ? WHERE Card_Numbers = ?", (amount, self.Card_number,))

Finally figured it out, silly me.
choice == 1:
amount = input("\nPlease enter the deposit amount: ")
if amount != '' and amount.isdigit():
int(amount)
balance = c.execute('UPDATE {tn} SET {cn} = Balances +:amount WHERE Card_Numbers =:self.Card_number' .\
format(tn=table_1, cn=column_2,))
new_bal = balance + (int(amount))
I was trying to reference it by printing the output of the of the db while it hadn't been committed yet, :eyeroll:
Thank you for the help forpas, it worked like a charm.

Related

How to print new balance after adding amount to the initial one?

I'm learning Python and went with a simple ATM code. I've tested it and everything works DownStream - what I mean by this is:
I have a few options when the class is initialized - Balance, Deposit, Withdraw, Exit.
When I run Balance I receive the amount set.
2.1. I go with Deposit - it shows the new amount the person has in their account
2.2. When I use Withdraw I get correct amount as well
Question - When I Deposit and then type Balance I'm getting the initial Balance of the user - that is expected. How can I change the code so after Depositing Money and select Balance to show me the new Balance?
Is this possible to be performed without much complicating the code?
The code:
class User:
def __init__(self):
self.fname = input('Enter your first name: ')
self.lname = input('Enter your last name: ')
self.age = input('Enter your age: ')
def user_details(self):
print('Details:')
print(f"First Name: {self.fname}")
print(f"Last Name: {self.lname}")
print(f"User age: {self.age}")
def deposit_money(self):
self.deposit_amount = 100
return self.deposit_amount
def withdraw_money(self, withdraw_amount):
self.withdraw_amount = withdraw_amount
return self.withdraw_amount
class ATM:
atm_balance = 10000
def __init__(self):
self.machine_balance = self.atm_balance
def user_bank_balance(self):
self.user_balance = 300
print ('Your current balance is ${}'.format(self.user_balance))
def deposit_atm(self, user):
self.total_savings = 0
deposit_m = float(input('How much do you want to deposit? '))
if deposit_m > user.deposit_money():
print('You do not have enough money to deposit')
elif deposit_m == user.deposit_money():
print('Amount deposited: ${}'.format(deposit_m))
self.total_savings = self.user_balance + deposit_m
print('Total amount in your account: ${}'.format(self.total_savings))
def withdraw_atm(self):
savings_left = 0
sum_to_withdraw = float(input('How much do you want to withdraw? '))
if self.atm_balance > sum_to_withdraw and self.user_balance > sum_to_withdraw:
savings_left = self.total_savings - sum_to_withdraw
print("You have withdraw {}".format(sum_to_withdraw))
print('You balance is {}'.format(savings_left))
elif self.atm_balance > sum_to_withdraw and self.user_balance < sum_to_withdraw:
print('Daily limit eceeded')
else:
print('ATM out of service')
class ATMUsage:
#classmethod
def run(cls):
print('Bulbank ATM')
instructions = print("""
Type 'Balance' to check your current balance,
Type 'Deposit' to deposit amount into your account,
Type 'Withdraw' to withdraw from your account,
Type 'Exit' to exit from your account,
""")
active = True
user1 = User()
atm1 = ATM()
user1.user_details()
while active:
selection = input("What would you like to do: 'Balance', 'Deposit', 'Withdraw', 'Exit': ")
if selection == 'Balance'.lower():
atm1.user_bank_balance()
elif selection == 'Deposit'.lower():
atm1.deposit_atm(user1)
elif selection == "Withdraw".lower():
atm1.withdraw_atm()
elif selection == 'Exit'.lower():
print('Thanks for passing by. Have a good one!')
break
else:
print('Wrong selection. Please, try again')
ATMUsage.run()
That's because every time you call the user_bank_balance method, you set the user_balance attribute to 300. So it wouldn't matter what updates you did on the user_balance, whenever you call the user_bank_balance method, you'll get 300
class ATM:
atm_balance = 10000
def __init__(self):
self.machine_balance = self.atm_balance
self.user_balance = 300
def user_bank_balance(self):
print ('Your current balance is ${}'.format(self.user_balance))

How can I get a single column in python and sql?

I am trying to make a book selling system and I am trying to take the book's name from input and find the quantity of the book.But system takes the whole row instead of taking a single column.How can I solve this ?
import sqlite3
print("------------------------------------------")
print("Welcome to the bookshop management system.")
print("------------------------------------------")
print("[1] Add Book")
print("[2] Search for a book")
print("[3] Sell a book")
print("[4] Change stocks")
connect=sqlite3.connect("librarydatabase.db")
cursor=connect.cursor()
Inserter="INSERT INTO books VALUES('booknamevalue','writervalue','DateOfReleasevalue','Quantityvalue','Pagevalue')"
operation=input("Please enter an operation:")
if operation=="1":
bookname=input("Please enter the book's name")
writername=input("Please enter the writer's name:")
DateOfReleaseinput=input("Please enter the Date of release:")
Quantityvalue=input("Please enter the Quantity of the book:")
Pagevalue=input("Please enter the Page count of the book:")
Inserter1=Inserter.replace("booknamevalue",bookname)
Inserter2=Inserter1.replace("writervalue",writername)
Inserter3=Inserter2.replace("DateOfReleasevalue",DateOfReleaseinput)
Inserter4=Inserter3.replace("Quantityvalue",Quantityvalue)
Inserter5=Inserter4.replace("Pagevalue",Pagevalue)
cursor.execute(Inserter5)
connect.commit()
Booksellersearcher="SELECT Quantity FROM Books WHERE Bookname='Booknamevalue'"
#Will be made correctly
if operation=="3":
Bookname2=input("Please enter the name of the book:")
Booksellersearcher2=Booksellersearcher.replace("Booknamevalue",Bookname2)
cursor.execute(Booksellersearcher2)
BookQuantity=cursor.fetchone()
if BookQuantity==0:
print("No Stock On this Book")
operation=input("Please enter an operation:")
else:
print("There are"+" "+str(BookQuantity)+"books"+" "+"of"+" "+Bookname2)
operationinput=input("Do you wanna sell ?(Y/N)")
if operationinput=="Y":
SellingQuantityInput=int(input("How many Books do you wanna sell ?"))
NewQuantity=BookQuantity-SellingQuantityInput
print(NewQuantity)
else:
operation=input("Please enter an operation:")
Booksearcher="SELECT * FROM Books WHERE Bookname='Booknamevalue'"
if operation=="2":
Booknameinput2=input("Please enter the name of the book:")
Booksearcher2=Booksearcher.replace("Booknamevalue",Booknameinput2)
cursor.execute(Booksearcher2)
Bookvalues=cursor.fetchall()
print(Bookvalues)
BookQuantitychanger="UPDATE Books SET Quantity='Quantityvalue' WHERE Bookname='Booknamevalue'"
if operation=="4":
Booknameinput3=input("Please enter the name of the book:")
BookQuantityinput=int(input("Please enter the quantity of the book:"))
BookQuantitychanger2=BookQuantitychanger.replace("Quantityvalue",str(BookQuantityinput))
BookNamereplacer=BookQuantitychanger2.replace("Booknamevalue",Booknameinput3)
cursor.execute(BookNamereplacer)
connect.commit()
print("Book quantity changed successfully!")
I will start with your question, SELECT on a table will return rows, which are put in tuples, even you select a single columns it returns the rows containing just this column, but those are still rows, and so tuples.
But now please read the following.
Using string replace or any other other string templating for any SQL statement is leaving it wide open for SQL injection, what if the user inputs ' ; DROP TABLE books ; -- in the Booksearcher statement ?
You end up with
SELECT * FROM Books WHERE Bookname='' ; DROP TABLE books ; --'
which will destroy you books table.
Please go through the SQLite3 tutorial to see SQL parameterisation.
Your SQL statement is SELECT * which is why you get all columns.
Change your SQL statement to the one below:
Booksearcher="SELECT Quantity FROM Books WHERE Bookname='Booknamevalue'"
But your code is a bit unreadable.
You are using a lot of replacements and for each you're using a new variable. Use f-strings instead.
Your variable names are capitalized. In python that's used to define classes/objects.
Your if statements should be if/elif instead.
There is no main loop, so your code only executes once.
You have what I would call main menu prints inside your submenus. Instead you should go back to the main menu.
Little Bobby Tables
I did a quick rewrite of your code because I'm a bit bored. See below
import sqlite3
connect = sqlite3.connect("librarydatabase.db")
cursor = connect.cursor()
while True:
print("------------------------------------------")
print("Welcome to the bookshop management system.")
print("------------------------------------------")
print("[1] Add Book")
print("[2] Search for a book")
print("[3] Sell a book")
print("[4] Change stocks")
print("[0] Exit")
operation = input("Please enter an operation:\n")
if operation == "1":
bookname = input("Please enter the book's name:\n")
writername = input("Please enter the writer's name:\n")
dateofrelease = input("Please enter the Date of release:\n")
quantity = input("Please enter the Quantity of the book:\n")
pagecount = input("Please enter the Page count of the book:\n")
cursor.execute(f"INSERT INTO books VALUES('{bookname}','{writername}','{dateofrelease}','{quantity}','{pagecount}')")
connect.commit()
elif operation == "2":
bookname = input("Please enter the name of the book:\n")
cursor.execute(f"SELECT Quantity FROM Books WHERE Bookname='{bookname}'")
books = cursor.fetchall()
print(books)
elif operation == "3":
bookname = input("Please enter the name of the book:\n")
cursor.execute(f"SELECT Quantity FROM Books WHERE Bookname='{bookname}'")
bookquantity = cursor.fetchone()
if bookquantity == 0:
print("No Stock On this Book")
# go to the start of the while loop
continue
else:
print(f"There are {bookquantity} books of {bookname}")
operationinput = input("Do you wanna sell ?(Y/N):\n")
if operationinput.upper() == "Y":
sellingquantity = int(input("How many Books do you wanna sell ?\n"))
newquantity = bookquantity - sellingquantity
print(newquantity)
else:
continue
elif operation == "4":
bookname = input("Please enter the name of the book:\n")
bookquantity = int(input("Please enter the quantity of the book:\n"))
cursor.execute(f"UPDATE Books SET Quantity='{bookquantity}' WHERE Bookname='{bookname}'")
connect.commit()
print("Book quantity changed successfully!")
elif operation == "0":
# exit while loop
break
else:
print("Operation not recognized.")

Why am I getting a UNIQUE constraint error in sqlite?

I'm trying to create a bank account management system where the user can create an account, log in, and withdraw/deposit money from that account.
# PHASE 1 (FILE I/O and Logic of System)
# Initialization of Current Balance ** Current Balance is the same for all users for the sake of simplicity **
myMoney = open("current_balance.txt")
currentBalance = int(myMoney.readline())
# Imports
import sqlite3
# Creation of Bank Account and Notifying User(s) of Current Balance
class Bank_Account:
def __init__(self):
self.balance= currentBalance
print("Welcome to Your Bank Account System!")
# If statements for first screen
def options_1(self):
ch = int(input("1. Create an Account\n2. Log into Your Account\nEnter a Choice: "))
if ch == 1:
self.create()
if ch == 2:
self.Log_in()
def options_2(self):
ch= int(input("1. Withdraw Money from Your Account\n2. Deposit Money to Your Account\nEnter a Choice: "))
if ch == 1:
self.withdraw()
if ch == 2:
self.deposit()
# Function to Create an Account
def create(self):
user_create_input = str(input("Enter a Username:"))
pin_create_input = int(input("Enter a Pin Number:" ))
print("Account successfully created!")
# Function to Log into Account
def Log_in(self):
user_input = str(input("Enter your Username:"))
pin_input = int(input("Enter your Pin Number:"))
print("Welcome", user_input, "!")
# Function to Deposit Money
def deposit(self):
amount=float(input("Enter the amount you want to deposit: "))
self.balance += amount
print("Amount Deposited: ",amount)
# Function to Withdraw Money
def withdraw(self):
amount = float(input("Enter the amount you want to withdraw: "))
if self.balance>=amount:
self.balance-=amount
print("You withdrew: ",amount)
else:
print("Insufficient balance ")
def display(self):
print("Net Available Balance=",self.balance)
# PHASE 2 (With Database) SQLite 3
# Define Connection and Cursor
connection = sqlite3.connect('Bank_Users.db')
cursor = connection.cursor()
# Create Users Table
command1 = """ CREATE TABLE IF NOT EXISTS
bank(pin INTEGER PRIMARY KEY, username text )"""
cursor.execute(command1)
# Add to Users/Bank
cursor.execute("INSERT INTO bank VALUES (7620, 'Kailas Kurup')")
cursor.execute("INSERT INTO bank VALUES (4638, 'Bethany Watkins')")
cursor.execute("INSERT INTO bank VALUES (3482, 'John Hammond')")
cursor.execute("INSERT INTO bank VALUES (3493, 'Melissa Rodriguez')")
cursor.execute("INSERT INTO bank VALUES (9891, 'Kevin Le')")
# Get Results / Querying Database
cursor.execute("SELECT username, pin FROM bank")
results = cursor.fetchall()
print(results)
connection.commit()
# Check Database User Info
def Log_in2():
user_input = str(input("Enter your Username:"))
pin_input = int(input("Enter your Pin Number:"))
for row in cursor.fetchall():
if user_input and pin_input in row:
print ("Welcome", user_input, "!")
else:
print("Invalid Login Credentials")
Log_in2()
# Phase 3 (With GUI) Tkinter
# Creating an object of class
self = Bank_Account()
# Calling functions with that class
self.options_1()
self.options_2()
self.display()
QUESTIONS:
The code I wrote underneath the "# Check Database User Info" isn't checking the user input. When a pin or username that is entered which is not in the database should return "Invalid Credentials" How do I fix this?
Why is this UNIQUE Constraint error happening and what do I do to fix it?
if user_input and pin_input in row:
is not the correct way to test of the two inputs are both in row. It's parsed as:
if user_input and (pin_input in row):
Also, you can't call cursor.fetchall() twice for the same query. cursor.fetchall() only fetches the rows that haven't been fetched yet. Once you call it, all rows have been fetched, so there's nothing left to fetch. If you want to loop over the query results multiple times, you should save the result of fetchall() in a list and use that.
But there's no need to loop over all the rows to tell if the user input is in the table. Get the user input first, and use it in the WHERE clause of the query.
def Log_in2():
user_input = str(input("Enter your Username:"))
pin_input = int(input("Enter your Pin Number:"))
cursor.execute("SELECT COUNT(*) FROM bank WHERE username = ? AND pin = ?", (user_input, pin_input))
(count,) = cursor.fetchone()
if count == 1:
print ("Welcome", user_input, "!")
else:
print("Invalid Login Credentials")

How to interate over an output list from fetchone() in mysql database

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()

SQLITE Python cannot change value

I am creating an ATM program that stores all registered users in a database and starts them with $500 in cheqings. I have created a function to deposit money but when I run it I get this error
InterfaceError: Error binding parameter 0 - probably unsupported type.
def depositCheq(userID):
while True:
cheqDeposit = input("How much would you like to deposit?: $")
"""try:
c.execute('UPDATE userAccounts SET cheqBal += ? WHERE id = ?',(int(cheqDeposit)), (userID,))
print("Deposit Complete.\n")
break
except:
print("Could not deposit, error!")"""
c.execute('SELECT cheqBal FROM userAccounts WHERE id = ?', (userID,))
cheqBal = (c.fetchone()) + (cheqDeposit,)
c.execute('UPDATE userAccounts SET cheqBal = ? WHERE id = ?', ([cheqBal], [userID]))
conn.commit()
print("Deposit Complete!\n")
def userMenu():
var = input("1: Deposit\n2: Withdrawl\n3: Check Balance\n4: Log Out\n")
if(int(var) == 1):
userIn = input("1: Cheqings\n2: Savings\n")
userName = input("Enter your username: ")
if(int(userIn) == 1):
database.depositCheq(userName)
elif(int(userIn) == 2):
database.depositSav(userName)

Categories

Resources