How can I resolve this SQLAlchemy error regarding SQL parameters? - python

I am passing a very simple SQL query to a server via Python's SQLAlchemy library. Here is my code:
def query4():
ed_notes = sa.Table("ED_NOTES_MASTER",metadata,autoload=True,autoload_with=engine)
note_query = sa.select([ed_notes.columns["PT_FIN"],
ed_notes.columns["RESULT_TITLE_TEXT"],
ed_notes.columns["RESULT"],
ed_notes.columns["RESULT_DT_TM"]]).where(ed_notes.columns["PT_FIN"].in_(unique_fins)).where(start_time<ed_notes.columns["RESULT_DT_TM"]).where(end_time>ed_notes.columns["RESULT_DT_TM"])
result = connection.execute(note_query)
resultset = result.all()
note_data_prelim = pd.DataFrame(resultset)
return note_data_prelim
the variable "unique_fins" is a list of over 50,000 unique identifiers that I am trying to specifically query. When this query is run, the following error results:
sqlalchemy.exc.ProgrammingError: (pyodbc.ProgrammingError) ('The SQL contains -11872 parameter markers, but 53664 parameters were supplied', 'HY000')
Any ideas on what is going on? The problem is definitely arising in the ed_notes.columns["PT_FIN"].in_(unique_fins) portion of the query.
Thanks in advance!

The in_ operator will convert your unique_fins list into a single parameter per item. You'll likely hit parameter limits on your underlying database.
Referring to this answer here you could do something like this;
.where(ed_notes.columns["PT_FIN"] == func.any_(unique_fins))

Related

Python/Pyodbc/SQL - Updating a table and setting a field to a CSV File

I am trying to use pyodbc to update an existing MS Access database table with a very long multiline string. The string is actually a csv that has been turned into a string.
The query I am trying to use to update the table is as follows:
query = """
UPDATE Stuff
SET Results = '{}'
WHERE AnalyteName =
'{}'
""".format(df, analytename)
The full printed statement looks as follows:
UPDATE Stuff
SET Results =
'col a,col b,col c,...,col z,
Row 1,a1,b1,c1,
...,...,...,...,
Row 3000,a3000,b3000,c3000'
WHERE AnalyteName = 'Serotonin'
However this does not seem to be working, and I keep getting the following error:
pyodbc.ProgrammingError: ('42000', '[42000] [Microsoft][ODBC Microsoft Access Driver] Syntax error in UPDATE statement. (-3503) (SQLExecDirectW)')
Which I assume is due to the format of the csv string I am trying to use to update the table with.
I have tried using INSERT and inserting a new row with the csv string and other relevant information and that seems to work. However, I need to use UPDATE as I will eventually be adding other csv strings to these columns. This leads me to believe that there is A) Something is wrong with the syntax of my UPDATE query (I am new to SQL syntax) or B) I am missing something from the documentation regarding UPDATE queries.
Is executing an UPDATE query like this possible? If so, where am I going wrong?
It would be determined by the table's field type.
For large amounts of text you'd need a blob field in your database table.
A blob field will store binary info so using blob will not 'see' illegal characters.
Answering my own question in case anyone else wants to use this.
It turns out what I was missing was brackets around the table column fields from my UPDATE statement. My final code looked something like this.
csv = df.to_csv(index=False)
name = 'some_name'
query = """
UPDATE Stuff
SET
[Results] = ?
WHERE
[AnalyteName] = ?
"""
self.cursor.execute(query, (csv, name))
I've seen several other posts here where brackets were not around the column names. However, since this is MS Access, I believe they were required for this query, or rather this specific query since it included a very long strong in the SET statement.
I welcome anyone else here to provide a more efficient method of performing this task or someone else who can provide more insight into why this is what worked for me.

MYSQL parameter python issue with table name

I am new in using python API to send a query to mysql.
My issue is very easy to reproduce. I have a table named "ingredient" and I would like to select the rows from python using parameters
If I do cursor.execute("select * from ?",('ingredient',)) I get the error message : Error while connecting to MySQL Not all parameters were used in the SQL statement MySQL connection is closed
I I do cursor.execute("select * from ?",'ingredient') I get the error message : Error while connecting to MySQL 1064 (42000): 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 '?' at line 1
Same issues using %s instead of ?. Using the other type of single quote on 'ingredient' instead of 'ingredient' does not give results either.
How is this supposed to work here ?
You just can't pass a table name as parameter to a query. The parameterization mechanism is there to pass literal values, not object names. Keep in mind that the database must be able to prepare the query plan from just the parameterized string (without the actual parameter value), which disqualifies using metadata as parameter.
You need string concatenation instead:
cursor.execute("select * from " + yourvar);
Note that, if the variable comes from outside your program, using such contruct exposes your code to SQL injection. You need to manually validate the value of the parameter before execting the query (for example by checking it against a fixed list of allowed values, or by querying the information schema of the database to ensure that the table does exist).
Does your query work if you just write:
cursor.execute("SELECT * FROM ingredient")
?

Psycopg2 - Passing variable in the where clause

I am trying to run a SQL script in Python where I am passing a variable in the where clause as below:
cursor.execute(f"""select * from table where type = variable_value""")
In the above query, variable_value has the value that I am trying to use in the where clause. I am however getting an error psycopg2.errors.UndefinedColumn: column "variable_value" does not exist in table
As per psycopg2 documentation the execute function takes variables as an extra parameter.
cursor.execute("""select * from table where type = %(value)s """, {"value": variable_value})
More examples in psycopg2 user manual..
Also please read carefully the section about SQL injection - the gist is, you should not quote parameters in your query, the execute function will take care of that to prevent the injection of harmful SQL.
Also to explain the error you are getting - the query you're sending is comparing two identifiers (type and variable_value). The table does not contain variable_value column, hence the error.
I believe, you intended to use string interpolation to construct the query, but you forgot the {}. It would work like this:
cursor.execute(f"""select * from table where type = '{variable_value}'""")
⚠️ but because of previously mentioned SQL injection, it is not a recommended way!.

Getting error when running a sql select statement in python

I am new to this and trying to learn python. I wrote a select statement in python where I used a parameter
Select """cln.customer_uid = """[(num_cuid_number)])
TypeError: string indices must be integers
Agree with the others, this doesn't look really like Python by itself.
I will see even without seeing the rest of that code I'll guess the [(num_cuid_number)] value(s) being returned is a string, so you'll want to convert it to integer for the select statement to process.
num_cuid_number is most likely a string in your code; the string indices are the ones in the square brackets. So please first check your data variable to see what you received there. Also, I think that num_cuid_number is a string, while it should be in an integer value.
Let me give you an example for the python code to execute: (Just for the reference: I have used SQLAlchemy with flask)
#app.route('/get_data/')
def get_data():
base_sql="""
SELECT cln.customer_uid='%s' from cln
""" % (num_cuid_number)
data = db.session.execute(base_sql).fetchall()
Pretty sure you are trying to create a select statement with a "where" clause here. There are many ways to do this, for example using raw sql, the query should look similar to this:
query = "SELECT * FROM cln WHERE customer_uid = %s"
parameters = (num_cuid_number,)
separating the parameters from the query is secure. You can then take these 2 variables and execute them with your db engine like
results = db.execute(query, parameters)
This will work, however, especially in Python, it is more common to use a package like SQLAlchemy to make queries more "flexible" (in other words, without manually constructing an actual string as a query string). You can do the same thing using SQLAlchemy core functionality
query = cln.select()
query = query.where(cln.customer_uid == num_cuid_number)
results = db.execute(query)
Note: I simplified "db" in both examples, you'd actually use a cursor, session, engine or similar to execute your queries, but that wasn't your question.

SQLAlchemy error when adding parameter to string SQL query

I'm trying to compose a string SQL query using SQLALchemy 1.1.2. I followed the explanation from the docs about using textual SQL but encountered a syntax error when I ran the following code:
from sqlalchemy.sql import text
# Create a database connection called "connection"...
q = text('USE :name')
connection.execute(q, name='DATABASE_NAME')
Here's the error message:
"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 ''DATABASE_NAME'' at line 1") [SQL: u'USE %s;'] [parameters:
(u'DATABASE_NAME',)]
Since I'm using the named colon format and passing the parameters as arguments to connection.execute I can't figure out why this problem is arising. I'm using a MySQL server, but if I read the docs correctly the text method should be DB-agnostic.
Thanks in advance for the help.
According to the documentation you need to use the bindparams like so:
q = text('USE :name')
q.bindparams(name="DATABASE_NAME")
connection.execute(q)
or like this:
q = text('USE :name')
q = q.bindparams(bindparam("name", String))
connection.execute(q, {"name": "DATABASE_NAME"})
This worked for me with no issues. Edit: I was wrong, it didn't work.
The problem is the bind params is going to auto wrap your value with a single quote. So what's happening is you get the final compiles statement (which is invalid syntax):
use 'DATABASE_NAME'
If you were to create the query: "Select * from mytable where column_a=:name"; this will work. Because it's wrapping the value with single quotes.
I would suggest for your use statement to do:
q = "USE {}".format("DATABASE_NAME")
Or something similar.

Categories