See this stored procedure
-- --------------------------------------------------------------------------------
-- Routine DDL
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `get_followers`(in _user_id int,in _topic_id int,in _type int)
MAIN:BEGIN
SELECT SQL_CALC_FOUND_ROWS follow.user_id
-- COUNT(follow.user_id) AS _topic_idcount
FROM
follow
WHERE
follow.followee_user_id = _user_id
AND (topic_id = _topic_id OR topic_id = 0)
GROUP BY follow.user_id;
SELECT FOUND_ROWS() AS count;
END
When I am use test call to this stored procedure function in mysql workbench it is giving expected result as number of count.
But When I execute python code and dump the json out put of this query it is giving following result.
[{"user_id": 3}, {"user_id": 4}, {"user_id": 5}]
According to my view it is not considering SELECT FOUND_ROWS() AS count; this statement when I call SP form python code as fallow
results = execute_sp("get_followers", [user_id, topic_id, type])
here execut is my custom function.
def execute_sp( sp_name, paramaters ):
#helper method to run sp's and return results
db = Db()
cursor = db.cursor()
cursor.callproc(sp_name,paramaters)
results = cursor.fetchallDict()
cursor.close()
return results
pleas help me to solve this.....
You'll have to try this to see if it works - I can't test it at the moment...
results = cursor.fetchallDict() is returning the first result set, as far as mysqldb is concerned. I.e. the result from the first SELECT. Try adding a nextset() call, like this:
def execute_sp( sp_name, paramaters ):
#helper method to run sp's and return results
db = Db()
cursor = db.cursor()
cursor.callproc(sp_name,paramaters)
cursor.nextset() #Need the second result set in the proc
results = cursor.fetchallDict()
cursor.close()
return results
Let me know if it doesn't work.
Related
I have made a GUI in PyQt5 that allows you to deal with a database. There is an insert button which allows you to insert data into a database and then using a stored procedure whose parameter is a MySQL query in string format, it passes a select query to the stored procedure whose where clause consists of values just entered.
`
def insert(self):
try:
self.table.setRowCount(0)
QEmpID = self.lineEmpID.text() + "%"
QFName = self.lineFName.text() + "%"
QLName = self.lineLName .text() + "%"
QSalary = self.lineSalary.text() + "%"
QTask = self.lineTask.text() + "%"
mydb = mc.connect(host="localhost",username="root",password="",database="Office")
mycursor = mydb.cursor()
selectQuery = "SELECT * From Employee WHERE EmpID like '{}' and FirstName like '{}' and LastName like '{}' and Salary like '{}' and Task like '{}'".format(QEmpID, QFName,QLName,QSalary,QTask)
QEmpID = self.lineEmpID.text()
QFName = self.lineFName.text()
QLName = self.lineLName.text()
QSalary = self.lineSalary.text()
QTask = self.lineTask.text()
insertQuery = "INSERT INTO Employee Values({},'{}','{}',{},'{}')".format(QEmpID,QFName, QLName, QSalary, QTask)
mycursor.execute(insertQuery)
mydb.commit()
insertResult = mycursor.fetchall()
mycursor.callProc('fetchData',[selectQuery])
for result in mycursor.stored_results():
selectResult = result.fetchall()
for row_number,row_data in enumerate(selectResult):
self.table.insertRow(row_number)
for column_number,data in enumerate(row_data):
self.table.setItem(row_number,column_number,QTableWidgetItem(str(data)))
except mc.Error as e:
print(e)
The above is my python code for the insert function which is then connected to the insert button.
`
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `fetchData`(in query1 varchar(1000))
begin
set #q = query1;
PREPARE stmt from #q;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
end$$
DELIMITER ;
The above is my stored procedure which executes a query passed to it in string format.
However, when I type in the record to be inserted into the fields and then press Insert, the following shows up without any tracebacks or error reports in the IDLE Shell:
The thing is, the record does get inserted into the database and I think the issue is with the calling of stored procedure with a select query passed to it and whose result can then be populated into the QTableWidget.
I can't think of anything right now. Help is needed.
Thank you!
I have gone through:
Error "Previous SQL was not a query" in Python?
MSSQL2008 - Pyodbc - Previous SQL was not a query
How to check if a result set is empty?
However none of them have resolved the issue.
The snippet from my db.py file is as follows:
result = cursor.execute(self.sql,self.params)
if result is None:
self.data = []
else:
self.data = [dict(zip([key[0] for key in cursor.description], row)) for row in result.fetchall()]
cnxn.close()
return self.data
This works for every SQL and stored procedure I have thrown at it except for this one
seq = request.form['seq']
s = 'EXEC sp_add ?, ?'
p = (udf.get_username(), int(seq))
l = Conn.testing(db="testingDatabase",sql=s,params=p)
I get the error:
Previous SQL was not a query
The SQL:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE sp_add
#user nvarchar(50),
#seq int
AS
BEGIN
SET NOCOUNT ON;
insert into tblName (userCol,seqCol) VALUES (#user,#seq)
END
GO
The stored procedure runs and the row gets inserted but the error shows up.
What I did instead was:
result = cursor.execute(self.sql,self.params)
cnxn.close()
return str(result)
This returns:
EXEC sp_add ?, ?
Why does it return that? Why does it return the statement I just passed to it?
In my SP, if I tag on a SELECT statement then the issue goes away.
Any suggestions other than the hack just mentioned?
According to the Python Database API PEP 249 specification, the return value of cursor.execute is not defined. So DB-APIs like pyodbc do not need to define consistent return value.
However, specifically for pyodbc, cursor.execute() returns a <pyodbc.Cursor> object which maintains the description attribute if object contains a value but will be None if an action command:
result = cursor.execute(self.sql, self.params)
if result.descripton is None:
self.data = []
else:
self.data = [
dict(zip([key[0] for key in cursor.description], row))
for row in
result.fetchall()
]
cnxn.close()
return self.data # METHODS INSIDE CLASSES DO NOT REQUIRE RETURN
Consider even a ternary operator:
result = cursor.execute(self.sql, self.params)
self.data = (
[
dict(zip([key[0] for key in result.description], row))
for row in result.fetchall()
]
if result.descripton is not None
else []
)
cnxn.close()
return self.data
I think I have the right idea to do this function but I'm not sure why I get
this error when I test it. Can anyone please help me fix this?
cur.execute(q)
sqlite3.ProgrammingError: Incorrect number of bindings supplied. The
current statement uses 1, and there are 0 supplied.
Current Attempt
def find_dept_courses(db, dept):
'''Return the courses from the given department. Use the "LIKE"
clause in your SQL query for the course name.'''
return run_query(db, '''SELECT DISTINCT Course FROM Courses WHERE
Course LIKE (? + 'dept%')''')
Desired output
find_dept_courses('exams.db', 'BIO')
# [('BIOA01H3F',), ('BIOA11H3F',), ('BIOB10H3F',), ('BIOB33H3F',),
# ('BIOB34H3F',), ('BIOB50H3F',), ('BIOC12H3F',), ('BIOC15H3F',),
# ('BIOC19H3F',), ('BIOC32H3F',), ('BIOC37H3F',), ('BIOC50H3F',),
# ('BIOC58H3F',), ('BIOC59H3F',), ('BIOC61H3F',), ('BIOC63H3F',),
# ('BIOD21H3F',), ('BIOD22H3F',), ('BIOD23H3F',), ('BIOD26H3F',),
# ('BIOD33H3F',), ('BIOD48H3F',), ('BIOD65H3F',)]
query function:
def run_query(db, q, args=None):
"""(str, str, tuple) -> list of tuple
Return the results of running query q with arguments args on
database db."""
conn = sqlite3.connect(db)
cur = conn.cursor()
# execute the query with the given args passed
# if args is None, we have only a query
if args is None:
cur.execute(q)
else:
cur.execute(q, args)
results = cur.fetchall()
cur.close()
conn.close()
return results
While using .execute you need to pass the argument as a list or tuple, here is the sample
# This is the qmark style:
cur.execute("insert into people values (?, ?)", (who, age))
Currently, you are using a placeholder but do not pass any parameters. Secondly, you are concatenating placeholder ? with a data value in LIKE expression.
Simply separate query statement and data value and leave ? by itself:
def find_dept_courses(db, dept):
sql = '''SELECT DISTINCT Course FROM Courses WHERE Course LIKE ?'''
return run_query(db, sql, args=(dept+'%',))
Remove the ? and resolve your sql syntax so dept is treated as a variable e.g. sql should evaluate to
SELECT DISTINCT Course FROM Courses WHERE
Course LIKE 'mydept%'
Note you may be susceptible to sql injection with this method and dept is from user input
I have been using Psycopg2 to read stored procedures from Postgres successfully and getting a nice tuple returned, which has been easy to deal with. For example...
def authenticate(user, password):
conn = psycopg2.connect("dbname=MyDB host=localhost port=5433 user=postgres password=mypwd")
cur = conn.cursor()
retrieved_pwd = None
retrieved_userid = None
retrieved_user = None
retrieved_teamname = None
cur.execute("""
select "email", "password", "userid", "teamname"
from "RegisteredUsers"
where "email" = '%s'
""" % user)
for row in cur:
print row
The row that prints would give me ('user#gmail.com ', '84894531656894hashedpassword5161651165 ', 36, 'test ')
However, when I run the following code to read a row of fixtures with a Stored Procedure, I get (what looks to me like) an unholy mess.
def get_from_sql(userid):
conn = psycopg2.connect("dbname=MyDB host=localhost port=5433 user=postgres password=pwd")
fixture_cursor = conn.cursor()
callproc_params = [userid]
fixture_cursor.execute("select sppresentedfixtures(%s)", callproc_params)
for row in fixture_cursor:
print row
The resulting output:
('(5,"2015-08-28 21:00:00","2015-08-20 08:00:00","2015-08-25 17:00:00","Team ",,"Team ",,"Final ")',)
I have researched the cursor class and cannot understand why it outputs like this for a stored procedure. When executing within Postgres, the output is in a perfect Tuple. Using Psycopg2 adds onto the tuple and I don't understand why?
How do I change this so I get a tidy tuple? What am I not understanding about the request that I am making that gives me this result?
I have tried the callproc function and get an equally unhelpful output. Any thoughts on this would be great.
This is because you're SELECTing the result of the function directly. Your function returns a set of things, and each "thing" happens to be a tuple, so you're getting a list of stringified tuples back. What you want is this:
SELECT * FROM sppresentedfixtures(...)
But this doesn't work, because you'll get the error:
ERROR: a column definition list is required for functions returning "record"
The solution is to return a table instead:
CREATE OR REPLACE FUNCTION sppresentedfixtures(useridentity integer) RETURNS TABLE(
Fixture_No int,
Fixture_Date timestamp,
...
) AS
$BODY$
select
"Fixtures"."Fixture_No",
"Fixtures"."Fixture_Date",
...
from "Fixtures" ...
$BODY$ LANGUAGE sql
I have a very large table (374870 rows) and when I run the following code timestamps just ends up being a long int with the value 374870.... I want to be able to grab all the timestamps in the table... but all I get is a long int :S
import MySQLdb
db = MySQLdb.connect(
host = "Some Host",
user = "SOME USER",
passwd = "SOME PASS",
db = "SOME DB",
port = 3306
)
sql = "SELECT `timestamp` from `table`"
timestamps = db.cursor().execute(sql)
Try this:
cur = db.cursor()
cur.execute(sql)
timestamps = []
for rec in cur:
timestamps.append(rec[0])
You need to call fetchmany() on the cursor to fetch more than one row, or call fetchone() in a loop until it returns None.
Consider the possibility that the not-very-long integer that you are getting is the number of rows in your query result.
Consider reading the docs (PEP 249) ... (1) return value from cursor.execute() is not defined; what you are seeing is particular to your database and for portability sake should not be relied on. (2) you need to do results = cursor.fetch{one|many|all}() or iterate over the cursor ... for row in cursor: do_something(row)