How to get different values from different tables in Treeview / Tkinter (SQLite)? - python

I've been working with Tkinter and I'm trying to get different columns from different tables in my Treeview, I'm using SQLite as database, in my first table called registers i got different columns idcard, name, surname, cellphone, address, email, etc in my second table named attendance I use to store my entries attendances by ID number I mean I got two entries cardin = entry1 and cardout = entry1 so if one of my entries match with my registers table idcard, it automatically store idcard, timein, timeout, date in my attendance table till that it works so good, but I canĀ“t get the names, surnames columns from my first table registers and store them in my second table attendace same as my idcard, timein, timeout, date (the idcard, names, surnames must match from the first table), I was trying to solve it but I falied, I really have no idea how to do it, any help thanls in advance. have a good day. Here is my code:
def botoningreso():
time = datetime.now().strftime("%I:%M%p")
date = datetime.now().strftime("%d/%m/%Y")
conn = sqlite3.connect('database.db')
c = conn.cursor()
cardin = entry1.get()
cardout = entry2.get()
c.execute('SELECT * FROM registers WHERE idcard = ? OR idcard = ?', (cardin, cardout))
if c.fetchall():
messagebox.showinfo(title='ID Registered', message='Registered Succefully')
c.execute("INSERT INTO attendance (timein, idcard, date) VALUES (?, ?, ?)", (time, cardin, date)) #Here i also wanto to save *names and surnames* from the first table *registers* that match with the idcard column.
conn.commit()
else:
messagebox.showerror(tittle=None, message='Wrong ID card')
c.close()

Assign a variable to fetched data and then index it and proceed:
data = c.fetchall()
if data:
username = data[0][1] # Access username from fetched list
surname = data[0][2] # Access surname
messagebox.showinfo(title='ID Registered', message='Registered Succefully')
c.execute("INSERT INTO attendance (timein,idcard,date,user,sur) VALUES (?,?,?,?,?)", (time,cardin,date,username,surname))
conn.commit()
It is important to assign variable to c.fetchall() as it behaves like a generator object and loses its items once its been used.

Related

Ask for user input and insert in DB in python with sqlite3

At the moment I try to ask the user for input in Python, to enter some information (here: expenseID, expense, categoryID, date). But I do not know were to start. No input validation is necessary at this step.
I managed to access my database and INSERT something manually. I tried several ways of the python input function but cannot use it as a placeholder in the SQL string.
import sqlite3
with sqlite3.connect('Expenses.sqlite') as conn:
# INSERT MANUALLY
script = "INSERT INTO Expense (ExpenseId, Amount, CategoryId, Date) VALUES ('103', '43625.5', '5', '2019-01-20');"
conn.execute(script) # execute the script
conn.commit() # commit changes to the file
# INSERT USER INPUT ???
pass
This is my idea:
with sqlite3.connect('Expenses.sqlite') as conn:
amount = input("What is the amount?")
script = "SELECT * FROM Category;"
conn.execute(script)
print(script)
category = input("What is the category?")
exp_ID = "SELECT LAST ExpenseId FROM Expense);"
date = datetime.date.today()
script = "INSERT INTO Expense (ExpenseId, Amount, CategoryId, Date) VALUES (exp_ID, amount, category, date);"
conn.execute(script)
conn.commit()
pass
Finally I want to achieve that the user is asked for amount of expense, and afterwards for expense category. ExpenseID and date should be added automatically. Date format is year-month-day. Thank you very much for advice.
Use the input function to retrieve the user input
user_input = input("Expense Amount: ")
Then use placeholders with sqlite3
sql = "INSERT INTO TABLE (COLUMN) VALUES (?)"
conn.execute(sql, (user_input,))
**in response to your edit
You need to add placeholders instead of the variable names.
Something like this:
script = "INSERT INTO Expense (ExpenseId, Amount, CategoryId, Date) VALUES (?, ?, ?, ?);"
conn.execute(script, (exp_ID,amount,category,date))

"No such column" when checking for table column

I am creating a table to add data to a database but I am not sure where to create the column for 'emails'. My final aim for this is to be able to enter a username (email) and password and for it to be saved into a database but I am not sure how to do this. Here is my code currently:
import sqlite3
def save_to_database(my_stack, filename = 'stack_database.db'):
conn = sqlite3.connect(filename)
c = conn.cursor()
for row in c.execute('SELECT email FROM sqlite_master WHERE type="table"'):
if row != None:
c.execute("DROP TABLE emails")
c.execute("CREATE TABLE emails(email text,login_date text)")
...
The sqlite_master table does not have a column named email; the entire table structure is contained in the text in the sql column.
You could check for the table name itself (but note that if no row is found, no row is returned, not even an empty one, so it does not make sense to try to handle this with a for loop):
c.execute("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'emails'")
if not c.fetchall():
c.execute('DROP TABLE emails')
However, there is an easier method to ensure that a table is removed, regardless of its previous state:
c.execute('DROP TABLE IF EXISTS emails')

Working with databases with Python: Course registration data in JSON

I am able to get my Python code to run print the desired results, but my problem is with the SQLite table. I was asked to apply this SQL command to the tables:
SELECT hex(User.name || Course.title || Member.role ) AS X
FROM User JOIN Member JOIN Course
ON User.id = Member.user_id AND Member.course_id = Course.id
ORDER BY X
I was able to execute the command in SQLite, but according to the instructions for this project, X is supposed to start with 416 in row one of the results column produced. However, the X I got for row 1 in the results was:
43616C6962736933313030
Here is what I wrote in Python so far:
import sqlite3
import json
#Working with Java and Sqlite
conn = sqlite3.connect('rosterdb.sqlite')
cur = conn.cursor()
cur.executescript('''
DROP TABLE IF EXISTS User;
DROP TABLE IF EXISTS Member;
DROP TABLE IF EXISTS Course;
CREATE TABLE User(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT UNIQUE
);
CREATE TABLE Member(
user_id INTEGER UNIQUE,
course_id INTEGER UNIQUE,
role INTEGER,
PRIMARY KEY (user_id, course_id)
);
CREATE TABLE Course(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
title TEXT UNIQUE
);
''')
#primary key for junction table is composite of both user_id and course_id
fname = raw_input("Enter file name:")
if (len(fname) < 1): fname = 'roster_data.json'
#prompts for file name
str_data = open(fname).read()
json_data = json.loads(str_data)
#opens the file and reads it all
#loads the json data and now is a python list
for entry in json_data:
title = entry[1];
name = entry [0];
role = entry[2];
#["Charley, "sill0", 1] represents the name, course title, and role
print name, title, role
cur.execute('''INSERT or IGNORE INTO User (name)
VALUES (?)''', (name, ))
cur.execute('SELECT id FROM User WHERE name = ?',(name, ))
user_id = cur.fetchone()[0]
cur.execute('''INSERT or IGNORE INTO Course (title)
VALUES (?)''', (title, ))
cur.execute('SELECT id FROM Course WHERE title = ?', (title, ))
course_id = cur.fetchone()[0]
cur.execute('''INSERT or REPLACE INTO Member (user_id, course_id, role)
VALUES (?,?,?)''', (user_id, course_id, role))
#INSERT, SELECT AND FETCHONE STATEMENTS
conn.commit()
Here is the JSON data that I was working with. It is about course registration for students: roster_data.json Here is the link to it:
https://pr4e.dr-chuck.com/tsugi/mod/sql-intro/roster_data.php?PHPSESSID=9addd537cfe55c03585d2bfaa757f6b0
I am not sure if I implemented the "role" key correctly. Thank you for your inputs!
The problem is that you made Member.course_id unique. Thus you can have no more members than courses. Using REPLACE in INSERT or REPLACE into Member hides this error.
Just drop UNIQUE constraint on Member.course and you will get expected result.

Calling three tables to insert data. (sqlite3/python)

I have normalised three tables (Product, ProductType and ProductGender) and I'm looking to call them in my main program so that the user can successfully enter values and the data be stored in the correct table.
Here are the SQL tables being created
def create_product_table():
sql = """create table Product
(ProductID integer,
Name text,
primary key(ProductID))"""
create_table(db_name, "Product", sql)
def create_product_type_table():
sql = """create table ProductType
(ProductID integer,
Colour text,
Size text,
Gender text,
AmountInStock integer,
Source text,
primary key(ProductID, Colour, Size, Gender)
foreign key(Gender) references ProductGender(Gender)
foreign key(ProductID) references Product(ProductID))"""
create_table(db_name, "ProductType", sql)
def create_product_gender_table():
sql = """create table ProductGender
(Gender text,
Price text,
primary key(Gender))"""
create_table(db_name, "ProductGender", sql)
Here are the SQL subroutines
def insert_data(values):
with sqlite3.connect("jam_stock.db") as db:
cursor = db.cursor()
sql = "insert into Product (Name, ProductID) values (?,?)"
cursor.execute(sql,values)
db.commit()
def insert_product_type_data(records):
sql = "insert into ProductType(Amount, Size, Colour, Source) values (?,?,?,?)"
for record in records:
query(sql,record)
def insert_product_gender_data(records):
sql = "insert into ProductGender(Gender, Price) values (?,?)"
for record in records:
query(sql, records)
def query(sql,data): #important
with sqlite3.connect("jam_stock.db") as db:
cursor = db.cursor()
cursor.execute("PRAGMA foreign_keys = ON") #referential integrity
cursor.execute(sql,data)
db.commit()
Below is the code where the user will enter the values.
if ans=="1": #1=to option 'Add Stock'
a = input("Enter Gender: ")
b = float(input("Enter Price: "))
c = int(input("Enter ProductID: "))
d = input("Enter Name: ")
e = input("Enter Size: ")
f = input("Enter Colour: ")
g = input("Enter Source: ")
h = input("Enter Amount: ")
#code calling tables should be here
Help is gratefully appreciated. Seriously not sure how to link the 3 tables with the user's input.
This is what I did before I normalised the database. So the one table in 'Product' would be updated instead of adding an already existing product. Obviously that has changed now, since I've created two new tables but I can't successfully add a product let alone edit one.
def update_product(data): #subroutine for editing stock
with sqlite3.connect("jam_stock.db") as db:
cursor = db.cursor()
sql = "update Product set Name=?, Price=?, Amount=?, Size=?, Colour=?, Source=?, Gender=? where ProductID=?"
cursor.execute(sql,data)
db.commit()
Given the code you show above, and assuming (BIG assumption, see later!) that the user never enters data for existing records, the following code should do it:
query('insert into Product (Name, ProductID) values (?,?)',
[d, c])
query('insert into ProductGender (Gender, Price) values (?,?)',
[a, b])
query('insert into ProductType (ProductID, Colour, Size, Gender, '
AmountInStock, Source) values (?,?,?,?,?,?)',
[c, f, e, a, h, g])
Your use of arbitrary single-letter variable names makes this very hard to follow, of course, but I think I got the correspondence right:-).
Much more important is the problem that you never tell us what to do if the user enters data for an already existing record in one or more of the three tables (as determined by the respective primary keys).
For example, what if Product already has a record with a ProductID of foobar and a Name of Charlemagne; and the user enters ProductID as foobar and a Name of Alexandre; what do you want to happen in this case? You never tell us!
The code I present above will just fail the whole sequence because of the attempt to insert a new record in Product with an already-existing primary key; if you don't catch the exception and print an error message this will in fact crash your whole program.
But maybe you want to do something completely different in such cases -- and there are so many possibilities that we can't just blindly guess!
So please edit your Q to clarify in minute detail what's supposed to happen in each case of primary key "duplication" in one or more table (unless you're fine with just crashing in such cases!-), and the SQL and Python code to make exactly-that happen will follow. But of course we can't decide what the semantics of your program are meant to be...!-)

PyQt ComboBox results not working in MySQL

I am writing a program in which two variables are selected from QCombobBoxes which are populated with results from a MySQL query. I then take these variable and insert them into a MySQLdb statement that inserts the variables into a different MySQL table. The first variable works fine, however on the second I get this error,
TypeError: 'NoneType' object has no attribute '__getitem__'
The code is identical for both variables, with the exception of different names
name = str(self.item_name.currentText())
cur.execute("SELECT item_id FROM Items WHERE name = '%s';"), name
db.commit()
results = cur.fetchone()
item_name = results[0]
personnel_name = str(self.purchaser_name.currentText())
cur.execute("SELECT personnel_id FROM Personnel WHERE name = '%s';"), personnel_name
db.commit()
results = cur.fetchone()
purchaser_id = results[0]
After playing with it, it looks like cur.execute("SELECT item_id FROM Items WHERE name = '%s';"), name is inserting an extra pair of quotation marks around the value that replaces %s Does anyone know why it's doing this and how to stop it? I coded both variables exactly the same, and it seems that name is getting an extra pair of quotes from MySQL
This is code that populates QComboBox:
#Get list of items currently in the database
cur = db.cursor()
cur.execute("SELECT name FROM Items")
db.commit()
results = cur.fetchall()
for name in results:
self.item_name.addItem(name[0])
#Get list of purchaser names
cur.execute("SELECT name FROM Personnel")
db.commit()
results = cur.fetchall()
for name in results:
self.purchaser_name.addItem(name[0])
If I manually insert a variable, it works fine. ex: cur.execute("SELECT item_id FROM Items WHERE name = 'Wire';") Only when I use string formatting with %s does the error occurr.
c.execute("SELECT * FROM sometable WHERE some_condition=?","My Condition")
you should always use the ? placeholders for this kind of thing
[edit]
try 1. cur.execute("SELECT item_id FROM Items WHERE name = '%s';"%(name,))
or 2. cur.execute("SELECT item_id FROM Items WHERE name = %s;", (name,))
from my brief reading, I think that mysql driver will automatically quote %s arguments
my conclusion is that cur.execute("SELECT item_id FROM Items WHERE name = %s;", (name,)) is the most correct way to do this(to avoid injection etc).

Categories