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.
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').
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])
Basically what i want to do is return entries from a database based on the user's input and display the records in PyQt4's textBrowser widget.
This is the code:
def url_search(self):
self.browserUrl.append("Look") \\ for testing reasons, works.
items = []
for index in range(self.listUrl.count()):
items.append(self.listUrl.item(index))
conn = sqlite3.connect(directory + '\\CyberConan Databases\\CB Database\\Google Chrome\\Chrome Artifacts.db')
for kw in items:
self.browserUrl.append("it is") \\for testing reasons, works
x = str(kw)
for row in conn.execute("SELECT * FROM urls WHERE ID LIKE ? OR URL LIKE ? OR Title LIKE ? "
"OR Visit_Count LIKE ? OR Typed_Count LIKE ?;",
("'%"+x+"%'", "'%"+x+"%'", "'%"+x+"%'", "'%"+x+"%'", "'%+x+%'")):
self.browserUrl.append("working") \\ for testing reasons, does not work
self.browserUrl.append(str(row[0]))
self.browserUrl.append(str(row[1]))
self.browserUrl.append(str(row[2]))
self.browserUrl.append(str(row[3]))
self.browserUrl.append("working man!") \\ for testing reasons, does not work
self.browserUrl.append(str(row[4]))
self.browserUrl.append(str(row[5]))
So the user would press a Button and this function runs. The only output im getting is:
Look
it is
This output is occurring every time the button is pressed. All the naming is correct. I get no errors. The table does contain what the user is searching for, so there should be output. Note that "it is" appears for as many kw there are in items.
(This is for a graduation project)
okay so I found out what the problem was.
First: the parsing of the string in the select statement was not done correctly.
Second: when I was returning the items from the list, i was returning their "locations" and not the strings themselves.
This is the solved code for anyone who may have run into a similar issue:
def url_search(self):
items = []
for index in range(self.listUrl.count()):
thing = self.listUrl.item(index)
items.append(thing.text())
conn = sqlite3.connect(directory + '\\CyberConan Databases\\CB Database\\Google Chrome\\Chrome Artifacts.db')
for kw in items:
x = str(kw)
for row in conn.execute("SELECT * FROM urls WHERE ID LIKE ? OR URL LIKE ? OR Title LIKE ? "
"OR Visit_Count LIKE ? OR Typed_Count LIKE ?;",
("%"+x+"%", "%"+x+"%", "%"+x+"%", "%"+x+"%", "%"+x+"%")):
self.browserUrl.append(str(row))
conn.close()
I would like to have the row number as a column of my queries. Since I am using MySql, I cannot use the built-in func.row_number() of SqlAlchemy. The result of this query is going to be paginated, therefore I would like to keep the row number before the split happen.
session.query(MyModel.id, MyModel.date, "row_number")
I tried to use an hybrid_property to increment a static variable inside MyModel class that I reset before my query, but it didn't work.
#hybrid_property
def row_number(self):
cls = self.__class__
cls.row_index = cls.row_index + 1
return literal(self.row_index)
#row_number.expression
def row_number(cls):
cls.row_index = cls.row_index + 1
return literal(cls.row_index)
I also tried to mix a subquery with this solution :
session.query(myquery.subquery(), literal("#rownum := #rownum + 1 AS row_number"))
But I didn't find a way to make a textual join for (SELECT #rownum := 0) r.
Any suggestions?
EDIT
For the moment, I am looping on the results of the paginated query and I am assigning the calculated number from the current page to each row.
SQLAlchemy allows you to use text() in some places, but not arbitrarily. I especially cannot find an easy/documented way of using it in columns or joins. However, you can write your entire query in SQL and still get ORM objects out of it. Example:
query = session.query(Foobar, "rownum")
query = query.from_statement(
"select foobar.*, cast(#row := #row + 1 as unsigned) as rownum"
" from foobar, (select #row := 0) as init"
)
That being said, I don't really see the problem with something like enumerate(query.all()) either. Note that if you use a LIMIT expression, the row numbers you get from MySQL will be for the final result and will still need to have the page start index added. That is, it's not "before the split" by default. If you want to have the starting row added for you in MySQL you can do something like this:
prevrow = 42
query = session.query(Foobar, "rownum")
query = query.from_statement(sqlalchemy.text(
"select foobar.*, cast(#row := #row + 1 as unsigned) as rownum"
" from foobar, (select #row := :prevrow) as init"
).bindparams(prevrow=prevrow))
In this case the numbers will start at 43 since it's pre-incrementing.
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.