I am trying to add argv[0] as variable to the SQL query below and running into compilation error below,what is the syntax to fix this?
#!/usr/bin/python
import pypyodbc as pyodbc
from sys import argv
component_id=argv[0]
server_name='odsdb.company.com'
database_name='ODS'
cnx = pyodbc.connect("DRIVER={SQL Server};SERVER="+server_name+";DATABASE="+database_name)
db_cursor=cnx.cursor()
SQL = 'SELECT Top 1 cr.ReleaseLabel ' + \
'FROM [ODS].[v000001].[ComponentRevisions] cr ' + \
'WHERE cr.ComponentId=' + component_id + \
'ORDER BY cr.CreatedOn DESC'
resp_rows_obj=db_cursor.execute(SQL)
print '('+', '.join([column_heading_tuple[0] for column_heading_tuple in resp_rows_obj.description])+')'
for row in resp_rows_obj:
print row
Error:-
pypyodbc.ProgrammingError: (u'42000', u"[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near the keyword 'BY'.")
Don't use string interpolation. Use SQL parameters; these are placeholders in the query where your database will insert values:
SQL = '''\
SELECT Top 1 cr.ReleaseLabel
FROM [ODS].[v000001].[ComponentRevisions] cr
WHERE cr.ComponentId = ?
ORDER BY cr.CreatedOn DESC
'''
resp_rows_obj = db_cursor.execute(SQL, (component_id,))
Values for the ? placeholders are sourced from the second argument to the cursor.execute() function, a sequence of values. Here you only have one value, so I used a one-element tuple.
Note that you probably want argv[1], not argv[0]; the latter is the script name, not the first argument.
to retrieve 1st command line argument do component_id=argv[1] instead of 0 which is the script name...
better yet, look at argparse
We had a hyphen in the database name that was being used in a T-SQL query being called from Python code. So we just added square brackets because SQL Server cannot interpolate the hyphen without them.
Before:
SELECT * FROM DBMS-NAME.dbo.TABLE_NAME
After:
SELECT * FROM [DBMS-NAME].dbo.TABLE_NAME
Related
For purposes of this question, let's say there is a table schema foo.bar.baz
And we have created a cursor object using following boilerplate
import snowflake.connector
ctx = snowflake.connector.connect(...)
cur = ctx.cursor()
With that cursor object, we can put the whole dot deliminated schema into a query like so:
cur.execute('''
select * from foo.bar.baz
'''
)
and have no issues, but we wouldn't be able to do:
cur.execute('''
select * from %(tbl)s
''', {'tbl': 'foo.bar.baz'}
)
Doing that throws this type of error: ProgrammingError: 001011 (42601): SQL compilation error: invalid URL prefix found in: foo.bar.baz
I'm guessing this is because the dots are sql identifiers and not strings, but I don't see any workaround in the snowflake documentation. Does anyone know how this could be done without having to change the connection object.
Using TABLE:
In a FROM clause, the syntax TABLE( { string_literal | session_variable | bind_variable } ) can be used
select * from TABLE(%(tbl)s)
From Python 3.9 i'm trying to do a MySql query like this
select * from brand WHERE text='L\'Orial'.
It works fine from phpMyAdmin but fails from python for all text including quote "'"
brand = "L'Orial"
where = f"text='{brand}'"
brand_pk_id = self.getPrimaryKeyIfExistInTable('brand', where)
def getPrimaryKeyIfExistInTable(self, table, where, key='id'):
try:
sql = f"SELECT {key} FROM {table} WHERE {where}"
self.cursor.execute(sql)
result = self.cursor.fetchone()
return result[key if self.bUseDictCursor else 0] if result else None
except pymysql.MySQLError as e:
logging.error(e)
return None
I can see that python escapes all quotes, which probably causes the problem, but can not figure out how to handle it properly !!
If I turn it around and use query LIKE with underscore( _ ) as wildcard:
brand = "L_Orial"
sql = f"SELECT {key} FROM {table} WHERE text LIKE '{brand}'"
It works fine, but this is not what I want !!
If I am understanding your question correctly, your problem is as follows:
Your query must exactly read:
SELECT * from brand WHERE text='L\'Orial'
But you are currently getting something like this, when you use python to execute the query:
SELECT * from brand WHERE text='L'Orial'
If this is indeed the issue, you should be able to resolve this by simply escaping the backslash that you need to have in the query. The complete python string for your query would be:
# Python String:
"SELECT * from brand WHERE text='L\\'Orial'"
# Resulting Query
SELECT * from brand WHERE text='L\'Orial'
If you wanted to automatically fix this issue for all brands that might include a ', you can simply replace the ' with \\' before making the query. Example:
brand = "L'Orial"
brand = brand.replace("'", "\\'")
# New Python string:
# "L\\'Orial"
# Output in SQL
# "L\'Orial"
Had to fire up my local instance just to make a point.
First, some prep work...
import pymysql
table = 'ps_carrier'
key = 'id_carrier'
mysql = {
"charset": "utf8",
"database": "mystore",
"host": "localhost",
"password": "secret",
"user": "justin"
}
As somebody suggested in the comments, the following
sql = "SELECT %s FROM %s WHERE %s"
where = "name='UPS'"
with pymysql.connect(**mysql) as conn:
with conn.cursor() as cur:
cur.execute(sql, (key, table, where))
Raises an error as expected since all the (string) params are quoted, even the table name!
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
...
File "C:\Python38\site-packages\pymysql\err.py", line 143, in raise_mysql_exception
raise errorclass(errno, errval)
pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''ps_carrier' WHERE 'name=\\'UPS\\''' at line 1")
If you can trust the inputs for the table name, the key, and the column name(s) then perhaps a simple query builder can help.
params = {'name': 'UPS'} # add more key--value pairs here
# use backticks in case we need to escape reserved words (OP uses MySQL)
where = " AND ".join(f"`{k}` = %s" for k in params.keys()) # .keys() just to be explicit
args = tuple([v for v in params.values()])
# backticks again
sql = f"SELECT `{key}` FROM `{table}` WHERE {where}"
print(sql)
print(args)
with pymysql.connect(**mysql) as conn:
with conn.cursor() as cur:
cur.execute(sql, args)
print(cur.fetchall())
If you need something more elaborate, there are a few modules such as Mysql Simple Query Builder and PyPika - Python Query Builder that you may want to look at (I've not used any of these.)
I am trying to connect to a Postgres DB and execute a simple select query. But I am getting errors. Below is the sample program
import psycopg2 as ps
param_dic = ps.connect(
host="localhost",
database="Test_DB",
user="username",
password="password"
)
cur = param_dic.cursor()
cur.execute("select * from <schema_name>.'employee_tbl'") # I am
rows = cur.fetchall()
for r in rows:
print(r)
I get below error:
psycopg2.errors.SyntaxError: syntax error at or near "'tbl_name'"
LINE 1: select * from <schema_name>.'tbl_name'
If I use
cur.execute("select * from <schema_name>.'Employee_TBL'")
Still, I get the same error.
Note: when I check my pgAdmin, I see below as the table name
<schema_name>.Employee_TBL
So, what is the right way to execute SQL queries on a Postgres table?
replace <schema_name>.'Employee_TBL'" with true value :
dbo.Employee_TBL or another schema name in your database
Maybe it's just a typo, use double quotes for the table if you need to.
Single quotes indicate a string literal.
import psycopg2
conn = psycopg2.connect(...)
cur = conn.cursor()
cur.execute('SELECT * FROM public.servers')
print(len(cur.fetchall()))
cur.execute('SELECT * FROM PUBLIC."servers"')
print(len(cur.fetchall()))
Out:
6
6
Try removing quotes around ‘emloyee_tbl’
The overriding issue is that you created a table name with quoted mixed case. This means that from then on you need to quote the name to be able to use it:
create table "Mixed_Case" (id int, fld_1 varchar);
select * from mixed_case;
ERROR: relation "mixed_case" does not exist
LINE 1: select * from mixed_case;
select * from "Mixed_Case";
id | fld_1
----+-------
(0 rows)
--NOTE the double quotes.
For more information see 4.1.1. Identifiers and Key Words
For the psycopg2 case:
import psycopg2
con = psycopg2.connect("dbname='test' host='localhost' user='aklaver'")
cur = con.cursor()
# Single quoted
cur.execute("select * from public.'Mixed_Case'")
SyntaxError: syntax error at or near "'Mixed_Case'"
LINE 1: select * from public.'Mixed_Case'
# Identifiers need double quotes
# Changing to double quotes
cur.execute('select * from public."Mixed_Case"')
# No error.
# You can also use Postgres functions
cur.execute("select * from quote_ident('public.Mixed_Case')")
For more on Postgres functions and methods see string functions
Also in psycopg2 there is the sql module that allows you to work with identifiers:
from psycopg2 import sql
sql_str = sql.SQL("select * from public.{}").format(sql.Identifier('Mixed_Case'))
print(sql_str.as_string(con))
select * from public."Mixed_Case"
cur.execute(sql_str)
Based on Python MySQLdb execute table variable and MySQL LOAD DATA LOCAL INFILE example in python? this should work:
import pymysql, os
directory = os.path.join('path', 'to', 'directory')
filename = 'my_filename.csv'
filepath = os.path.join(directory, filename)
to_table_name = "my_table"
connection = pymysql.connect(..., local_infile=True)
with connection.cursor() as cursor:
load_statement = """
load data local infile %s
into table %s
fields terminated by ','
optionally enclosed by '"'
lines terminated by '\\n'
ignore 1 lines
"""
cursor.execute(load_statement % (filepath, to_table_name, ))
connection.commit()
connection.close
But I'm still seeing this error:
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 '/path/to/directory/my_filename.csv\n into ' at line 1")
When I run this without the parameters i.e. writing the actual filepath and table name it works.
Any help would be much appreciated.
You should use the built in ability of Execute to do your string formatting also (this avoids MYSQL Injection attacks and errors) ... Rather than passing the parameters to the load_statement using % (String Interpolation) , pass that as parameters to execute
cursor.execute(load_statement , (filepath, to_table_name ))
Notice the comma instead of a %
Code is follow. How to get replaced ? by value of variables [table, url]?
Expected SQL command is select * from OTHER_URL where url="http://a.com/a.jpg"
This SQL command occurs no error on the sqlite3 command line interface.
import sqlite3
from contextlib import closing
dbname = "ng.db"
with closing(sqlite3.connect(dbname)) as conn:
c = conn.cursor()
c.execute("CREATE TABLE IF NOT EXISTS OTHER_URL (url TEXT)")
conn.commit()
table = "OTHER_URL"
url = "http://a.com/a.jpg"
with closing(sqlite3.connect(dbname)) as conn:
c = conn.cursor()
c.execute('select * from ? where url="?"', [table, url])
print c.fetchone()
There are two errors here. Firstly, you can't use parameter substitution for table names (or column names), only for values. You need to use string interpolation for anything else.
Secondly, you don't need quotes around the value parameter; the substitution will take care of that.
So:
c.execute('select * from {} where url=?'.format(table), [url])