What am I doing wrong in my query? [duplicate] - python

This question already has answers here:
SQLite parameter substitution problem
(8 answers)
Closed 6 years ago.
So I have a table in my Customers.db file that looks like this:
I wanted to make a function which returns the "rows" which has the id equal to the user input. The Table is also called 'Customers and all the columns are type TEXT.
def run_query(db, query, args=NONE):
con = sqlite3.connect(db)
cur = con.cursor()
if args is None:
cur.execute(query)
else:
cur.execute(query, args)
data = cur.fetchall()
cur.close()
con.close()
return data
def get_info_by_id(db, ide):
query = "SELECT * FROM Customers WHERE id = ?"
return run_query(db, query, ide)
When I ran this in the shell like this
get_info_by_id('Customers.db', '920')
I get the error "sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 1, and there are 3 supplied."

You need to update your run_query function as:
def run_query(db, query, *args):
# ^ *args here for variable number of arguments
# It will read additional arguments as tuples
..
cur.execute(query, args) # No need of if-else now
.. # It expects arguments to be in tuple format
For more information related to *args, take a look at: What does asterisk * mean in Python?

The args argument of cur.execute needs to be an iterable so that they can be bound to multiple placeholders (?) if necessary. Therefore you should always be passing a list or tuple.
get_info_by_id('Customers.db', ['920'])
When you pass a string it gets treated as an iterable of single-character strings, hence it says there were 3 bindings (3 characters in '920').

Related

How to write a scalar Snowflake Python UDF with variable number of arguments?

I'd like to write a Snowflake scalar UDF in Python which takes a variable number of string arguments.
The idea I had was to use array type for this (i.e. array can handle variable number of elements) but the issue I had with this was that as soon as a single element of array argument was NULL, Snowflake threw an error and I need to be able to handle these NULLs.
Code:
create or replace function udx_py_uuid5_null(a array)
returns string
language python
runtime_version = 3.8
handler = 'f_uuid5'
as $$
import uuid
from typing import List, Optional
_null_uuid = uuid.UUID('00000000-0000-0000-0000-000000000000')
def f_uuid5(args: List[Optional[str]]):
args = [arg if not getattr(arg, "is_sql_null", False) else '' for arg in args]
return str(uuid.uuid5(_null_uuid, ':'.join(args)))
$$;
I'm trying to handle NULLs as described here but it seems to me as if this only applies to "first-level" arguments. As shown in the solution, desired behaviour is to replace NULLs with empty string before calculating the UUID.
Call:
select udx_py_uuid5_null([NULL, 'test', 'test1', NULL]);
Error message:
Python Interpreter Error: Traceback (most recent call last): File "_udf_code.py", line 7, in f_uuid5 TypeError: sequence item 0: expected str instance, NoneType found in function UDX_PY_UUID5_NULL with handler f_uuid5
Instead of trying to replacing NULLs with empty string why not simply remove None values:
args = [arg if not getattr(arg, "is_sql_null", False) else '' for arg in args]
=>
args = list(filter(lambda arg: arg is not None, args))
Full code:
create or replace function udx_py_uuid5_null(a array)
returns string
language python
runtime_version = 3.8
handler = 'f_uuid5'
as $$
import uuid
from typing import List, Optional
_null_uuid = uuid.UUID('00000000-0000-0000-0000-000000000000')
def f_uuid5(args: List[Optional[str]]):
args = list(filter(lambda arg: arg is not None, args))
return str(uuid.uuid5(_null_uuid, ':'.join(args)))
$$;
select udx_py_uuid5_null([NULL, 'test', 'test1', NULL]);
Output:

Wrong number or types of arguments in call to procedure with use zxJDBC

I took official example from http://www.jython.org/archive/21/docs/zxjdbc.html:
Oracle
>>> c = db.cursor() # open the database as in the examples above
>>> c.execute("create or replace function funcout (y out varchar2) return varchar2 is begin y := 'tested'; return 'returned'; end;")
>>> params = [None]
>>> c.callproc("funcout", params)
>>> print params
When I run this code I get exception:
PLS-00306: wrong number or types of arguments in call to 'FUNCOUT'
ORA-06550: line 1, column 7: PL/SQL: Statement ignored
How to fix it?
Addition!!! Also does not work this code:
outParam = ""
self.cursor.execute("create or replace function funcout (y out varchar2) return varchar2 is begin y := 'tested'; return 'returned'; end;")
self.cursor.callproc("funcout", [outParam])
When you have an OUT or IN OUT parameter, you must pass a variable, not a literal for that parameter. How else can the procedure pass the value back?
You can take a look at PLSQLSample.java

How to efficiently unravel arguments to a database in Python

I have the following function which takes 4 arguments (we don't know which are set and which aren't before runtime).
myFuct(self, arg1, arg2, arg3, arg4):
# db insert function for only those args that are set
Is there an efficient way of unraveling the set arguments in a mysql database with a single sql query?
P.S. I am looking for a pythonic way to do this without having to say if-this-then-that for a million times...
Thanks in advance.
Not entirely sure what you need.
def myfunc(*args, **kwargs):
...
Can take any number of arguments, is this what you're looking for?
print(*(1,2,3,4)) * "unravels" the arguments in the order they are given but can be passed as one object or any number of objects.
However, passing these into a SQL statement without knowing the precise length of the arguments. Since SQL to my knowledge is a bit strict on how you pass the arguments.
You could do something like:
def myfunc(*args):
statement = "INSERT INTO table VALUES(" + ', '.join(str(x) for x in args) + ");"
db.execute(statement)
Note of course that this can only be used if you actually pass arguments to myfunc that are of the correct type, order and length.
in postgresql you have something called a prepared statement which would come in handy here.
def myfunc(*args):
statement = "INSERT INTO table VALUES(" + ', '.join('$'+str(i) for i in range(0, len(args)+1)) + ");"
handle = db.prepare(statement)
handle(args)
Where you simply define $1, $2 and so on in the prepared statement and then pass the equivilant number of arguments to the handler which will execute the query with the correct format on each of the values enabling you to pass integers, strings and arrays.. any way you like :)
Also, if the argument is a dictionary (mentioned in a comment)...
You'd have to do:
def myfunc(*args):
keys = ', '.join(str(x) for x in list(args.keys()))
values = ', '.join(str(val) for k, val in list(args.items()))
statement = "INSERT INTO table (" + keys + ") VALUES(" + values + ");"
db.execute(statement)
Again, assumes the dictionary is passed with proper variables for a execution to proceed.
You can use variable-length argument list construct:
def myfunc(*args):
args_non_empty = [a for a in args if a]
This allows you to pass any number of argument to your method. You can easily then filter them by traversing the list.

Python - Database query function with non-consistent arguments

So I have a database with 10 fields(call them a, b, c....j), and I need to create a function "find_use()" that can find and modify records in the database based on any combination of fields given to it as arguments ( ie: find_use(a=="happy", g =="birthday") ). Also, due to privileges, I am not generating the SQL queries directly, but instead use an SQL wrapper the system provides called "selector()" which will locate records based on the same arguments, ie: query = selector(a=="happy", g=="birthday"), which would then return a list of the matching records
So the problem is, since I don't know what arguments find_use() will be receiving, I don't know how to structure the inner call to selector(). Ideally, the call to selector should be created dynamically; something to the effect of:
def find_use(a='',b='',c='',.....j=''):
vars = locals()
for v in vars:
if v.value() != '':
q_string += '{0} == {1},'.format(v.key(),v.value())
query = selector(q_string)
...do something to query...
This, however, will not work since selector does not take a string, but rather arguments in the same format as the find_use() function. How, then, can this be done. I have the feeling this is actually really easy, and I'm just missing something obvious. Any input would be greatly appreciated.
I think you are looking for keyword argument unpacking:
def find_use(**kwargs):
query = selector(**kwargs)
...do something to query...
When defined this way, find_use can receive an arbitrary number of keyword arguments. The keyword arguments are collected in a dict, kwargs.
For example,
def foo(**kwargs):
print(kwargs)
foo(a = 'happy', g = 'birthday')
yields
{'a': 'happy', 'g': 'birthday'}
and if
def bar(a, g):
print(a)
print(g)
then
bar(**{'a': 'happy', 'g': 'birthday'}) # like selector(**kwargs)
yields
happy
birthday

Understand Python Function [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm learning Python and wanted to see if anyone could help break down and understand what this function does step by step?
def label(self, index, *args):
"""
Label each axes one at a time
args are of the form <label 1>,...,<label n>
APIPARAM: chxl
"""
self.data['labels'].append(
str('%s:|%s'%(index, '|'.join(map(str,args)) )).replace('None','')
)
return self.parent
It's a good idea to change the formatting, before trying to understand what it does:
def label(self, index, *args):
"""
Label each axes one at a time
args are of the form <label 1>,...,<label n>
APIPARAM: chxl
"""
self.data['labels'].append(
str( '%s:|%s' % \
( index, '|'.join( map( str,args ) ) )
).replace( 'None', '' )
)
return self.parent
So:
it appends something to self.data[ 'labels' ] list. We know this because append() is a method of list object.
This something is a string such that:
string is of the form xxx:|yyy
xxx is replaced with the value of argument index
yyy is replaced with all the other arguments converted to strings (map(str,args)) and joined with | character (join(...)) so resulting in something like 'a|b|None|c'
every occurence of None in the string above is replaced with an empty string and this is appended to the list
EDIT:
As #abarnert pointed out it might be good to explain what does *args mean and why later on it's used as args, so here it goes.
*args (which is an asterisk + an arbitrary name) means "any number of anonymous arguments available further in args list". One can also use **kwargs - note two asterisk which is used for accepting keyworded arguments, i.e. ones passed to the function in the form of foo = bar where foo is the name of the argument and bar is its value rather than just bar.
As said above args and kwargs are arbitrary, one could just as well use *potatoes or **potatoes but using args and kwargs is a convention in Python (sometimes people also use **kw instead of **kwargs, but the meaning is the same - any number of anonymous and any number of keyworded arguments respectively).
Both are used if the number of arguments which the function/method should accept is not known beforehand - consider for a example a function which processes names of the party guests, one may not know how many there may be, so defining a following function makes sense:
def add_party_quests( *quests ):
for guest in quests:
do_some_processing( guest )
Then both calls below are valid:
add_party_guests( 'John' )
add_party_guests( 'Beth', 'Tim', 'Fred' )
This is also explained in this SO post: https://stackoverflow.com/a/287101/680238
I assume the misleading lines are:
self.data['labels'].append(
str('%s:|%s'%(index, '|'.join(map(str,args)) )).replace('None','')
)
Those can be formatted more clearly to aid reading:
self.data['labels'].append(
str('%s:|%s' % (
index,
'|'.join(map(str, args))
)).replace('None', '')
)
But can be better rewritten as:
self.data['labels'].append( # append to the list at `self.data['labels']`
'%s:|%s' % ( # a string of the format X:|Y
index, # where X is the index
'|'.join( # and Y is a list joined with '|'s
str(arg) if arg is not None else # with each item in the list
'' for arg in args # being it's string representation
)
)
)
*args turns into a list of arguments called args. self.data['labels'] looks to be a list. .append adds an item to the list. The item appended is returned by the string returned by the right most part, replace. To parse what string that is, start inside the parens and work your way out. map(str,args) converts all the args to strings and returns that list. '|'.join( takes the output of map and joins it into a single string, of the general pattern elem1|elem2|elem3..., it then uses the format string '%s:|%s'. The first %s gets replaced by the value of index, the second by the string output by '|'.join. It then calls replace on this string, replacing all occurences of 'None' with ''. Then it returns self.parent.

Categories

Resources