Python - failing to update 90% of rows - python

cur.execute("""SELECT match_own_goals.game_id, home_team, away_team, team, time
FROM football.match_own_goals
JOIN football.match_info
ON match_own_goals.game_id = match_info.game_id""")
e = cur.fetchall()
for game in e:
print game
time = game[4]
print type(time)
if game[3] == 1:
team_id = game[1]
else:
team_id = game[2]
cur.execute("""UPDATE football.match_own_goals
SET team_id = %s
WHERE time = %s AND game_id = %s""", (team_id, time, game[0]))
db.commit()
This has updated about 10% of the rows, no idea why. time is actually a float (it doesn't represent a time, more a point in time during a football match e.g. 87mins, 54mins).
Time is definately the problem as when I removed it it worked fine, but I really need it in there for other tables.
What am I doing wrong? Thanks

time = %s this is definitely an issue (you can not properly compare floats with equation operator, read more about it here).

Related

Simple system to track hours worked

I am a total beginner and I think I underestimated my little project.
I am trying to implement a simple attendance system that will give me the hours worked per day and later per month.
I am using a Raspberry pi 3 b+ and RC522 Rfid reader plus 16x2 lcd display.
The data ist stored in a database using MariaDB.
The idea is to use it for student workers in a restaurant to clock in their hours.
The employees still write down their hours, but if it works it could replace the paperwork, we will see.
I know that there will be some concerns about legality, but thats up for the lawyers once I am done.
However my issue is, that right now I am unable to clock in and clock out multiple users.
It does work for one user.
If I clock in User 1 it waits until there is a new clock out info, doesn't matter which user it is.
So user 1 clock in, user 2 wants to clock in but he is registered to clock out and only then the database entry is transferred. I think it somehow would need to update the entries instantly.
I think you can get the idea from the picture
phpMyAdminScreenshot
I think I need to get more info from the database and compare it to what I have.
But I hit a wall now and I am unable to find a solution for my problem.
The code I have right now:
'#!/usr/bin/env python
import time
import datetime
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
import mysql.connector
import drivers
db = mysql.connector.connect(
host="localhost",
user="xxx",
passwd="xxx",
database="attendancesystem"
)
cursor = db.cursor()
reader = SimpleMFRC522()
display = drivers.Lcd()
sign_in = 0
sign_out= 1
try:
while True:
display.lcd_clear()
display.lcd_display_string("Transponder", 1)
display.lcd_display_string("platzieren", 2)
id, text = reader.read()
ts = time.time()
timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
cursor.execute("Select id, name FROM users WHERE rfid_uid="+str(id))
result = cursor.fetchone()
display.lcd_clear()
#if cursor.rowcount >= 1:
#display.lcd_display_string("Willkommen " + result[1], 2)
#cursor.execute("INSERT INTO attendance (user_id) VALUES (%s)", (result[0],) )
if sign_in == 0:
sign_in = (sign_in +1) % 2
sign_out = (sign_out +1) % 2
cursor.execute(f"INSERT INTO attendance (user_id, clock_in, signed_in) VALUES (%s, %s, %s)", (result[0], timestamp, sign_in) )
display.lcd_display_string(f"Angemeldet " + result[1], 1)
elif sign_in == 1:
sign_out = (sign_out +1) % 2
sign_in = (sign_in +1) % 2
cursor.execute(f"INSERT INTO attendance (user_id, clock_out, signed_in) VALUES (%s, %s, %s)", (result[0], timestamp, sign_in) )
display.lcd_display_string (f"Abgemeldet " + result[1], 1)
db.commit()
else:
display.lcd_display_string("Existiert nicht.", 1)
time.sleep(2)
finally:
GPIO.cleanup()'
My idea was to get one more database entry called signed_in and either have it as 0 or as 1.
The signed_in status does update how I want it to, but I don't know how to continue from here.
And I fail to be able to update the table I want to.
My idea was to get user_id and check for this id the last status of the signed_in row, if it is 1 the timestamp will update the clock_out row and signed_in to 0.
If it is 0 and clock_out is not NULL it will start a new row with the clock_in timestamp and switch signed_in to 1.
I didn't have any luck with updating any database values, so I reverted back to INSERT.
I would expect the database would only store events. These events would be from when they touched the RFID. The card would have an ID/employee number.
Processing the database information would allow the calculation of who is on shift and the length of shifts worked etc.
If there was an odd number of entries for an employee then you could assume they are on shift. Even number of entries would mean they have completed the shift.
I don't have your hardware or database so I've created random RFID read events and used sqlite3.
import datetime
import random
import sqlite3
import time
class SimpleMFRC522:
#staticmethod
def read():
while random.randint(0, 30) != 10: # Create some delay/blocking
time.sleep(1)
employee_id = random.randint(0, 5)
return employee_id, f'employee_{employee_id}'
class MyDatabase:
def __init__(self):
self.db = sqlite3.connect('/tmp/my-test.db')
with self.db:
self.db.execute("""
CREATE TABLE IF NOT EXISTS workers (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
empl_no INTEGER,
name TEXT,
tap_event timestamp);
""")
self.db.commit()
def insert_event(self, empl_no, name, timestamp):
sqlite_insert_with_param = """INSERT INTO 'workers'
('empl_no', 'name', 'tap_event')
VALUES (?, ?, ?);"""
self.db.cursor()
self.db.execute(sqlite_insert_with_param, (empl_no, name, timestamp))
self.db.commit()
def worker_in(self, empl_no):
sql_cmd = f"SELECT COUNT(*) FROM workers WHERE empl_no = {empl_no};"
cursor = self.db.execute(sql_cmd)
event_count, = cursor.fetchone()
return event_count % 2 == 1 and event_count > 0
def last_shift(self, empl_no):
sql_cmd = f"""SELECT tap_event FROM
(SELECT * FROM workers WHERE empl_no = {empl_no} ORDER BY tap_event DESC LIMiT 2)
ORDER BY tap_event ASC ;"""
cursor = self.db.execute(sql_cmd)
tap_in, tap_out = cursor.fetchall()
start = datetime.datetime.fromtimestamp(tap_in[0])
end = datetime.datetime.fromtimestamp(tap_out[0])
return end - start
def main():
db = MyDatabase()
reader = SimpleMFRC522()
while True:
empl_no, name = reader.read()
print(f"adding tap event for {name}")
db.insert_event(empl_no, name, datetime.datetime.timestamp(datetime.datetime.now()))
if db.worker_in(empl_no):
print(f"\t{name} has started their shift")
else:
time_worked = db.last_shift(empl_no)
print(f"\t{name} has left the building after {time_worked}")
if __name__ == '__main__':
main()
This gave me a transcript as follows
adding tap event for employee_5
employee_5 has started their shift
adding tap event for employee_0
employee_0 has left the building after 0:02:10.154697
adding tap event for employee_3
employee_3 has left the building after 0:07:02.465903
adding tap event for employee_3
employee_3 has started their shift
adding tap event for employee_2
employee_2 has left the building after 0:06:27.403874
adding tap event for employee_2
employee_2 has started their shift

List index out of range for Python

I have a question regarding the following exercise:
def addstock():
time = datetime.now().strftime("%B %d, %Y")
hour = datetime.now().strftime("%I:%M%p")
query = 'SELECT TotalStock FROM Stocks WHERE name = ? ORDER BY MovementID DESC LIMIT 1'
parameters = (name.get(),)
lastrecord = run_query(query, parameters)
print(float(lastrecord.fetchall()[0][0]))
print(float(quantity.get()))
totalstock = (float(lastrecord.fetchall()[0][0])) + (float(quantity.get()))
query = 'SELECT precio FROM product WHERE name = ?'
precio = run_query(query, parameters)
pricequant = precio.fetchall()[0]
pricequantity = pricequant * quantities
query = 'SELECT precio FROM product WHERE name = ?'
parameters = (name.get(),)
precio = run_query(query, parameters)
priceforall = pricequant * totalstock
In this function, I print lastrecord.fetchall()[0][0] and quantity.get to make sure they are float. So the program prints in that case: 5.0 for lastrecord.fetchall and quantity.get
Up to now, no problem, but when I try to us them up, it gives me an error of List Index Out Of Range, so program do not find the value of lastrecord.fetchall()[0][0] which 2 lines before I was able to print successfully. Can someone explain why?
According to documentation:
The method fetches all (or all remaining) rows of a query result set and returns a list of tuples. If no more rows are available, it returns an empty list.
When you first time used lastrecord.fetchall()[0][0] all the records of lastrecord curser are fetched, so on the second call on totalstock = (float(lastrecord.fetchall()[0][0])) + (float(quantity.get())) there is no more rows left for the curser. If you want to reuse the fetched data, store it, then use it anytime you want, like this:
all_records = lastrecord.fetchall()
// ...
print(float(all_records[0][0]))
// ...
totalstock = (float(all_records[0][0])) + (float(quantity.get()))

Python SQLite3 / Nested cursor.execute

Consider with this following piece of code:
for count in range(28, -1, -1):
crsr.execute("SELECT board, win1, win2 FROM positions WHERE balls = ?", (count,))
response = crsr.fetchall()
print count, len(response)
for possibility in response:
internal = possibility[0]
player = count & 1
victor = 1 - player
opponent = 2 - player
victory = possibility[opponent]
if victory:
crsr.execute("UPDATE positions SET result = ? WHERE board = ?", (victor, internal))
else:
subsequent = derive((internal, count))
for derived in subsequent:
external = reduce(derived[0])
crsr.execute("SELECT result FROM positions WHERE board = ?", (external,))
colour = crsr.fetchall()
if colour[0][0] == player:
victor = player
break
crsr.execute("UPDATE positions SET result = ? WHERE board = ?", (victor, internal))
Consider with the line:
response = crsr.fetchall()
Whenever that there are as much as 107 rows in response, the above statement returns a memory error, even on a system with 8 GB of RAM.
So, I decided that I would change with the following piece of code:
for count in range(28, -1, -1):
crsr.execute("SELECT board, win1, win2 FROM positions WHERE balls = ?", (count,))
response = crsr.fetchall()
print count, len(response)
for possibility in response:
internal = possibility[0]
to:
for count in range(28, -1, -1):
crsr.execute("SELECT COUNT(board) FROM positions WHERE balls = ?", (count,))
sum = crsr.fetchall()
total = sum[0][0]
print count, total
crsr.execute("SELECT board, win1, win2 FROM positions WHERE balls = ?", (count,))
for possibility in range(total):
response = crsr.fetchone()
internal = response[0]
Now that the line:
response = crsr.fetchone()
makes use of the crsr variable for performing with SQLite3 selection query for every iteration of possibility in range(total).
There are already other crsr statements in the same 'for' loop:
crsr.execute("UPDATE positions SET result = ? WHERE board = ?", (victor, internal))
with that statement occurring twice, and
crsr.execute("SELECT result FROM positions WHERE board = ?", (external,)).
with that statement occurring once.
So, whenever the crsr variable from the line: response = crsr.fetchall() changes with every iteration of possibility in range(total), will it not conflict with the other crsr statements already in the same 'for' loop?
We cannot create with other cursor variables for executing with different SQLite3 queries, because crsr is defined by using crsr = connection.cursor() for a specific database file, as soon as it is initialized (whichever is spline.db, in this particular case).
So, I would like to know that if there are any other alternative solutions available for it whichever are efficient enough quite directly.
A result set is part of the cursor object, so whenever you call execute(), any previous query on the same cursor object is aborted. The only way to avoid this is to use fetchall() to read all result rows before the next query is executed.
To be able to execute multiple simultaneous queries, you must use multiple cursors. Simply call connection.cursor() multiple times.
Please note that you must not modify a table that you are still reading from (even if you are using multiple cursors); changed rows might be skipped or read twice by the read cursor. If you cannot use fetchall(), put the results of the first query into a temporary table:
crsr1.execute("CREATE TEMP TABLE temp_pos(board, win1, win2)")
for count in ...:
crsr1.execute("INSERT INTO temp_pos SELECT board, win1, win2 ...")
crsr1.execute("SELECT board, win1, win2 FROM temp_pos")
for row in crsr1:
if ...:
crsr2.execute("UPDATE positions ...")
else:
crsr2.execute("SELECT ... FROM positions ...")
...
crsr1.execute("DELETE FROM temp_pos")
crsr1.execute("DROP TABLE temp_pos")

Python Form/Prompt for SQLite input

In an effort to learn SQL I've been using it at work. I keep a list of every account I work on and the information I gather while working on that particular account. My database has two tables that I update. One is the customer's information and it always gets updated with each new account and the other is an institution table that gets updated sometimes but not every time. These two tables are relational.
As I said, I am new to SQL and have been using the command line to update these tables and it's getting annoying. What I thought would be an easy solution is to run a series of Python prompts that queries the user for each column and then executes the INSERT command at the end of the prompt. It would then ask if I wanted to create an entry for the second table (since I don't always add to this one).
These are my tables.
> create table stu_info (
> id Integer,
> name text,
> CEEB integer,
> degree text,
> terms integer,
> comm text
> );
> create table coll_info (
> CEEB integer,
> name text,
> Accred text,
> Hours text,
> comm text
> );
In Python I figure it'd be easy to just use raw_input() and add an int() around it when required. Then use a loop so that after adding each new row to the database it starts over until I'm done for the day. My problem is I cannot figure out how to execute sqlite commands through Python and I can't figure out how to access the database.
Whenever I run
import sqlite3
conn = sqlite3.connect(stu.db)
c = conn.cursor()
enter code here
I get a NameError: name 'stu' is not defined
Any help? I imagine this is easy and my Google-fu is bad and inexperience has led even good search results to being useless...
It looks like it's as simple as needing quotes.
conn = sqlite3.connect("stu.db")
The error you're getting is because there is no variable stu in scope. So long as "stu.db" is in the working directory then the snippet above should work.
Once I found out, thanks to Jamie, that the filename needs to be in quotes I was able to connect to the database. I then was able to work my way through the problem. Here is my solution:
import sqlite3
conn = sqlite3.connect('stu.db')
c = conn.cursor()
def add_coll():
cceeb = int(raw_input("CEEB:> "))
cname = raw_input("Name:> ")
ccred = raw_input("Accred:> ")
ccal = raw_input("Calendar:> ")
ccomm = raw_input("Comments:> ")
c.execute("INSERT INTO coll VALUES (%d, '%s', '%s', '%s', '%s')" %
(cceeb, cname, ccred, ccal, ccomm))
var = 1 #This creates an infinite loop
while var == 1:
input_stu = raw_input("Add Student?:> ")
if input_stu == 'no' or input_stu == 'n':
add_coll()
else:
id = int(raw_input("ID:> "))
name = raw_input("Name:> ")
ceeb = int(raw_input("CEEB:> "))
deg = raw_input("Degree:> ")
terms = int(raw_input("Terms:> "))
comm = raw_input("Comments:> ")
c.execute("INSERT INTO stu VALUES (%d, '%s', %d, '%s', %d, '%s')" %
(id, name, ceeb, deg, terms, comm))
input_coll = raw_input("Add College?:> ")
if input_coll == 'yes' or input_coll == 'y':
#cceeb = int(raw_input("CEEB:> "))
#cname = raw_input("Name:> ")
#ccred = raw_input("Accred:> ")
#ccal = raw_input("Calendar:> ")
#
#c.execute("INSERT INTO coll VALUES (%d, '%s', '%s', '%s')" %
# (cceeb, cname, ccred, ccal))
add_coll()
conn.commit()

Python - Continue Code Execution After Popping Up MsgBox?

I'm fairly new to Python. Here's a script I have that gathers info from our MySQL server hosting our Helpdesk tickets, and will pop up a message box (using EasyGUI's "msgbox()" function) whenever a new ticket arrives.
The issue is that I want my program to continue processing after the popup, regardless of whether the user clicks "OK" or not, even if that means message boxes could keep popping up over each other and must be dismissed one by one; that would be fine with me.
I looked into threading, and either it doesn't work or I did something wrong and need a good guide. Here's my code:
import MySQLdb
import time
from easygui import *
# Connect
db = MySQLdb.connect(host="MySQL.MyDomain.com", user="user", passwd="pass", db="db")
cursor = db.cursor()
# Before-and-after arrays to compare; A change means a new ticket arrived
IDarray = ([0,0,0])
IDarray_prev = ([0,0,0])
# Compare the latest 3 tickets since more than 1 may arrive in my time interval
cursor.execute("SELECT id FROM Tickets ORDER BY id DESC limit 3;")
numrows = int(cursor.rowcount)
for x in range(0,numrows):
row = cursor.fetchone()
for num in row:
IDarray_prev[x] = int(num)
cursor.close()
db.commit()
while 1:
cursor = db.cursor()
cursor.execute("SELECT id FROM Tickets ORDER BY id DESC limit 3;")
numrows = int(cursor.rowcount)
for x in range(0,numrows):
row = cursor.fetchone()
for num in row:
IDarray[x] = int(num)
if(IDarray != IDarray_prev):
cursor.execute("SELECT Subject FROM Tickets ORDER BY id DESC limit 1;")
subject = cursor.fetchone()
for line in subject:
# -----------------------------------------
# STACKOVERFLOW, HERE IS THE MSGBOX LINE!!!
# -----------------------------------------
msgbox("A new ticket has arrived:\n"+line)
# My time interval -- Checks the database every 8 seconds:
time.sleep(8)
IDarray_prev = IDarray[:]
cursor.close()
db.commit()
You can use Python GTK+
It offers non-modal using
set_modal(False)

Categories

Resources