POSTGRES ALTER procedure syntax error I can't figure out - python

Here is the error:
ERROR: [GET_ALL_DATASETS_BY_DATE] syntax error at or near "LANGUAGE"
LINE 3: LANGUAGE SQL
Here is the code
def PROCEDURE_GET_ALL_DATASETS_BY_DATE(conn):
print("CREATING [GET_ALL_DATASETS_BY_DATE] PROCEDURE")
try:
cursor = conn.cursor()
cursor.execute(f"""
ALTER PROCEDURE GET_ALL_DATASETS_BY_DATE(how_many int)
LANGUAGE SQL
AS $$
SELECT U.username, F.File_PATH "Path", Description "Desc", F.Date_Time "Date", F.File_size "Size"
FROM USERS as U
INNER JOIN FILES as F
ON F.UserId = U.User_Id
ORDER BY F.Date_Time
limit how_many
$$;
""")
conn.commit()
except Exception as e:
cursor.execute("ROLLBACK")
print("ERROR: [GET_ALL_DATASETS_BY_DATE] " + str(e))
I feel like I am missing something super simple...Thank you for your time. Any help is appreciated
here is the documentation link to how I've been modelling my procedures.
https://www.postgresql.org/docs/current/sql-createprocedure.html

if you wanna bring the table by using join. You can use the code below.
PostgreSQL is not like MSSQL or TSQL. In MSSQL and TSQL we can use procedure as direct. But In Postgres, if we want to use select processing, we have to specify columns on our query.
Example:
CREATE OR REPLACE FUNCTION public.myposts(_user_id integer)
RETURNS TABLE(post_id integer, create_user_id integer, ad_name character varying, topic character varying, content_values text, slug_url character varying)
LANGUAGE plpgsql
AS $function$
BEGIN
RETURN QUERY
select distinct posts.id,posts.create_user_id,users.ad_name,posts.topic,posts.content_values,posts.slug_url from posts
inner join users on users.id = posts.create_user_id
inner join post_receivers on post_receivers.post_id = posts.id
where post_receivers.user_id = _user_id;
END
$function$
;

Related

How to specify a dot separated table as a parameter into the sql query

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)

Python -> MySQL "select * from brand WHERE text='L\'Orial'" (quote inside search text)

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.)

Python variables in MySQL execute command

I've looked for an answer everywhere and didn't manage to find any suitable one.
This is my code:
conn = pymysql.Connect(host="host", user="user", passwd="password", db="database")
dbhandler = conn.cursor()
table_name = today_date.split(" ")[0]
execute_it = """CREATE TABLE %s (
USERNAME CHAR(20) NOT NULL,
X CHAR(10),
Y INT,
Z INT,
A INT)"""
try:
dbhandler.execute(execute_it, table_name)
except:
print("\n----------------------------\nFailed to create table.")
Now I've tried to do it like this.
I tried with % separating in execute.
I tried with ? instead of %s.
I tried it with many more options and yet none of them worked for me and I failed to create the table
This is the exception I get:
(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 ''11/14/18' (\n USERNAME CHAR(20) NOT NULL, \n
X CHAR(10' at line 1")
Using 5.5.52-MariaDB.
Thank you!
EDIT:
Managed to get through it.
Thanks Pavel FrancĂ­rek for the help.
Problem is not in placeholder, but in date format. Character "/" is not allowed in table name. Try something like:
table_name = today_date.split(" ")[0].replace("/","")
I assume that all numbers in your date format are 2-digit.

Executing SQL Server stored procedures with parameters in Python

I'm trying to execute a stored procedure to query a table, and am having trouble passing through a parameter successfully.
title=cursor.execute("SELECT titlequery(%s)", str(member_id))`
titlequery() is created by this:
CREATE OR REPLACE FUNCTION public.titlequery(mid text)
RETURNS text AS
$BODY$
SELECT title FROM Member WHERE member_id=mid;
$BODY$
LANGUAGE sql
And the error I'm getting:
modules.pg8000.core.ProgrammingError: ('ERROR', '42P18', 'could not
determine data type of parameter $2', 'postgres.c', '1356',
'exec_parse_message', '', '')
Does anyone know what's happening here?
PEP-249 specifies API for database drivers and pg8000 follows this API as well
pg8000 is a DB-API 2.0 compatible pure-Python interface to the PostgreSQL database engine.
From PEP-249 execute method specification:
Parameters may be provided as sequence or mapping and will be bound to variables in the operation.
We can see at pg8000 sources an example of how to pass parameters to query.
So you should pass a tuple/list of values, not value itself.
Also we should execute query first and then fetch its results using fetchone or fetchmany or fetchall because execute itself returns None (more at sources). I guess OP needs one record, so we're going to use fetchone.
Note: fetchone method returns record represented as tuple, so if we need first coordinate, then we should get it using zero index.
In your case you should try:
parameters = (str(member_id),) # WARNING: don't miss the comma
cursor.execute("SELECT titlequery(%s)", parameters)
title = cursor.fetchone()[0]
or
parameters = [str(member_id)]
cursor.execute("SELECT titlequery(%s)", parameters)
title = cursor.fetchone()[0]
Example
This worked for me
import pg8000
table_definition = """
CREATE TABLE Member(
title VARCHAR(40) NOT NULL,
member_id VARCHAR(40) NOT NULL)
"""
procedure_definition = """
CREATE OR REPLACE FUNCTION public.titlequery(mid text)
RETURNS text AS
$BODY$
SELECT title FROM Member WHERE member_id=mid;
$BODY$
LANGUAGE sql
"""
connection = pg8000.connect(database='database',
user='username',
password='password',
host='hostname',
port=5432)
cursor = connection.cursor()
# Preparation
cursor.execute(table_definition)
cursor.execute(procedure_definition)
values = ('Information', 'A000042553')
cursor.execute('INSERT INTO Member (title, member_id) VALUES (%s, %s)',
values)
# Reading stored procedure result
parameters = ('A000042553',)
cursor.execute("SELECT titlequery(%s)", parameters)
title = cursor.fetchone()[0]
print(title)
# Cleanup
cursor.close()
connection.close()
gives us
Information

django + south + python: strange behavior when using a text string received as a parameter in a function

this is my first question.
I'm trying to execute a SQL query in django (south migration):
from django.db import connection
# ...
class Migration(SchemaMigration):
# ...
def transform_id_to_pk(self, table):
try:
db.delete_primary_key(table)
except:
pass
finally:
cursor = connection.cursor()
# This does not work
cursor.execute('SELECT MAX("id") FROM "%s"', [table])
# I don't know if this works.
try:
minvalue = cursor.fetchone()[0]
except:
minvalue = 1
seq_name = table + '_id_seq'
db.execute('CREATE SEQUENCE "%s" START WITH %s OWNED BY "%s"."id"', [seq_name, minvalue, table])
db.execute('ALTER TABLE "%s" ALTER COLUMN id SET DEFAULT nextval("%s")', [table, seq_name + '::regclass'])
db.create_primary_key(table, ['id'])
# ...
I use this function like this:
self.transform_id_to_pk('my_table_name')
So it should:
Find the biggest existent ID or 0 (it crashes)
Create a sequence name
Create the sequence
Update the ID field to use sequence
Update the ID as PK
But it crashes and the error says:
File "../apps/accounting/migrations/0003_setup_tables.py", line 45, in forwards
self.delegation_table_setup(orm)
File "../apps/accounting/migrations/0003_setup_tables.py", line 478, in delegation_table_setup
self.transform_id_to_pk('accounting_delegation')
File "../apps/accounting/migrations/0003_setup_tables.py", line 20, in transform_id_to_pk
cursor.execute(u'SELECT MAX("id") FROM "%s"', [table.encode('utf-8')])
File "/Library/Python/2.6/site-packages/django/db/backends/util.py", line 19, in execute
return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: relation "E'accounting_delegation'" does not exist
LINE 1: SELECT MAX("id") FROM "E'accounting_delegation'"
^
I have shortened the file paths for convenience.
What does that "E'accounting_delegation'" mean? How could I get rid of it?
Thank you!
Carlos.
The problem is that you're using DB-API parameterization for things that are not SQL data. When you do something like:
cursor.execute('INSERT INTO table_foo VALUES (%s, %s)', (col1, col2))
the DB-API module (django's frontend for whatever database you are using, in this case) will know to escape the contents of 'col1' and 'col2' appropriately, and replace the %s's with them. Note that there are no quotes around the %s's. But that only works for SQL data, not for SQL metadata, such as table names and sequence names, because they need to be quoted differently (or not at all.) When you do
cursor.execute('INSERT INTO "%s" VALUES (%s, %s)', (tablename, col1, col2))
the tablename gets quoted as if you mean it to be string data to insert, and you end up with, for example, "'table_foo'". You need to separate your SQL metadata, which is part of the query, and your SQL data, which is not, like so:
sql = 'INSERT INTO TABLE "%s" VALUES (%%s, %%s)' % (tablename,)
cursor.execute(sql, (col1, col2))
Note that because the django DB-API frontend's paramstyle is 'pyformat' (it uses %s for placeholders) you need to escape those when you do the string formatting to create the SQL you want to execute. And note that this isn't secure against SQL injection attacks when you take the tablename from an insecure source and don't validate it.

Categories