Python MYSQL multiple statement execution issue - python

Suppose I have this multiple-process Python-MySql query:
self.calculateLeadTime = ("""SET #lastDate = (SELECT sessionDate FROM stock
WHERE product = (%s)
ORDER BY stocksessionID DESC LIMIT 1);
SET #secondLastDate = (SELECT sessionDate FROM stock WHERE product = (%s)
ORDER BY stocksessionID DESC LIMIT 1, 1);
SET #leadTime = (SELECT DATEDIFF(#lastDate, #secondLastDate));
SET #lastStockSessionID = (SELECT stocksessionID
FROM stock WHERE product = (%s) ORDER BY stocksessionID DESC LIMIT 1);
UPDATE stock SET leadTime = (#leadTime)
WHERE stocksessionID = #lastStockSessionID;""", (self.productID.get(), self.productID.get(), self.productID.get()))
self.query = self.cur.execute(self.calculateLeadTime, multi=True)
for self.cur in self.results:
print('cursor:', self.cur)
if self.cur.with_rows:
print('result:', self.cur.fetchall())
self.cn.commit()
I am subject to the error:
stmt = operation.encode(self._connection.python_charset)
AttributeError: 'tuple' object has no attribute 'encode'
I have read the MySql Python documentation regarding multi=True when executing multiple SQL statements via Python. However, my implementation does not work. Any ideas?

Currently, you are passing a tuple as first argument in the cursor.execute call when it expects a single scalar query string in first argument and tuple/list of parameters in second argument:
self.calculateLeadTime = """SET #lastDate = (SELECT sessionDate
FROM stock
WHERE product = (%s)
ORDER BY stocksessionID DESC LIMIT 1);
SET #secondLastDate = (SELECT sessionDate
FROM stock WHERE product = (%s)
ORDER BY stocksessionID DESC LIMIT 1, 1);
SET #leadTime = (SELECT DATEDIFF(#lastDate, #secondLastDate));
SET #lastStockSessionID = (SELECT stocksessionID
FROM stock WHERE product = (%s)
ORDER BY stocksessionID DESC LIMIT 1);
UPDATE stock
SET leadTime = (#leadTime)
WHERE stocksessionID = #lastStockSessionID;
"""
self.query = self.cur.execute(self.calculateLeadTime,
params=(self.productID.get(), self.productID.get(), self.productID.get()),
multi=True)
By the way, MySQL supports JOIN in UPDATE statements for a single statement. Run below with two parameters:
UPDATE stock s
INNER JOIN
(SELECT product, MAX(stocksessionID) AS MaxID
FROM stock
WHERE product = %s
GROUP BY product
) agg_id
ON s.stocksessionID = agg_id.MaxID
INNER JOIN
(SELECT product, MAX(sessionDate) As MaxDate
FROM stock
GROUP BY product) max_dt
ON max_dt.product = s.product
INNER JOIN
(SELECT product, MAX(sessionDate) As SecMaxDate
FROM stock
WHERE sessionDate < ( SELECT MAX(sessionDate)
FROM stock
WHERE product = %s )
GROUP BY product
) sec_max_dt
ON max_dt.product = max_dt.product
SET leadTime = DATEDIFF(MaxDate, SecMaxDate);

I am unsure, if this will work or counts even as multiple queries, because Multi = true is for multiple Resultsets from SELECTS.
You must add teh data for the %s
self.query = self.cur.execute(self.calculateLeadTime,('product','product','product') , multi=True)

Related

Convert SQL to peewee

How to convert this to peewee query?
_, storage, spaceLeft = db.execute('''
SELECT session, storage, storage - count(questID) FROM Hypos
INNER JOIN Quests ON Hypos.hypoID = Quests.hypoID
WHERE Hypos.hypoID = ?1 AND session = ?2
GROUP BY session
UNION SELECT NULL, max(storage), storage FROM Hypos
WHERE Hypos.hypoID = ?1
ORDER BY session DESC LIMIT 1
''', (body.hypo_id, session)
).fetchone()
I don't understand how to create UNION SELECT in peewee. My attempt:
_, storage, spaceLeft = (db_models.Hypos
.select(db_models.Quests.session, db_models.Hypos.storage, db_models.Hypos.storage-fn.COUNT(db_models.Quests.questID))
.join(db_models.Quests, on=(db_models.Hypos.hypoID == db_models.Quests.hypoID), attr='quests')
.where(db_models.Hypos.hypoID==body.hypo_id, db_models.Quests.session==session)
.group_by(db_models.Quests.session)
) | (db_models.Hypos.select(None, fn.MAX(db_models.Hypos.storage), db_models.Hypos.storage)
.where(db_models.Hypos.hypoID==body.hypo_id)
.order_by(db_models.Quests.session.desc()).limit(1)
)
I got :
1st ORDER BY term does not match any column in the result set
without order_by problem is not enough values to unpack (expected 3, got 2)
Try something like this:
lhs = (Hypo
.select(Quest.session, Hypo.storage, Hypo.storage - fn.COUNT(Quest.questID))
.join(Quest)
.where(
(Hypo.hypoID == hypo_id) &
(Quest.session == session))
.group_by(Quest.session))
rhs = (Hypo
.select(Value(None), fn.MAX(Hypo.storage), Hypo.storage)
.where(Hypo.hypoID == hypo_id))
union = (lhs | rhs).order_by(SQL('1').desc()).limit(1)
_, storage, spaceLeft = union.scalar(as_tuple=True)
The resulting SQL:
SELECT "t1"."session", "t2"."storage", ("t2"."storage" - COUNT("t1"."questID"))
FROM "hypo" AS "t2"
INNER JOIN "quest" AS "t1" ON ("t1"."hypo_id" = "t2"."hypoID")
WHERE (("t2"."hypoID" = ?) AND ("t1"."session" = ?))
GROUP BY "t1"."session"
UNION
SELECT ?, MAX("t3"."storage"), "t3"."storage"
FROM "hypo" AS "t3"
WHERE ("t3"."hypoID" = ?)
ORDER BY 1 DESC LIMIT ?

SQLite3 - cross table SELECT queries

What I would like returned is all the seat_ids in the performance table that have a booking_id that matches all the booking_ids where night = 1 in the booking table - is an INNER JOIN the best way to do it?
Or is it more along the lines of """SELECT seat_id FROM performance WHERE booking_id=(SELECT * FROM booking WHERE night = ?""", (night_number))
With the above I get sqlite3.OperationalError: incomplete input error.
connection = sqlite3.connect('collyers_booking_system.db')
cursor = connection.cursor()
cursor.execute(booking_table)
cursor.execute(performance_table)
connection.commit()
booking_table = """CREATE TABLE IF NOT EXISTS
booking(
booking_id TEXT PRIMARY KEY,
customer_id INTEGER,
night INTEGER,
cost REAL,
FOREIGN KEY (customer_id) REFERENCES customer(customer_id)
)"""
performance_table = """CREATE TABLE IF NOT EXISTS
performance(
performance_id TEXT PRIMARY KEY,
seat_id TEXT,
booking_id INTEGER,
FOREIGN KEY (seat_id) REFERENCES seat(seat_id),
FOREIGN KEY (booking_id) REFERENCES booking(booking_id),
)"""
night_number = 1
cursor.execute("""SELECT seat_id FROM performance INNER JOIN booking ON night=?""", (night_number))
booked_seats = cursor.fetchall()
print(booked_seats)
With this I get ValueError: parameters are of unsupported type error.
First, if this is your actual code, there is a typo in the CREATE statement of the table performance.
You must remove the , at the end of:
FOREIGN KEY (booking_id) REFERENCES booking(booking_id),
Then, here:
cursor.execute("""SELECT seat_id FROM performance WHERE booking_id=(SELECT * FROM booking WHERE night = ?""", (night_number))
you missed a closing parenthesis for the sql statement and the subquery may return more than 1 rows, so instead of = you should use IN.
Also, the parameter night_number should passed as a tuple and not just a number, by adding a , inside the paraentheses:
cursor.execute("""SELECT seat_id FROM performance WHERE booking_id IN (SELECT * FROM booking WHERE night = ?)""", (night_number,))
For the join you need a proper ON clause, that links the tables and a , to create the tuple for night_number:
sql = """
SELECT p.seat_id
FROM performance p INNER JOIN booking b
ON b.booking_id = p. booking_id
WHERE b.night=?
"""
cursor.execute(sql, (night_number,))
Both ways, the operator IN and the join will work.
There is another option which sometimes performs better and this is EXISTS:
sql = """
SELECT p.seat_id
FROM performance p
WHERE EXISTS (
SELECT 1 FROM booking b
WHERE b.night=? AND b.booking_id = p.booking_id
)
"""
cursor.execute(sql, (night_number,))
You are comparing a list result with an integer.
this SELECT * FROM booking WHERE night = ? => returns an N rows
and you are wating for an Integer SELECT seat_id FROM performance WHERE booking_id=?.
You have to use something like this :
SELECT seat_id FROM performance WHERE booking_id in (SELECT * FROM booking WHERE night = ?""", (night_number))

How can you pass the same argument twice in a python sqlite3 nested query?

I am trying to pass data into a nested sqlite3 query in python and I get the following error
Incorrect number of bindings supplied. The current statement uses 2, and there are 1 supplied.
x = uid
sql_query1 = """SELECT title FROM movies WHERE addedBy != ? AND mid NOT IN (SELECT mid FROM ratings WHERE uid = ?);"""
data = (uid, x)
cursor.execute(sql_query1, [data])
movies = cursor.fetchall()
I'm guessing the problem might be that x = uid, I have also tried data = (uid, uid) and cursor.execute(sql_query1, [uid]).
Parameters can be explicitly numbered, and the same value used for all instances of a given number:
sql_query1 = """
SELECT title
FROM movies
WHERE addedBy != ?1 AND mid NOT IN (SELECT mid FROM ratings WHERE uid = ?1);"""
cursor.execute(sql_query1, (uid,))
You need to supply as many parameters as you have question marks.
cursor.execute("""
SELECT title
FROM movies
WHERE addedBy != ?
AND mid NOT IN (SELECT mid FROM ratings WHERE uid = ?);
""", [uid, uid])
movies = cursor.fetchall()

SQLALCHEMY: Problem with subquery select, How do i a exact subquery with outerjoin?

I'd like to get a select by a sub-query but, I don't know how I will do that. I searched for every world of internet but not found what i want.
The select is:
SELECT order_status.*
FROM `order`
LEFT OUTER JOIN
(
SELECT *
FROM (
SELECT *
FROM order_status
ORDER BY created_date DESC LIMIT 1) s
WHERE status IN ('NEW', 'FINISH','SENDED','PROCESSING')
) AS order_status ON order.id = order_status.order_id;
my code:
subqy = self.session.query(OrderStatus).order_by(OrderStatus.created_date.desc()).limit(1).subquery()
query = self.session.query(Order).outerjoin(subqy)
return query.filter(and_(in_(conditions))).all()
I'd change the query a little bit to remove one subquery:
SELECT order_status.*
FROM `order`
LEFT OUTER JOIN
(
SELECT *
FROM order_status
ORDER BY created_date DESC
LIMIT 1
) AS order_status ON order.id = order_status.order_id
AND order_status.status IN ('NEW', 'FINISH','SENDED','PROCESSING')
Then the code becomes
subquery = self.session\
.query(OrderStatus)\
.order_by(OrderStatus.created_date.desc())\
.limit(1)\
.subquery()
query = self.session.query(Order)\
.outerjoin(subquery,
(subquery.c.order_id == Order.id)
& subquery_a.c.status.in_(('NEW', 'FINISH','SENDED','PROCESSING')))
return query.all()
I think the thing you missed is that for subqueries, you need to access the columns through table.c.column, instead of Table.column, as you're used to.

Python list of String to SQL IN parameter

I have this query in python:
ssim_group = [S1200,S1300]
query = '''select WIPMessageCnt from waferdata where recipename in (%s) and equipment = ?
and runtype = ? order by stopts desc limit 1''' % (','.join(ssim_grp))
print query
Current result
select WIPMessageCnt from waferdata where recipename in (S1200,S1460) and equipment = ?
and runtype = ? order by stopts desc limit 1
Expected result should be like this
select WIPMessageCnt from waferdata where recipename in ('S1200','S1460') and equipment = ?
and runtype = ? order by stopts desc limit 1
The list should have single qoutation on each element when I try to put them inside the IN parameter on SQL. How can I achieve this?
ssim_group = ['S1200', 'S1300']
query = '''select WIPMessageCnt from waferdata where recipename in ('%s') and equipment = ? and runtype = ? order by stopts desc limit 1''' % ("','".join(ssim_group))

Categories

Resources