I would be grateful to know what is the easiest way to diagnose this error, as it does not seem to be easy to display what SQL is being executed via pyodbc.
My stored procedure looks like this:
ALTER PROCEDURE [dbo].[s_populate_Test_sp]
#TestDateTime DATETIME,
#TestInt INT,
#TestMoney MONEY,
#TestVarChar500 VARCHAR(500),
#TestFloat FLOAT
AS
SET NOCOUNT ON
INSERT INTO [dbo].[tbl_Test_sp2] (test_datetime, test_int, test_money, test_varchar500, test_float)
VALUES (#TestDateTime, #TestInt, #TestMoney, #TestVarChar500, #TestFloat)
I can execute this stored procedure once successfully using raw text (the commented code below), but I am having difficulty with executemany:
import os
import pyodbc
import datetime
def test_sp():
# Constants
dir_path = os.path.dirname(os.path.realpath(__file__))
# Connect
server = 'xxx'
db2 = 'xxx'
conn_str = 'DRIVER={SQL Server};SERVER=' + server + \
';DATABASE=' + db2 + ';Trusted_Connection=yes'
conn=pyodbc.connect(conn_str, autocommit=False)
cursor = conn.cursor()
cursor.fast_executemany = True
for row in range(10000):
# sql = '''EXEC [dbo].[s_populate_Test_sp] #TestDateTime = '2020-01-01 13:00',
# #TestInt = 999,
# #TestMoney = '£12.34',
# #TestVarChar500 = 'Hello My Name is Jon',
# #TestFloat = 1.234567
# '''
# cursor.execute(sql)
sql = '''exec s_populate_Test_sp (#TestDateTime = ?, #TestInt = ?, #TestMoney = ?, #TestVarChar500 = ?, #TestFloat = ?)'''
values = ['2020-01-01 13:00', 999, '£12.34', 'Hello My Name is Jon', 1.234567]
cursor.executemany(sql, [values])
conn.commit()
if __name__ == '__main__':
test_sp()
Unfortunately this yields a rather cryptic error message:
ProgrammingError: ('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near '#TestDateTime'. (102) (SQLExecute); [42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Statement(s) could not be prepared. (8180)")
I can't find a way of displaying the SQL before it gets executed, so it's all a bit trial and error at the moment.
Many thanks
Per the comments, the answer was to remove the parentheses, the £ sign and use a datetime.datetime object:
sql = '''exec s_populate_Test_sp #TestDateTime = ?, #TestInt = ?, #TestMoney = ?, #TestVarChar500 = ?, #TestFloat = ?'''
values = [datetime.datetime.now(), 999, 12.34, 'Hello My Name is Jon', 1.234567]
It is frustrating that it is so slow. Over my firm's VPN it can do 400 records per minute and on a virtual machine close to the server it can do 9,000 records per minute. I suspect this is one of the limitations of pyodbc and SQL Server, and I will have to do bcp or something like that for larger datasets.
Related
import cursor as cursor
import requests
import pprint
import pyodbc
:
conn = pyodbc.connect('Driver={SQL Server};'
'Server=MY-PC-PC;'
'Database=test;'
'Trusted_Connection=yes;')
def read(conn):
print("Read")
cursor = conn.cursor()
cursor.execute('select * FROM test.dbo.books')
for row in cursor:
print(f'row = {row}')
print()
r = requests.get('https://5f97076911ab98001603b6d0.mockapi.io/api/v1/books')
# pprint.pprint(r.json()) #to print all the data
# pprint.pprint(r.json()[1]['author']) #to print user number 2 data
print(r.json()[1]['author'])
cursor = conn.cursor()
for i in range(50):
cursor.execute("INSERT INTO dbo.books (id, createdAt, title, author, imageUrl) "
"VALUES (r.json[i] ,r.json()[i]['createdAt'],r.json()[i]['title'], r.json()[i]['author'],r.json()[i]['imageUrl'] )")
conn.commit();
read(conn);
read(conn)
cursor.close()
I keep getting this error:
Traceback (most recent call last):
File "C:/Users/MY-PC/PycharmProjects/pythonProject2/py.py", line 40, in
cursor.execute("INSERT INTO dbo.books (id, createdAt, title, author, imageUrl) "
pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near 'i'. (102) (SQLExecDirectW)")
Process finished with exit code 1
You are not using "i" or "r" as variables there, but as simple text. Try using a fstring, which would be putting an f before the "" and using {} to use your variables, as I do in this example:
name = "MyName"
print(f"Hello {name}")
I am attempting to create a program that reads 3 sensors from a raspberry pi sense hat, and insert those values into a sql database, using python. When I execute the program, no errors are given, but when I try to select the data using python, or even going into the database itself, the data is nowhere to be found, I believe the data isn't being properly written. How would I go about correcting this?
import sqlite3
import datetime
from sense_hat import SenseHat
sense = SenseHat()
sensePressure = int(sense.get_pressure())
senseTemp = int(sense.get_temperature() * 1.8 + 32 - 18.85)
senseHumidity = int(sense.get_humidity())
currDateTime = datetime.datetime.now()
COUNT = 1
conn = sqlite3.connect('sense.db')
c = conn.cursor()
c.execute("INSERT INTO atmos (ITEM, DATETIME, TEMPERATURE, HUMIDITY, PRESSURE) VALUES (?, ?, ?, ?,
?)", (COUNT, currDateTime, senseTemp, sensePressure, senseHumidity))
conn.commit()
conn.close()
If you are writing to any SQL database, you will be better of using the pyodbc library it is quite effective and very easy to use :
import pyodbc
connection = pyodbc.connect('Driver={SQL Server};'
'Server=server_name;'
'Database=db_name;'
'Trusted_Connection=yes;')
cursor = connection.cursor()
cursor.execute("INSERT INTO atmos (ITEM, DATETIME, TEMPERATURE, HUMIDITY, PRESSURE)
VALUES (?, ?, ?, ?, ?)", COUNT, currDateTime, senseTemp,
sensePressure, senseHumidity)
I am trying to execute the following script. but I don't get neither the desired results nor a error message ,and I can't figure out where I'm doing wrong.
import pyodbc
cnxn = pyodbc.connect("Driver={SQL Server Native Client 11.0};"
"Server=mySRVERNAME;"
"Database=MYDB;"
"uid=sa;pwd=MYPWD;"
"Trusted_Connection=yes;")
cursor = cnxn.cursor()
cursor.execute('select DISTINCT firstname,lastname,coalesce(middlename,\' \') as middlename from Person.Person')
for row in cursor:
print('row = %r' % (row,))
any ideas ? any help is appreciated :)
You have to use a fetch method along with cursor. For Example
for row in cursor.fetchall():
print('row = %r' % (row,))
EDIT :
The fetchall function returns all remaining rows in a list.
If there are no rows, an empty list is returned.
If there are a lot of rows, *this will use a lot of memory.*
Unread rows are stored by the database driver in a compact format and are often sent in batches from the database server.
Reading in only the rows you need at one time will save a lot of memory.
If we are going to process the rows one at a time, we can use the cursor itself as an interator
Moreover we can simplify it since cursor.execute() always returns a cursor :
for row in cursor.execute("select bla, anotherbla from blabla"):
print row.bla, row.anotherbla
Documentation
I found this information useful to retrieve data from SQL database to python as a data frame.
import pandas as pd
import pymssql
con = pymssql.connect(server='use-et-aiml-cloudforte-aiops- db.database.windows.net',user='login_username',password='login_password',database='database_name')
cursor = con.cursor()
query = "SELECT * FROM <TABLE_NAME>"
cursor.execute(query)
df = pd.read_sql(query, con)
con.close()
df
import mysql.connector as mc
connection creation
conn = mc.connect(host='localhost', user='root', passwd='password')
print(conn)
#create cursor object
cur = conn.cursor()
print(cur)
cur.execute('show databases')
for i in cur:
print(i)
query = "Select * from employee_performance.employ_mod_recent"
emp_data = pd.read_sql(query, conn)
emp_data
I'm using pyodbc together with QODBC to construct an ODBC query.
I'm having trouble inserting datestamp parameters. Here you can see the escalation starting from the literal version (1) to string-format version (2) to error-state versions. (Note DateFrom & DateTo):
sql = "sp_report ProfitAndLossStandard show Amount_Title, Text, Label, Amount parameters DateFrom = {d'2018-02-12'}, DateTo = {d'2018-02-18'}, SummarizeColumnsBy='TotalOnly', ReturnRows='All'"
sql = "sp_report ProfitAndLossStandard show Amount_Title, Text, Label, Amount parameters DateFrom = %s, DateTo = %s, SummarizeColumnsBy='TotalOnly', ReturnRows='All'" % (q_startdate, q_enddate)
Subsequent attempts with the insertion syntax ?, cursor.execute(sql, (q_startdate), (q_enddate)) and the variables:
q_startdate = ("{d'%s'}" % dates[0])
q_enddate = ("{d'%s'}" % dates[1])
sql = "sp_report ProfitAndLossStandard show Amount_Title, Text, Label, Amount parameters DateFrom = ?, DateTo = ?, SummarizeColumnsBy='TotalOnly', ReturnRows='All'"
>>> ('HY004', '[HY004] [Microsoft][ODBC Driver Manager] SQL data type out of range (0) (SQLBindParameter)')
q_startdate = (dates[0])
q_enddate = (dates[1])
sql = "sp_report ProfitAndLossStandard show Amount_Title, Text, Label, Amount parameters DateFrom = {d'?'}, DateTo = {d'?'}, SummarizeColumnsBy='TotalOnly', ReturnRows='All'"
>>> ('42000', "[42000] [QODBC] [sql syntax error] Expected lexical element not found: = {d'?'} (11015) (SQLPrepare)")
Reading the pyodbc Wiki page on inserting data, I don't read about any speed bumps with insertion strings. This must have something to do with how pyodbc processes (escapes) the datestamp.
How do you parameterize datestamp--Especially with the qodbc flavor of datestamp.
It is almost never necessary to use ODBC escape sequences like {d'2018-02-12'} in a pyodbc parameterized query. If the parameter value is a true Python date object
q_startdate = date(2018, 2, 12)
then pyodbc will inform the ODBC driver that the parameter value is a SQL_TYPE_DATE as shown in the ODBC trace log
[ODBC][2984][1532535987.825823][SQLBindParameter.c][217]
Entry:
Statement = 0x1f1a6b0
Param Number = 1
Param Type = 1
C Type = 91 SQL_C_TYPE_DATE
SQL Type = 91 SQL_TYPE_DATE
Col Def = 10
Scale = 0
Rgb Value = 0x1f3ac78
Value Max = 0
StrLen Or Ind = 0x1f3ac58
and we can just use a bare parameter placeholder in our SQL command text
... parameters DateFrom = ?, ...
I have SQl statement List, when running the a single statement it work running the loop it gives:
pyodbc.ProgrammingError: ('42000', "[42000] [MySQL][ODBC 5.1 Driver][mysqld-5.5.8]You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Sql_2' at line 1 (1064) (SQLExecDirectW)")
SQl = """Select something"""
SQl_2 = """Select something"""
SQl_3 = """Select something"""
Sqls= ('Sql','Sql_2','Sql_3')
for x in Sqls:
print x
use = Sql_2
# use = x
cxn = pyodbc.connect('DSN=MySQL;PWD=xxx')
csr = cxn.cursor()
csr.execute(use)
fetch = csr.fetchall()
Your tuple should be
Sqls = (Sql,Sql_2,Sql_3)
instead of
Sqls = ('Sql','Sql_2','Sql_3')
You should additionally move connecting to the database as well as creating a cursor out of the for-loop, since it's unneeded overhead.
SQl = """Select something"""
SQl_2 = """Select something"""
SQl_3 = """Select something"""
Sqls = (Sql, Sql_2, Sql_3)
cxn = pyodbc.connect('DSN=MySQL;PWD=xxx')
csr = cxn.cursor()
for x in Sqls:
print x
use = Sql_2
# use = x
csr.execute(use)
fetch = csr.fetchall()