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
Related
I write to see how I can get only one data to show by a print when I make a query in python, when I do the query it should only give me a number but I cannot show or access it.
def run_query(self, query, parameters = ()):
with sqlite3.connect(self.db_name) as conn:
cursor = conn.cursor()
result = cursor.execute(query, parameters)
conn.commit()
return result
def get_horarios(self):
query = 'SELECT hora FROM horarios where horario=1'
db_rows = self.run_query(query)
print(db_rows)
To show the first row in the results of the query:
print(db_rows.fetchone())
To show all of the results of the query:
print(db_rows.fetchall())
or
for row in db_rows.fetchall():
print(row)
The query always return a list. To access the first item, you can do:
print(db_rows[0])
Using the following function:
import pyodbc
def execute_side_effect_stmt(sql_stmt: str, params: list):
with get_connection() as conn:
cursor = conn.cursor()
cursor.executemany(sql_stmt, params)
columns = [column[0] for column in cursor.description]
results = cursor.fetchall()
response = []
for row in results:
response.append(dict(zip(columns, row)))
conn.commit()
if not response:
return ''
return response
With the following arguments:
sql = """INSERT INTO dbo.events
(sha, duration)
OUTPUT Inserted.id, Inserted.sha
VALUES (?, ?)"""
params = [('123',1),('456', 2), ('789', 3)]
result = execute_side_effect_stmt(sql, params)
Result only returns the id and sha of the last entry in params. Everything is inserted correctly into the database. Any insights on why only the last insert gives an output would be very welcome.
The reason is that cursor.executemany() executes the SQL statement for each element in params.
As shown in the docs, unless you set cursor.fast_executemany = True, the INSERT statement will be called len(params) times.
With cursor.fast_executemany = True, the result will be a single insert as described here
As described:
Here, all the parameters are sent to the database server in one bundle (along with the SQL statement), and the database executes the SQL against all the parameters as one database transaction. Hence, this form of executemany() should be much faster than the default executemany(). However, there are limitations to it, see fast_executemany for more details.
Your code could be modified to:
import pyodbc
def execute_side_effect_stmt(sql_stmt: str, params: list):
with get_connection() as conn:
cursor = conn.cursor()
cursor.fast_executemany = True
cursor.executemany(sql_stmt, params)
columns = [column[0] for column in cursor.description]
results = cursor.fetchall()
response = []
for row in results:
response.append(dict(zip(columns, row)))
conn.commit()
if not response:
return ''
return response
I'm trying to insert dummy data into a mysql database.
The database structure looks like:
database name: messaround
database table name: test
table structure:
id (Primary key, auto increment)
path (varchar(254))
UPDATED 2 method below, and error.
I have a method to try to insert via:
def insert_into_db(dbcursor, table, *cols, **vals):
try:
query = "INSERT INTO {} ({}) VALUES ('{}')".format(table, ",".join(cols), "'),('".join(vals))
print(query)
dbcursor.execute(query)
dbcursor.commit()
print("inserted!")
except pymysql.Error as exc:
print("error inserting...\n {}".format(exc))
connection=conn_db()
insertstmt=insert_into_db(connection, table='test', cols=['path'], vals=['test.com/test2'])
However, this is failing saying:
INSERT INTO test () VALUES ('vals'),('cols')
error inserting...
(1136, "Column count doesn't match value count at row 1")
Can you please assist?
Thank you.
If you use your code:
def insert_into_db(dbcursor, table, *cols, **vals):
query = "INSERT INTO {} ({}) VALUES ({})".format(table,",".join(cols), ",".join(vals))
print(query)
insert_into_db('cursor_here', 'table_here', 'name', 'city', name_person='diego', city_person='Sao Paulo')
Python returns:
INSERT INTO table_here (name,city) VALUES (name_person,city_person)
Now with this other:
def new_insert_into_db(dbcursor, table, *cols, **vals):
vals2 = ''
for first_part, second_part in vals.items():
vals2 += '\'' + second_part + '\','
vals2 = vals2[:-1]
query = "INSERT INTO {} ({}) VALUES ({})".format(table,",".join(cols), vals2)
print(query)
new_insert_into_db('cursor_here', 'table_here', 'name', 'city', name_person='diego', city_person='Sao Paulo')
Python will return the correct SQL:
INSERT INTO table_here (name,city) VALUES ('diego','Sao Paulo')
Generally in Python you pass a parameterized query to the DB driver. See this example in PyMySQL's documentation; it constructs the INSERT query with placeholder characters, then calls cursor.execute() passing the query, and a tuple of the actual values.
Using parameterized queries is also recommended for security purposes, as it defeats many common SQL injection attacks.
you should print the sql statement which you've generated, that makes it a lot easier to see what's wrong.
But I guess you need quotes ' around string values for your ",".join(vals) (in case there are string values.
So your code is producing
insert into test (path,) values (test.com/test2,);
but it should produce
insert into test (`path`) values ('test.com/test2');
Otherwise try https://github.com/markuman/MariaSQL/ which makes it super easy to insert data to MariaDB/MySQL using pymysql.
Change your query as below
query = "INSERT INTO {} ({}) VALUES ('{}')".format(table, ",".join(cols), "'),('".join(vals))
As you are using join, the variable is expected to be a list but not a string
table = 'test'
cols = ['path']
vals = ['test.com/test2', 'another.com/anothertest']
print(query)
"INSERT INTO test (path) VALUES ('test.com/test2'),('another.com/anothertest')"
Update:
def insert_into_db(dbconnection=None, table='', cols=None, vals=None):
mycursor = dbconnection.cursor()
if not (dbconnection and table and cols and vals):
print('Must need all values')
quit()
try:
query = "INSERT INTO {} ({}) VALUES ('{}')".format(table, ",".join(cols), "'),('".join(vals))
mycursor.execute(query)
dbconnection.commit()
print("inserted!")
except pymysql.Error as exc:
print("error inserting...\n {}".format(exc))
connection=conn_db()
insertstmt=insert_into_db(dbconnection=connection, table='test', cols=['path'], vals=['test.com/test2'])
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 am trying to retrieve a user from my sessions table in the database. In my unit test i get an error:
line 138, in test_session_user
self.assertEqual(nick_from_cookie, nick)
AssertionError: ('Bobalooba',) != 'Bobalooba'
I understand that this is because my code is returning a tuple when the test is comparing my return value against a string therefore it is not matching.
Is there a way for me to do this comparison using the tuple or is their a better way to query the result i need. Below is the table im using aswell as my function:
def session_user(db):
"""try to
retrieve the user from the sessions table
return usernick or None if no valid session is present
"""
cursor = db.cursor()
sessionid = bottle.request.get_cookie(COOKIE_NAME)
usernick = None
if sessionid:
cursor.execute("SELECT usernick FROM sessions WHERE sessionid=?", (sessionid,))
usernick = cursor.fetchone()
return usernick
Use
row = cursor.fetchone()
if row:
usernick, = row
Note the unpacking of the tuple.