SQL error when using format() function with pyodbc in Django - sql

I want to execute a command using pyodbc in my Django app. When I do simple update with one column it works great:
cursor.execute("UPDATE dbo.Table SET attr = 1 WHERE id = {}".format(id))
However when I try to use a string as a column value it throws error:
cursor.execute("UPDATE dbo.Table SET attr = 1, user = '{}' WHERE id = {}".format(id, str(request.user.username)))
Here's error message:
('42S22', "[42S22] [Microsoft][ODBC SQL Server Driver][SQL Server]Invalid column name 'Admin'. (207) (SQLExecDirectW)")
Suprisingly this method works:
cursor.execute("UPDATE dbo.Table SET attr = 1, user = 'Admin' WHERE id = {}".format(id))
What seems to be the problem? Why is sql mistaking column value for its name?

As mentioned above, you have your arguments backwards, but if you're going to use cursor.execute(), the far more important thing to do is use positional parameters (%s). This will pass the SQL and values separately to the database backend, and protect you from SQL injection:
from django.db import connection
cursor = connection.cursor()
cursor.execute("""
UPDATE dbo.Table
SET attr = 1,
user = %s
WHERE id = %s
""", [
request.user.username,
id,
])

You've got your format arguments backwards. You're passing id to user, and username to the id WHERE clause.

Related

Passing table name and list of values as argument to psycopg2 query

Context
I would like to pass a table name along with query parameters in a psycopg2 query in a python3 function.
If I understand correctly, I should not format the query string using python .format() method prior to the execution of the query, but let psycopg2 do that.
Issue
I can't succeed passing both the table name and the parameters as argument to my query string.
Code sample
Here is a code sample:
import psycopg2
from psycopg2 import sql
connection_string = "host={} port={} dbname={} user={} password={}".format(*PARAMS.values())
conn = psycopg2.connect(connection_string)
curs = conn.cursor()
table = 'my_customers'
cities = ["Paris", "London", "Madrid"]
data = (table, tuple(customers))
query = sql.SQL("SELECT * FROM {} WHERE city = ANY (%s);")
curs.execute(query, data)
rows = cursLocal.fetchall()
Error(s)
But I get the following error message:
TypeError: not all arguments converted during string formatting
I also tried to replace the data definition by:
data = (sql.Identifier(table), tuple(object_types))
But then this error pops:
ProgrammingError: can't adapt type 'Identifier'
If I put ANY {} instead of ANY (%s) in the query string, in both previous cases this error shows:
SyntaxError: syntax error at or near "{"
LINE 1: ...* FROM {} WHERE c...
^
Initially, I didn't used the sql module and I was trying to pass the data as the second argument to the curs.execute() method, but then the table name was single quoted in the command, which caused troubles. So I gave the sql module a try, hopping it's not a deprecated habit.
If possible, I would like to keep the curly braces {} for parameters substitution instead of %s, except if it's a bad idea.
Environment
Ubuntu 18.04 64 bit 5.0.0-37-generic x86_64 GNU/Linux
Python 3.6.9 (default, Nov 7 2019, 10:44:02)
psycopg2.__version__
'2.8.4 (dt dec pq3 ext lo64)'
You want something like:
table = 'my_customers'
cities = ["Paris", "London", "Madrid"]
query = sql.SQL("SELECT * FROM {} WHERE city = ANY (%s)").format(sql.Identifier(table))
curs.execute(query, (cities,))
rows = cursLocal.fetchall()

Sqlalchemy use json_set to update specific JSON field

I intend to use func function to update a specific JSON field in Sqlalchemy, but I get some problem, here is my code to update field:
self.db.query(TestModel).filter(TestModel.test_id == self._test_id).update(
{field_name: func.json_set(
field_name,
"$." + key,
formatted_val)}
, synchronize_session='fetch'
)
self.db.commit()
I ran the code above and got the error:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) malformed JSON
So, I go to check the log, found Sqlalchemy form an SQL clause like that:
UPDATE test_model SET field_name=json_set('field_name', '$.keyname', 'value') WHERE test_model.test_id = 1;
the problem is Sqlalchemy should not use 'field_name' to specific the field it should use field_name to specific the field, and I try to run corrected sql clause below in sql client:
UPDATE test_model SET field_name=json_set(field_name, '$.keyname', 'value') WHERE test_model.test_id = 1;
and it work find
I just want to know how to make the Sqlalchemy form the correct field from 'field_name' to field_name?
You should pass first parameter with a name of model to function func.json_set:
self.db.query(TestModel).filter(TestModel.test_id == self._test_id).update(
{field_name: func.json_set(
TestModel.field_name,
"$." + key,
formatted_val)},
synchronize_session='fetch'
)
self.db.commit()

Invalid number string (7498) JDBC Request

I'm converting this progress statement into SQL.
for each usr_mstr where usr_userid matches "PRF52" exclusive-lock:
assign usr_force_change = no.
end.
This is what I currently have.
UPDATE PUB.usr_mstr SET usr_force_change = 'false' WHERE usr_userid = 'PRF52'
The error that I am receiving is '[DataDirect][OpenEdge JDBC Driver][OpenEdge] Invalid number string (7498)'.
A select statement for this field is working and returns the following.
SELECT usr_force_change FROM PUB.usr_mstr WHERE usr_userid = 'PRF52'
usr_force_change
false
The column data type was of type 'LOGICAL'. This translates to type 'BIT' in SQL. I updated the statement to the following at it worked.
UPDATE PUB.usr_mstr SET usr_force_change = '0' WHERE usr_userid = 'PRF51'
You need to choose Query type as Update Statement when submit update
Update Statement - use this for Inserts and Deletes as well

Passing a parameter to a sql query using pyodbc failing

I have read dozens of similar posts and tried everything but I still get an error message when trying to pass a parameter to a simple query using pyodbc. Apologies if there is an answer to this elsewhere but I cannot find it
I have a very simple table:
select * from Test
yields
a
b
c
This works fine:
import pyodbc
import pandas
connection = pyodbc.connect('DSN=HyperCube SYSTEST',autocommit=True)
result = pandas.read_sql("""select * from Test where value = 'a'""",connection,params=None)
print(result)
result:
value
0 a
However if I try to do the where clause with a parameter it fails
result = pandas.read_sql("""select * from Test where value = ?""",connection,params='a')
yields
Error: ('01S02', '[01S02] Unknown column/parameter value (9001) (SQLPrepare)')
I also tried this
cursor = connection.cursor()
cursor.execute("""select * from Test where value = ?""",['a'])
pyodbcResults = cursor.fetchall()
and still received the same error
Does anyone know what is going on? Could it be an issue with the database I am querying?
PS. I looked at the following post and the syntax there in the first part of answer 9 where dates are passed by strings looks identical to what I am doing
pyodbc the sql contains 0 parameter markers but 1 parameters were supplied' 'hy000'
Thanks
pandas.read_sql(sql, con, index_col=None, coerce_float=True, params=None, parse_dates=None, columns=None, chunksize=None)[https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_sql.html]ΒΆ
params : list, tuple or dict, optional, default: None
example:
cursor.execute("select * from Test where value = %s",['a'])
or Named arguments example:
result = pandas.read_sql(('select * from Test where value = %(par)s'),
db,params={"par":'p'})
in pyodbc write parms directly after sql parameter:
cursor.execute(sql, *parameters)
for example:
onepar = 'a'
cursor.execute("select * from Test where value = ?", onepar)
cursor.execute("select a from tbl where b=? and c=?", x, y)

Update From clause in SQL Server CE doesn't work , any Solutions?

I've this SQL statement:
UPDATE Movement_Item_Lots
SET Batch_Code = (SELECT WHSS.Batch_Code
FROM WH_Stock_Serials AS WHSS
WHERE WHSS.Item_Code = Movement_Item_Lots.Item_Code
AND WHSS.From_Distribution_Code = Movement_Item_Lots.Distribution_Code
)
it returns :
There was an error parsing the query.
[ Token line number = 2,Token line offset = 19,Token in error = SELECT ]
I know this is common issue in SQL Server CE that it can't do update from, any workaround for this issue ?
Change to sqlite, if possible, this sql would work... If not possible, you can always divide the statement in your program:
var <- SELECT WHSS.Batch_Code...
UPDATE .. SET Batch_Code = var