PYODBC ProgrammingError: ('42000', "[42000] [Microsoft][Pilote ODBC Microsoft Access] - python

I try to do an update query using a left join on another mdb.
Into a cursor for the first MDB, I execute this query:
update table as ori
left join (select *
from param in "E:/Jeter/param_141114.mdb"
where zone = '1H005') param
on ori.dep_sur = param.dsu_co
set ori.texture = param.textu where mid(ori.type,4,1) in ('0','7','8')
When I launch this query from Microsoft Access, no problem, the query is applied.
When I launch this query from python 2.7 with pyodbc, here my result translated from french:
ProgrammingError ('42000', "[42000] [Microsoft] [ODBC Microsoft Access
Driver] The database engine can not find [E: /Jeter/param_141114.mdb]
'Make sure the name. parameter or alias is valid, he does not
understand character or incorrect punctuation and that it is not too
long. (-1002) (SQLExecDirectW) ")
Some ideas?

Apparently the SELECT ... FROM TableName IN "FileName" ... syntax is not available to ODBC queries from external applications. However, I just tried the following variation and it worked for me (Python 2.7 and pyodbc):
sql = """
update tableau as ori
left join (select *
from [C:/__tmp/test.mdb].param
where zone = '1H005') param
on ori.dep_sur = param.dsu_co
set ori.texture = param.textu
"""
crsr = db.execute(sql)
crsr.commit()

Related

Alter database query with variables using Python

I am trying to execute below SQL query by introducing 2 variables in Python but getting error,
Original Query:
ALTER DATABASE db1 MODIFY (SERVICE_OBJECTIVE = 'DW300');
I want to use variables for db1 and 'DW300'. I have tried below statement in Python and got error.
dwu = 'DW100'
sqlpool = 'db1'
cursor.execute("""ALTER DATABASE ? MODIFY (SERVICE_OBJECTIVE = ?) """, (sqlpool, dwu))
Error: pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Incorrect syntax near '#P1'. (102) (SQLExecDirectW)")
I use sqlite and it accepts this answe.
try the use of fstrings
f"""Alter Database {sqlpool} modify (service objective = {dwu}) """

SQLAlchemy Core - Subquery missing an alias

I was working on a straightforward SQLAlchemy Core (Python 3.x) count unique query using the following code:
table_object = sqlalchemy.Table(table_name, metadata, autoload=True, autoload_with=engine, schema=schema)
agg_fields = [get_column_correct_case(table_object, col) for col in agg_fields]
agg_col_obj = [table_object.c[col] for col in agg_fields]
agg_query = sqlalchemy.select(agg_col_obj).select_from(table_object)\
.group_by(*agg_fields).count()
engine.scalar(agg_query)
While I believe this should be valid SQLAlchemy Core code, its execution returned a PYODBC error:
(pyodbc.ProgrammingError) ('42000', "[42000] [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]
Incorrect syntax near ')'. (102) (SQLExecDirectW);
[42000] [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Statement(s) could not be prepared. (8180)")
The SQL query generated by this code which failed to execute properly was:
[SQL: SELECT count([ACCOUNT]) AS tbl_row_count
FROM (SELECT dbo.history.[ACCOUNT] AS [ACCOUNT], dbo.history.[RTXNNBR] AS [RTXNNBR]
FROM dbo.history
GROUP BY dbo.history.[ACCOUNT], dbo.history.[RTXNNBR])]
Running the query directly in SQL Server, it appears to be failing because the nested select is missing an alias. Is this a bug? If not, how do I fix this code?
I figured out the answer. I was surprised it was necessary, but this can be resolved by giving the query to be counted an alias.
So
agg_query = sqlalchemy.select(agg_col_obj).select_from(table_object)\
.group_by(*agg_fields).count()
becomes:
agg_query = sqlalchemy.select(agg_col_obj).select_from(table_object)\
.group_by(*agg_fields).alias('a').count()
which now works.

How to parameterize pyodbc identifiers in queries safely?

I have written a small tool which migrates data from SQL Server to Postgres.
To make things work, I did it quick and dirty using string concats since I had a lot of other issues to solve and I did not want to bother with the SQL at the time. But now that everything is sorted out, I want to do things porperly in the SQL department.
The unsafe quick and dirty version :
import pyodbc
# this is the bad example DON'T do this
def getDataFromTable(self,table):
"""
Gets all data from the specified Table.
table -- Table name as string
"""
cursor = self.cursor
SQL = f"""SELECT * FROM {table}""" ## DON'T do this
cursor.execute(SQL)
rows = cursor.fetchall()
records = []
for row in rows:
records.append(list(row))
return records
This works perfectly fine, but is a SQL injection waiting to happen.
I want to build something like this (I have omitted the unchanged parts):
...
cursor = self.cursor
SQL = f"""SELECT * FROM ?""" # Use parameters insted of string concats
cursor.execute(SQL, table) # pass parameters to the execute method.
rows = cursor.fetchall()
...
This looks nice an safe, but also does not work. Following error pops up :
pyodbc.ProgrammingError: ('42000', '[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Die #P1-Tabellenvariable muss deklariert werden. (1087) (SQLExecDirectW); [42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Anweisung(en) konnte(n) nicht vorbereitet werden. (8180)')
It's in German but roughly translates to: table variables must be declared, statement could not be prepared.
How can I pass a variable into the execute method to take the identifiers place safely?
You can not have a variable for table name in SQL Server. You can generate a string in python and then execute it.
table_name = 'table1'
query = "Select * from %s" % table_name
Or you can use Dynamic SQL.

How to drop and create database using sql sanitizing

cursor.execute("DROP DATABASE ?", (databasename,))
I am using python3 with pyodbc driver. Only facing issue while create and delete database. other operations like select are working fine.
Getting below error:
pyodbc.ProgrammingError: ('42000', u"[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Incorrect syntax near '#P1'. (102) (SQLExecDirectW)")
In order to sanitize your data you can use SQL Server QUOTENAME to returns a Unicode string with the delimiters added to make the input string a valid SQL Server delimited identifier.
You also need to set autocommit=True in your pyodbc connection to allow dropping of databases.
conn = pyodbc.connect("DRIVER={SQL Server};"
"SERVER="+server+";"
"UID="+username+";"
"PWD="+password,
autocommit=True)
cursor = conn.cursor()
your_database_name = "YOUR_DB_NAME"
sql_drop = (
"DECLARE #sql AS NVARCHAR(MAX);"
"SET #sql = 'DROP DATABASE ' + QUOTENAME(?);"
"EXEC sp_executesql #sql"
)
cursor.execute(sql_drop, your_database_name)

Unable to CREATE DATABASE via PyODBC connection

I am using pyodbc in python 2.7 with MS SQL Server 2008R.
Here is my code for creating a database (the SQL code which works fine in SQL alone, but crash when executed in python)
SQL_command = """
IF EXISTS(SELECT * FROM sys.databases WHERE [name] = 'NewDatabase')
DROP DATABASE NewDatabase
"""
conn.cursor.execute(SQL_command)
SQL_command = """
CREATE DATABASE NewDatabase
ON
(
NAME = 'NewDatabase_data'
, FILENAME='D:\MSSQL\DATA\NewDatabase_data.mdf'
, SIZE = 4096KB
, FILEGROWTH = 4096KB
)
LOG ON
(
NAME = 'NewDatabase_log'
, FILENAME='D:\MSSQL\LOG\NewDatabase_log.ldf'
, SIZE = 4096KB
, FILEGROWTH = 10%
)
COLLATE SQL_Latin1_General_CP1_CI_AS
"""
conn.cursor.execute(SQL_command)
SQL_command = """
ALTER DATABASE
NewDatabase
SET RECOVERY SIMPLE
"""
conn.cursor.execute(SQL_command)
However, I've got following error message:
pyodbc.ProgrammingError: ('42000', '[42000] [Microsoft][ODBC SQL
Server Driver][SQL Server]CREATE DATABASE statement not allowed within
multi-statement transaction. (226) (SQLExecDirectW)')
May I know what is wrong with my code?
Many thanks.
====================================================================================
So, after taking the advice from #Matthias, I've executed commit after the drop database, then the error message became:
pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC SQL
Server Driver][SQL Server]CREATE FILE encountered operating system
error 123(failed to retrieve text for this error. Reason: 15105) while
attempting to open or create the physical file
'D:\MSSQL\DATA\NewDatabase_data.mdf'. (5123)
(SQLExecDirectW); [42000] [Microsoft][ODBC SQL Server Driver][SQL
Server]CREATE DATABASE failed. Some file names listed could not be
created. Check related errors. (1802)")

Categories

Resources