Have a program that recieves a list of player names and results. Then trys to add them to a SQL DB. If the player name is already on the list I want it to update there Score by adding there current score to the stored one. I'm trying to do this by using the ON DUPLICATE KEY UPDATE statement but I'm unsure how to tell it to use the value. Here is my code.
from mysql.connector.cursor import MySQLCursorPrepared
print(playerNames ,playerScore )
try:
#MariaDB Connection
con = mysql.connector.connect(port=5004,user='root',password='password',host='localhost',database='scoreboard')
records_to_insert = [ (playerNames[0],playerScore[0]) ,
(playerNames[1],playerScore[1]),
(playerNames[2],playerScore[2]) ,
(playerNames[3],playerScore[3])
]
sql_insert_query = " INSERT INTO results (Player, Score) VALUES (%s,%s) ON DUPLICATE KEY UPDATE Score = VALUES(Score) + %s; "
myCursor = con.cursor()
myCursor.executemany(sql_insert_query, records_to_insert)
con.commit()
I know the issue is with using "= VALUES(Score) + %s" but I'm not sure of how else to tell it what value I want to use there. Any advice would be greatly appreciated.
You can simply use this expression:
INSERT INTO results (Player, Score)
VALUES (%s, %s)
ON DUPLICATE KEY UPDATE Score = VALUES(Score) + Score;
Notes:
This assumes that you have a unique index on Player (or better yet, it is the primary key).
You should learn to use SQL parameters for passing in values, rather than string substitution.
You might want to declare Score to be NOT NULL to ensure that it always has reasonable values.
sql_insert_query = " INSERT INTO results (Player, Score) VALUES {0},{1}) ON DUPLICATE
KEY UPDATE Score = VALUES(Score) + {1}; ".format(playerNames[0],playerScore[1])
Related
I'm a total Noob and don't know how I can assign variables to the data returned from a SQL Query so that I can then manipulate it. The example below captures random data and not the results from the SQL Query.
I'm using the Replit website with sqlite3.
connect_SQL.execute(""" SELECT MAX(last),exchange from MY_TABLE WHERE base="XRP" and target="EUR" """)
Sell_on=connect_SQL.fetchall()
Sell_price=last_price
Sell_exchange=exchange
print ("A: ", Sell_price , " B: ", Sell_exchange) # This doesnt work wrong value
Print (Sell_on) # give output like [(0.3786567, 'EXMO') but I can assign variables to the price/exchange
All Help is appreciated!
The Price and Exchange details contained in Sell_on are correct, but combined into one output [(0.3786567, 'EXMO') I want to break this down and assign to two different variables, assigning one to the price (0.3786567) and the other to the exchange ('EXMO').
I'm a bit new to the whole Python + DB interactions and I have encountered some issues while trying to insert into a table using subqueries. At this point I imagine it's only a problem of syntax/missing parentheses/missing exclamation marks/etc but I can't seem to be able to figure it out by myself so maybe a fresh eye could help with the issue.
This is the query I am trying to run :
self.cur.execute("INSERT INTO game_genre (id_game, id_genre) VALUES (( SELECT gd.id_game from game_details gd where gd.title like %s, ( "%" + x + "%" , )) , (SELECT g.id_genre from genres g where g.title_genre like %s, ("%" + genre + "%",))"))
where "x" and "genre" are variables
I have tested the queries independently (outside of the insert) and they return the expected result
Could someone shed some divine light onto this?? Thanks
It looks like you're trying to parameterize your query, but you've stuck two different parameter lists into your query as postgres code instead of just one after your query as python code. It's always a good idea to format your code so that the overall structure jumps out at you.
Try:
self.cur.execute("""
INSERT INTO game_genre (id_game, id_genre)
VALUES (
(SELECT gd.id_game FROM game_details gd WHERE gd.title LIKE %s),
(SELECT g.id_genre FROM genres g WHERE g.title_genre LIKE %s))
""", ("%" + x + "%", "%" + genre + "%"))
See http://initd.org/psycopg/docs/usage.html for more details on query parameterization. In particular, note that execute() takes a query with a bunch of %ss, and then a parameter list with one value for each %s. Using """ around every query is highly recommended, in part for readability, and in part because it will prevent you from having to escape " and ' characters.
query = "SELECT serialno from registeredpcs where ipaddress = "
usercheck = query + "'%s'" %fromIP
#print("query"+"-"+usercheck)
print(usercheck)
rs = cursor.execute(usercheck)
print(rs)
row = rs
#print(row)
#rs = cursor.rowcount()
if int(row) == 1:
query = "SELECT report1 from registeredpcs where serialno = "
firstreport = query + "'%s'" %rs
result = cursor.execute(firstreport)
print(result)
elif int(row) == 0:
query_new = "SELECT * from registeredpcs"
cursor.execute(query_new)
newrow = cursor.rowcount()+1
print(new row)
What I am trying to do here is fetch the serialno values from the db when it matches a certain ipaddress. This query if working fine. As it should the query result set rs is 0. Now I am trying to use that value and do something else in the if else construct. Basically I am trying to check for unique values in the db based on the ipaddress value. But I am getting this error
error: uncaptured python exception, closing channel smtpd.SMTPChannel connected
192.168.1.2:3630 at 0x2e47c10 (**class 'TypeError':'int' object is not
callable** [C:\Python34\lib\asyncore.py|read|83]
[C:\Python34\lib\asyncore.py|handle_read_event|442]
[C:\Python34\lib\asynchat.py|handle_read|171]
[C:\Python34\lib\smtpd.py|found_terminator|342] [C:/Users/Dev-
P/PycharmProjects/CR Server Local/LRS|process_message|43])
I know I am making some very basic mistake. I think it's the part in bold thats causing the error. But just can't put my finger on to it. I tried using the rowcount() method didn't help.
rowcount is an attribute, not a method; you shouldn't call it.
"I know I am making some very basic mistake" : well, Daniel Roseman alreay adressed the cause of your main error, but there are a couple other mistakes in your code:
query = "SELECT serialno from registeredpcs where ipaddress = "
usercheck = query + "'%s'" % fromIP
rs = cursor.execute(usercheck)
This part is hard to read (you're using both string concatenation and string formatting for no good reason), brittle (try this with `fromIP = "'foo'"), and very very unsafe. You want to use paramerized queries instead, ie:
# nb check your exact db-api module for the correct placeholder,
# MySQLdb uses '%s' but some other use '?' instead
query = "SELECT serialno from registeredpcs where ipaddress=%s"
params = [fromIP,]
rs = cursor.execute(query, params)
"As it should the query result set rs is 0"
This is actually plain wrong. cursor.execute() returns the number of rows affected (selected, created, updated, deleted) by the query. The "resultset" is really the cursor itself. You can fetch results using cursor.fetchone(), cursor.fetall(), or more simply (and more efficiently if you want to work on the whole resultset with constant memory use) by iterating over the cursor, ie:
for row in cursor:
print row
Let's continue with your code:
row = rs
if int(row) == 1:
# ...
elif int(row) == 0:
# ...
The first line is useless - it only makes row an alias of rs, and badly named - it's not a "row" (one line of results from your query), it's an int. Since it's already an int, converting it to int is also useless. And finally, unless 'ipadress' is a unique key in your table, your query might return more than one row.
If what you want is the effective value(s) for the serialno field for records matching fromIP, you have to fetch the row(s):
row = cursor.fetchone() # first row, as a tuple
then get the value, which in this case will be the first item in row:
serialno = row[0]
Im creating a python program that connects to mysql.
i need to check if a table contains the number 1 to show that it has connected successfully, this is my code thus far:
xcnx.execute('CREATE TABLE settings(status INT(1) NOT NULL)')
xcnx.execute('INSERT INTO settings(status) VALUES(1)')
cnx.commit()
sqlq = "SELECT * FROM settings WHERE status = '1'"
xcnx.execute(sqlq)
results = xcnx.fetchall()
if results =='1':
print 'yep its connected'
else:
print 'nope not connected'
what have i missed? i am an sql noob, thanks guys.
I believe the most efficient "does it exist" query is just to do a count:
sqlq = "SELECT COUNT(1) FROM settings WHERE status = '1'"
xcnx.execute(sqlq)
if xcnx.fetchone()[0]:
# exists
Instead of asking the database to perform any count operations on fields or rows, you are just asking it to return a 1 or 0 if the result produces any matches. This is much more efficient that returning actual records and counting the amount client side because it saves serialization and deserialization on both sides, and the data transfer.
In [22]: c.execute("select count(1) from settings where status = 1")
Out[22]: 1L # rows
In [23]: c.fetchone()[0]
Out[23]: 1L # count found a match
In [24]: c.execute("select count(1) from settings where status = 2")
Out[24]: 1L # rows
In [25]: c.fetchone()[0]
Out[25]: 0L # count did not find a match
count(*) is going to be the same as count(1). In your case because you are creating a new table, it is going to show 1 result. If you have 10,000 matches it would be 10000. But all you care about in your test is whether it is NOT 0, so you can perform a bool truth test.
Update
Actually, it is even faster to just use the rowcount, and not even fetch results:
In [15]: if c.execute("select (1) from settings where status = 1 limit 1"):
print True
True
In [16]: if c.execute("select (1) from settings where status = 10 limit 1"):
print True
In [17]:
This is also how django's ORM does a queryObject.exists().
If all you want to do is check if you have successfully established a connection then why are you trying to create a table, insert a row, and then retrieve data from it?
You could simply do the following...
sqlq = "SELECT * FROM settings WHERE status = '1'"
xcnx.execute(sqlq)
results = xcnx.fetchone()
if results =='1':
print 'yep its connected'
else:
print 'nope not connected'
In fact if your program has not thrown an exception so far indicates that you have established the connection successfully. (Do check the code above, I'm not sure if fetchone will return a tuple, string, or int in this case).
By the way, if for some reason you do need to create the table, I would suggest dropping it before you exit so that your program runs successfully the second time.
When you run results = xcnx.fetchall(), the return value is a sequence of tuples that contain the row values. Therefore when you check if results == '1', you are trying to compare a sequence to a constant, which will return False. In your case, a single row of value 0 will be returned, so you could try this:
results = xcnx.fetchall()
# Get the value of the returned row, which will be 0 with a non-match
if results[0][0]:
print 'yep its connected'
else:
print 'nope not connected'
You could alternatively use a DictCursor (when creating the cursor, use .cursor(MySQLdb.cursors.DictCursor) which would make things a bit easier to interpret codewise, but the result is the same:
if results[0]['COUNT(*)]':
# Continues...
Also, not a big deal in this case, but you are comparing an integer value to a string. MySQL will do the type conversion, but you could use SELECT COUNT(*) FROM settings WHERE status = 1 and save a (very small) bit of processing.
I recently improved my efficiency by instead of querying select, just adding a primary index to the unique column and then adding it. MySQL will only add it if it doesn't exist.
So instead of 2 statements:
Query MySQL for exists:
Query MySQL insert data
Just do 1 and it will only work if it's unique:
Query MySQL insert data
1 Query is better than 2.
I have a function with a new improved version of the code for automatic table indexing:
def update_tableIndex(self,tableName):
getIndexMySQLQuery = """SELECT numberID
FROM %s;""" % (tableName,)
updateIndexMySQLQuery = """UPDATE %s
SET numberID=%s WHERE numberID=%s;""" % (tableName,)
updateIndex=1
self.cursorMySQL.execute(getIndexMySQLQuery)
for row in self.cursorMySQL:
indexID = row[0]
self.cursorMySQL.execute(updateIndexMySQLQuery,(updateIndex,indexID))
updateIndex+=1
While the query 'getIndexMySQLQuery' works fine with this syntax, the other one 'updateIndexMySQLQuery' doesn't work.
Any hints or suggestion how to get that fixed?
All comments and suggestions are highly appreciated.
Second one doesn't work, because you are using three placeholders inside the query string and provide only one variable for interpolation.
updateIndexMySQLQuery = """UPDATE %s
SET numberID=%%s WHERE numberID=%%s;""" % (tableName,)
This way the string formatting mechanism doesn't expect you to provide 3 values, as the percent signs are "escaped" (shame on me for the first version of the answer).
Use %s to replace the table name in the beginning, but use a question mark to create a parameter replacement.
updateIndexMySQLQuery = """UPDATE %s
SET numberID=? WHERE numberID=?;""" % (tableName,)
...
self.cursorMySQL.execute(updateIndexMySQLQuery,(updateIndex,indexID))
thanks for the input. I just re-did the whole function. Here is how it's working and looks now:
def update_tableIndex(self,tableName,indexName):
getIndexMySQLQuery = """SELECT %s
FROM %s;""" % (indexName,tableName,)
updateIndex=1
self.cursorMySQL.execute(getIndexMySQLQuery)
for row in self.cursorMySQL:
indexID = row[0]
updateIndexMySQLQuery = """UPDATE %s
SET %s=%s WHERE
%s=%s;""" % (tableName,
indexName,updateIndex,
indexName,indexID)
self.cursorMySQL.execute(updateIndexMySQLQuery)
updateIndex+=1
So, the only thing to do is to inform the column name and the table name as parameters. It allows to re-use the code for all other tables in the database.
Hope this can be useful for others too.