pyodbc execute variable becomes #P1 - python

Hi I'm doing something like:
# pyodbc extension
cursor.execute("select a from tbl where b=? and c=?", x, y)
-- some values in the query in provided by variables. But sometimes the variable is interpreted as #P1 in the query.
For example:
import pyodbc
ch = pyodbc.connect('DRIVER={SQL Server};SERVER=xxxx;DATABASE=xxx;Trusted_Connection=True')
cur = ch.cursor()
x = 123
cur.execute('''
CREATE TABLE table_? (
id int IDENTITY(1,1) PRIMARY KEY,
obj varchar(max) NOT NULL
)
''', x).commit()
This results in a new table named table_#P1 (I want table_123)
Another example:
x = 123
cur.execute('''
CREATE TABLE table_2 (
id int IDENTITY(1,1) PRIMARY KEY,
obj varchar(?) NOT NULL
)
''', x).commit()
it reports error:
ProgrammingError: ('42000', "[42000] [Microsoft][ODBC SQL Server
Driver][SQL Server]Incorrect syntax near '#P1'. (102)
(SQLExecDirectW)")
Again, the variable is interpreted as #P1.
Anyone know how to fix this? Any help's appreciated. Thanks-

In your first case, parameter substitution does not work for table/column names. This is common to the vast majority of (if not all) database platforms.
In your second case, SQL Server does not appear to support parameter substitution for DDL statements. The SQL Server ODBC driver converts the pyodbc parameter placeholders (?) to T-SQL parameter placeholders (#P1, #P2, ...) so the statement passed to SQL Server is
CREATE TABLE table_2 (id int IDENTITY(1,1) PRIMARY KEY, obj varchar(#P1) NOT NULL
specifically
exec sp_prepexec #p1 output,N'#P1 int',N'CREATE TABLE table_2 (id int IDENTITY(1,1) PRIMARY KEY, obj varchar(#P1) NOT NULL',123
and when SQL Server tries to prepare that statement it expects a literal value, not a parameter placeholder.
So, in both cases you will need to use dynamic SQL (string formatting) to insert the appropriate values.

There is a way to do this sort of thing. What you need to do is dynamically build the command (ideally as a nvarchar( MAX), not varchar( MAX)) string variable and pass that variable to the cur.execute() - or any other - command. Modifying your first example accordingly:
ch = pyodbc.connect( 'DRIVER={SQL Server};SERVER=xxxx;DATABASE=xxx;Trusted_Connection=True' )
cur = ch.cursor()
x = 123
SQL_Commands = 'CREATE TABLE table_' + str( x ) + '''
(
id int IDENTITY(1,1) PRIMARY KEY,
obj varchar(max) NOT NULL
) '
'''
cur.execute( SQL_Commands ).commit()
BTW, you shouldn't try to do everything in one line, if only to avoid problems like this one. I'd also suggest looking into adding "autocommit=True" to your connect string, that way you wouldn't have to append .commit() to cur.execute().

Related

Unable to cast POINT datatype in INSERT query to PostgreSQL. Longitude, Latitude required to be inserted into table

I'm trying to insert latitude & longitude that are stored as python variables into a table in PostgreSQL via the INSERT query. Any suggestions on how to cast Point other than what I've tried?
I tried the insert query first as shown -
This is the table:
cur.execute('''CREATE TABLE AccidentList (
accidentId SERIAL PRIMARY KEY,
cameraGeoLocation POINT,
accidentTimeStamp TIMESTAMPTZ);''')
Try1:
cur.execute("INSERT INTO AccidentList(cameraGeoLocation,accidentTimeStamp)
VALUES {}".format((lat,lon),ts));
Error:
>Hint: psycopg2.ProgrammingError: column "camerageolocation" is of type point but expression is of type numeric
LINE 1: ...ist (cameraGeoLocation,accidentTimeStamp) VALUES (13.0843, 8...
^
HINT: You will need to rewrite or cast the expression.
Try2:
query = "INSERT INTO AccidentList (cameraGeoLocation,accidentTimeStamp)
VALUES(cameraGeoLocation::POINT, accidentTimeStamp::TIMESTAMPTZ);"
data = ((lat,lon),ts)
cur.execute(query,data)
Error:
LINE 1: ...List (cameraGeoLocation,accidentTimeStamp) VALUES(cameraGeoL...
^
HINT: There is a column named "camerageolocation" in table "accidentlist", but it cannot be referenced from this part of the query.
Try 3:
query = "INSERT INTO AccidentList (camerageolocation ,accidenttimestamp) VALUES(%s::POINT, %s);"
data = (POINT(lat,lon),ts)
cur.execute(query,data)
Error:
cur.execute(query,data)
psycopg2.ProgrammingError: cannot cast type record to point
LINE 1: ...tion ,accidenttimestamp) VALUES((13.0843, 80.2805)::POINT, '...
Single quote your third attempt.
This works: SELECT '(13.0843, 80.2805)'::POINT
I had a similar problem trying to insert data of type point into Postgres.
Using quotes around the tuple (making it a string) worked for me.
conn = psycopg2.connect(...)
cursor = conn.cursor()
conn.autocommit = True
sql = 'insert into cities (name,location) values (%s,%s);'
values = ('City A','(10.,20.)')
cursor.execute(sql,values)
cursor.close()
conn.close()
My environment:
PostgreSQL 12.4,
Python 3.7.2,
psycopg2-binary 2.8.5

mysql error syntax in python

sql = """
DROP PROCEDURE
IF EXISTS schema_change;
delimiter ';;'
CREATE PROCEDURE schema_change() BEGIN
if exists (select * from information_schema.columns where table_schema =
schema() and table_name = 'selectedairport' and column_name = 'GDP')
then
alter table selectedairport drop column GDP;
alter table selectedairport add column GDP DOUBLE;
end;;
delimiter ';'
CALL schema_change () ; DROP PROCEDURE
IF EXISTS schema_change ;
"""
cursor6.execute(sql)
However, this produces the error:
pymysql.err.ProgrammingError: (1064, "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 'delimiter ';;'\nCREATE PROCEDURE schema_change() BEGIN\n\n if exists (select * f' at line 1")
What could be the problem?
The execute() method (usually) only executes a single command at a time, so the script cannot be parsed, and anyway there is no support for DELIMITER; see this comment on GitHub. Therefore, one solution is to have multiple calls:
cursor6.execute("""
DROP PROCEDURE
IF EXISTS schema_change
""")
cursor6.execute("""
CREATE PROCEDURE schema_change() BEGIN
if exists (select * from information_schema.columns where table_schema =
schema() and table_name = 'selectedairport' and column_name = 'GDP')
then
alter table selectedairport drop column GDP;
NOTE: There is a syntax error here, we need to further add:
END IF;
Now continue as before:
alter table selectedairport add column GDP DOUBLE;
end
""")
cursor6.execute("""
CALL schema_change ()
""")
# Or cursor6.callproc('schema_change')
cursor6.execute("""
DROP PROCEDURE
IF EXISTS schema_change
""")

Using instance variables in SQLite3 update?

Ok so basically I'm trying to update an existing SQLite3 Database with instance variables (typ and lvl)
#Set variables
typ = 'Test'
lvl = 6
#Print Databse
print("\nHere's a listing of all the records in the table:\n")
for row in cursor.execute("SELECT rowid, * FROM fieldmap ORDER BY rowid"):
print(row)
#Update Info
sql = """
UPDATE fieldmap
SET buildtype = typ, buildlevel = lvl
WHERE rowid = 11
"""
cursor.execute(sql)
#Print Databse
print("\nHere's a listing of all the records in the table:\n")
for row in cursor.execute("SELECT rowid, * FROM fieldmap ORDER BY rowid"):
print(row)
As an Error I'm getting
sqlite3.OperationalError: no such column: typ
Now I basically know the problem is that my variable is inserted with the wrong syntax but I can not for the life of me find the correct one. It works with strings and ints just fine like this:
sql = """
UPDATE fieldmap
SET buildtype = 'house', buildlevel = 3
WHERE rowid = 11
"""
But as soon as I switch to the variables it throws the error.
Your query is not actually inserting the values of the variables typ and lvl into the query string. As written the query is trying to reference columns named typ and lvl, but these don't exist in the table.
Try writing is as a parameterised query:
sql = """
UPDATE fieldmap
SET buildtype = ?, buildlevel = ?
WHERE rowid = 11
"""
cursor.execute(sql, (typ, lvl))
The ? acts as a placeholder in the query string which is replaced by the values in the tuple passed to execute(). This is a secure way to construct the query and avoids SQL injection vulnerabilities.
Hey I think you should use ORM to manipulate with SQL database.
SQLAlchemy is your friend. I use that with SQLite, MySQL, PostgreSQL. It is fantastic.
That can make you get away from this syntax error since SQL does take commas and quotation marks as importance.
For hard coding, you may try this:
sql = """
UPDATE fieldmap
SET buildtype = '%s', buildlevel = 3
WHERE rowid = 11
""" % (house)
This can solve your problem temporarily but not for the long run. ORM is your friend.
Hope this could be helpful!

Python mysql connector insert with %s

I'm trying to append a set containing a number into my MySQL database using the Python MySQLConnector. I am able to add data manually, but the following expression with %s won't work. I tried several variations on this, but nothing from the documentation seems to work in my case. The table was already buildt as you can see:
#Table erstellen:
#cursor.execute('''CREATE TABLE anzahlids( tweetid INT )''')
Here is my code and the error:
print len(idset)
id_data = [
len(idset)
]
print id_data
insert = ("""INSERT INTO anzahlids (idnummer) VALUES (%s)""")
cursor.executemany(insert, id_data)
db_connection.commit()
"Failed processing format-parameters; %s" % e)
mysql.connector.errors.ProgrammingError: Failed processing format-parameters; argument 2 to map() must support iteration
Late answer, but I would like to post some nicer code. Also, the original question was using MySQL Connector/Python.
The use of executemany() is wrong. The executemany() method expects a sequence of tuples, for example, [ (1,), (2,) ].
For the problem at hand, executemany() is actually not useful and execute() should be used:
cur.execute("DROP TABLE IF EXISTS anzahlids")
cur.execute("CREATE TABLE anzahlids (tweetid INT)")
some_ids = [ 1, 2, 3, 4, 5]
cur.execute("INSERT INTO anzahlids (tweetid) VALUES (%s)",
(len(some_ids),))
cnx.commit()
And with MySQL Connector/Python (unlike with MySQLdb), you have to make sure you are committing.
(Note for non-German speakers: 'anzahlids' means 'number_of_ids')
The following is an example that worked on my machine.
import MySQLdb
db = MySQLdb.connect(host="localhost", user="stackoverflow", passwd="", db="stackoverflow")
cursor = db.cursor()
try:
sql = 'create table if not exists anzahlids( tweetid int ) ; '
except:
#ignore
pass
sql = ("""INSERT INTO anzahlids (tweetid) VALUES (%s)""")
data = [1,2,3,4,5,6,7,8,9]
length = [len(data)]
cursor.executemany(sql,length)
db.commit()
if idset is a single value you can use
sql = ("""INSERT INTO anzahlids (tweetid) VALUES (%s)""") % len(idset)
cursor.execute(sql)
db.commit()

MySQL syntax error using python to add column to a table

The code i have is:
for key in keys:
cursor.execute("""
ALTER TABLE segment_table ADD %s VARCHAR(40)
""", key)
I get a error telling me my syntax is wrong. When I replace the %s with a actual string the syntax error goes away.
for key in keys:
cursor.execute("""
ALTER TABLE segment_table ADD myColumn VARCHAR(40)
""")
Any help is appreciated.
There is a bit of confusion going here, for several reasons:
(1) mySQL uses the % as a parameter marker -- easily confused with the % in Python's string % (data1, data2, etc)
(2) some people seem not to be aware that parameter markers can be used only where an expression can be used in SQL syntax -- this excludes table names, column names, function names, keywords, etc
(3) code-golf onelinerism
Required SQL: ALTER TABLE segment_table ADD myColumn VARCHAR(40)
Using a parameter doesn't work:
key = "myColumn"
sql = "ALTER TABLE segment_table ADD %s VARCHAR(40)" # col name not OK as parm
cursor.execute(sql, (key, ))
You need to build an acceptable SQL statement, using e.g. Python string formatting:
key = "myColumn"
sql = "ALTER TABLE segment_table ADD %s VARCHAR(40)" % key
cursor.execute(sql)
Shouldn't you do the replacement before feeding it?
query = "ALTER TABLE segment_table ADD %s VARCHAR(40)" % (key)
cursor.execute( query )
when cursor.execute() replace %s in a query string it adds ' ' to the argument values supplied...so when you do
key = 'abc'
cursor.execute("""
ALTER TABLE segment_table ADD %s VARCHAR(40)
""", key)
the query executed is
ALTER TABLE segment_table ADD 'abc' VARCHAR(40)
to which mysql will throw a syntax error coz the column names, table names can be in `` but not ' '
so this will work
query = "ALTER TABLE segment_table ADD %s VARCHAR(40)" % (key)

Categories