I am trying to create a Tkinter based revision application which has a variety of learning options, such as flashcards and an exam-style questions simulator. For the exam questions, each question the user gets right, a new score and a timestamp will be added to a SQLite database called "scores", namely in the columns INT "phy" and DATETIME "phystamp". The score gets updated by adding 20 to the previous record in the "phy", and adding the timestamp of it in the same row in the "phystamp" column. However this program doesn't seem to work, as the record is not appeared to have been successfully inserted into the database. Im getting no errors while running the code.
Any other ways of structuring my code will also help as i've only recently starting coding with python and SQL.
if realanswer == data[randomphysics][2]:
cursor.execute("""SELECT phy FROM scores WHERE phy=(SELECT max(phy) FROM scores)""")
lastrecord = cursor.fetchone()
num = int(''.join(map(str, lastrecord)))
newrecord = num + 20
dt = datetime.now()
physicstime = dt.strftime("%Y-%m-%d %H:%M:%S")
decisionlabel.config(text="Correct Answer!")
cursor.execute("INSERT INTO scores(phy,phystamp)VALUES(?,?)",(newrecord,physicstime))
print(physicstime)
else:
decisionlabel.config(text=f"Incorrect Answer! The correct answer is {data[randomphysics][2]}")
Yes, if you write an insert-statement SQLite will implicitly open a transaction, which you explicitly need to close to make changes to the database. so just follow up your cursor.execute(...) with a connection.commit().
Related
I'm pretty new to python and to flask, and I've been trying to make a program where people can store their receipts. I've got three tables, users, receipts, and user_receipts. im trying to make a page where it lists all the receipts from the user thats logged in, however im just getting blank tables every time, even if the user has entered a receipt.
def list():
global user_id
con = sql.connect("database.db")
con.row_factory = sql.Row
cur = con.cursor()
cur.execute("select * from receipts WHERE receiptID = (select receipt_id from user_receipts WHERE user_id =?)", (user_id,))
rows = cur.fetchall();
return render_template("view_receipts.html",rows = rows)
I know that my methods for naming my variables are not consistent, however I'm aware of which variables belong to which table and I am 100 percent sure they are right.
Im just not sure why its giving me empty tables every time.
I recommend first checking if it is a problem with flask or SQLite first by doing a simple print statement for debugging.
If its a problem with SQLite I recommend to try to modify the variable names and see if there was an error while making the table
if all else fails try to move to something like sqlalchemy so you can get a more reliable database.
I have another question that is related to a project I am working on for school. I have created a PostgreSQL database, with 5 tables and a bunch of rows. I have created a script that allows a user to search for information in the database using a menu, as well as adding and removing content from one of the tables.
When displaying a table in PostgreSQL CLI itself, it looks pretty clean, however, whenever displaying even a simple table with no user input, it looks really messy. While this is an optional component for the project, I would prefer to have something that looks a little cleaner.
I have tried a variety of potential solutions that I have seen online, even a few from stack overflow, but none of them work. Whenever I try to use any of the methods I have seen and somewhat understand, I always get the error:
TypeError: 'int' object is not subscriptable
I added a bunch of print statements in my code, to try and figure out why it refuses to typecast. It is being dumb. Knowing me it is probably a simple typo that I can't see. Not even sure if this solution will work, just one of the examples I saw online.
try:
connection = psycopg2.connect(database='Blockbuster36', user='dbadmin')
cursor = connection.cursor()
except psycopg2.DatabaseError:
print("No connection to database.")
sys.exit(1)
cursor.execute("select * from Customer;")
tuple = cursor.fetchone()
List_Tuple = list(tuple)
print("Customer_ID | First_Name | Last_Name | Postal_Code | Phone_Num | Member_Date")
print(List_Tuple)
print()
for item in List_Tuple:
print(item[0]," "*(11-len(str(item[0]))),"|")
print(item)
print(type(item))
print()
num = str(item[0])
print(num)
print(type(num))
print(str(item[0]))
print(type(str(item[0])))
cursor.close()
connection.close()
I uploaded the difference between the output I get through a basic python script and in the PostgreSQL CLI. I have blocked out names in the tables for privacy reasons. https://temporysite.weebly.com/
It doesn't have to look exactly like PostgreSQL, but anything that looks better than the current mess would be great.
Use string formatting to do that. You can also set it to pad right or left.
As far as the dates use datetime.strftime.
The following would set the padding to 10 places:
print(”{:10}|{:10}".format(item[0], item[1]))
I have started a small project yesterday in python and finally managed to make a database selection function that works, but I was wondering if anybody could tell me if the way I wrote it is good or could eventually end up in multiple problems.
The idea was to make a function that I could call to request/update a table where I would store players data for a small online game I want to create via Python, Pygame and MySQL.Connector-Python
So, here is the function code (I have tried to keep it as clean as possible and as intuitive as I could with my current knowledge of Python which is limited currently as I just picked it back up this week.)
The part I am not sure is the select_statement variable where I do not know for sure if the way I used concatenation is okay or if there is a way as simple and efficient.
def db_select(selection, table):
dbc = db_connect()
if dbc:
print("The SQL connection was successful.")
else:
print("The SQL connection could not be established.")
cur = dbc.cursor()
select_statement = "SELECT * FROM " + table + " WHERE id = %(id)s"
cur.execute(select_statement, {'id': selection})
print(cur.fetchone()[1])
dbc.close()
print("The SQL connection was closed successfully.")
Python has the .format()syntax just for these kinds of situations - handling a dynamic value (such as table being inserted into a string (including SQL queries).
query = "SELECT * FROM {} WHERE id = %(id)s".format(table)
It's cleaner and more reliable in my daily use than the prior approaches such as yours.
I have made a simple for loop program which takes info from the user and updates the Database in sqlite. However my program does not update the DB, it just plainly ignores it. I have tried solutions from all over the net and haven't found anything just yet. I've given just the relevant stuff everything else works just fine.
query ="Alpha"
string = "Beta"
CreateDB = sqlite3.connect('check.db')
querycurs = CreateDB.cursor()
def createTable():
querycurs.execute('''CREATE TABLE Data1
(id INTEGER PRIMARY KEY, q TEXT, info TEXT)''')
createTable()
def addCust(q,info):
querycurs.execute('''INSERT INTO Data1 (q,info)
VALUES (?,?)''',(q,info))
addCust(query,string)
for i in range (1, 5):
string = input('What would you like to enter?: ')
querycurs.execute('UPDATE Data1 SET info =? WHERE q =?',(string,query))
CreateDB.commit()
If you get any syntax errors running this program its fine cause i edited the program so i could put it online. It's only the UPDATE statement you'd need to worry about. Cheerio.
Works fine for me. I suggest you change input() to raw_input() to enforce string data.
I am trying to do a simple fetch using MySQLDB in Python.
I have 2 tables(Accounts & Products). I have to look up Accounts table, get acc_id from it & query the Products table using it.
The Products tables has more than 10 rows. But when I run this code it randomly returns between 0 & 6 rows each time I run it.
Here's the code snippet:
# Set up connection
con = mdb.connect('db.xxxxx.com', 'user', 'password', 'mydb')
# Create cursor
cur = con.cursor()
# Execute query
cur.execute("SELECT acc_id FROM Accounts WHERE ext_acc = '%s'" % account_num ) # account_num is alpha-numberic and is got from preceding part of the program
# A tuple is returned, so get the 0th item from it
acc_id = cur.fetchone()[0]
print "account_id = ", acc_id
# Close the cursor - I was not sure if I can reuse it
cur.close()
# Reopen the cursor
cur = con.cursor()
# Second query
cur.execute("SELECT * FROM Products WHERE account_id = %d" % acc_id)
keys = cur.fetchall()
print cur.rowcount # This prints incorrect row count
for key in keys: # Does not print all rows. Tried to directly print keys instead of iterating - same result :(
print key
# Closing the cursor & connection
cur.close()
con.close()
The weird part is, I tried to step through the code using a debugger(PyDev on Eclipse) and it correctly gets all rows(both the value stored in the variable 'keys' as well as console output are correct).
I am sure my DB has correct data since I ran the same SQL on MySQL console & got the correct result.
Just to be sure I was not improperly closing the connection, I tried using with con instead of manually closing the connection and it's the same result.
I did RTM but I couldn't find much in it to help me with this issue.
Where am I going wrong?
Thank you.
EDIT: I noticed another weird thing now. In the line
cur.execute("SELECT * FROM Products WHERE account_id = %d" % acc_id), I hard-coded the acc_id value, i.e made it
cur.execute("SELECT * FROM Products WHERE account_id = %d" % 322) and it returns all rows
This is not actually an answer, just an attempt to gather together all of the information from a chat with RBK that ruled out a bunch of potential problems, but still didn't come up with an explanation or a solution, in hopes that someone else can spot the problem or think of something else to try.
It's clearly something in this line:
cur.execute("SELECT * FROM Products WHERE account_id = %d" % acc_id)
Especially since putting 322 in place of acc_id fixes everything. (As proven below.)
There are actually two problems with that line, which could be getting in the way. You always want to use DB-API binding rather than string formatting (and the equivalent in any other language), to avoid SQL injection attacks, for correctness of escaping/conversion/etc., and for efficiency. Also, both DB-ABI binding and string formatting require a tuple of arguments, not a single argument. (For legacy reasons, a single argument often works, but sometimes it doesn't, and then it's just confusing to debug… better not to do it.) So, this should be:
cur.execute("SELECT * FROM Products WHERE account_id = %d", (acc_id,))
Unfortunately, after discussing this in chat, and having you try a bunch of things, we were unable to find what's actually wrong here. Summarizing what we tried:
So then, we tried:
cur.execute("SELECT COUNT(*) FROM Devices WHERE account_id = %s" , (333,))
print cur.fetchone()[0]
print 'account id =', acc_id
print type(acc_id)
cur.execute("SELECT COUNT(*) FROM Devices WHERE account_id = %s" , (acc_id,))
print cur.fetchone()[0]
The output was:
10
account id = 333
<type 'long'>
2
When run repeatedly, the last number varies from 0-6, while the first is always 10. There's no way using acc_id could be different from using 333, and yet it is. And just in case one query was somehow "infecting" the next one, without the first two lines, the rest works the same way.
So, there's no way using acc_id could possibly be different than using 333. And yet, it is.
At some point during the chat we apparently moved from Products to Devices, and from 322 to 333, but regardless, the tests shown above were definitely done exactly as shown, and returned different results.
Maybe he has a buggy or badly-installed version of MySQLDb. He's going to try looking for a newer version, or one of the other Python MySQL libraries, and see if it makes a difference.
My next best guess at this point is that RBK has inadvertently angered some technologically-sophisticated god of mischief, but I can't even think of one of those off the top of my head.
I sort of figured out the problem. It was silly at the end. It was a race condition!
This is how my actual code was organized :
Code Block 1
{code which calls an API which creates an entry in Accounts table &
Creates corresponding entries in Product table(10 entries)}
......
Code Block2
{The code I had posted in my question}
The problem was that the API(called in Code Block 1) took a few seconds to add 10 entries into the Product table.
When my code(Code Block 2) ran a fetch query, all the 10 rows were not added and hence fetched somewhere between 0 to 6 rows(how much ever was added at that time).
What I did to solve this was made the code sleep for 5 seconds before I did the SQL queries:
Code Block 1
time.sleep(5)
Code Block 2
The reason why it worked when I hard coded the acc_id was that, the acc_id which I hard-coded was from a precious execution(each run returns a new acc_id).
And the reason why it worked while stepping through a debugger was that manually stepping acted like giving it a sleep time.
It is a lesson for me to know a little about the inside working of APIs(even though they are supposed to be like a black box) and think about race conditions like this, the next time I come across similar issues.