Reputation: 43
In the below, Scenario 1 is working fine in both (Code 1 & Code 2). But Scenario 2 is not working in Code 1.
My requirement is Tuple should keep on repeating itself until it fills all the formatting string in the Query dynamically. Because where clauses are not constant for all the queries.
Scenario 1#
query = SELECT * FROM test.order where total_price in {}
Tuple:
finTup=((125, 125, 125, 125),)
SELECT * FROM test.order where total_price in (125, 125, 125, 125)
Scenario 2#
query = SELECT * FROM test.order WHERE order_id IN {} AND product_id IN {}
Tuple:
finTup=((101, 105, 106, 107), (2, 2, 2, 2))
Code 1:
frt = 'finTup[{}]'
half = ''
val = ''
i = 0
le = len(finTup)
for i in range(le):
print(i)
print(eval(frt.format(i)))
if i == le -1:
half = half + frt.format(i)
val = val + " " + frt.format(i)
else:
half = half + frt.format(i)+', '
val = val + " " + frt.format(i)+', '
temp2 = query.format(eval(val))
Code 2:
if le == 1:
query = query.format(finTup[0])
elif le == 2:
query = query.format(finTup[0], finTup[1])
elif le == 3:
query = query.format(finTup[0], finTup[1], finTup[2])
elif le == 4:
query = query.format(finTup[0], finTup[1], finTup[2], finTup[3])
Error:
temp2 = query.format(eval(val))
IndexError: tuple index out of range
Please help me to fix this.
Upvotes: 1
Views: 437
Reputation: 1525
Hello, you have this error because you are trying to provide a single argument to the format
function which expects two parameters (since you have 2 {}
).
Note: Avoid using the eval
function... That's pretty not recommended, even less in the current situation that you are. Everything can be done without having to evaluate a str
.
In what follows, I only run the code for Scenario #2, i.e.
query2 = """SELECT * FROM test.order WHERE order_id IN {} AND product_id IN {}"""
finTup = ((101, 105, 106, 107), (2, 2, 2, 2))
Let's imagine you update your code for debugging as follows:
frt = 'finTup[{}]'
half = ''
val = ''
i = 0 # btw, you don't need to initialize i here
le = len(finTup)
for i in range(le):
if i == le -1:
half = half + frt.format(i)
val = val + " " + frt.format(i)
else:
half = half + frt.format(i)+', '
val = val + " " + frt.format(i)+', '
print val
print eval(val)
temp2 = query.format(eval(val))
Your output should be:
vars[0], vars[1]
((101, 105, 106, 107), (2, 2, 2, 2))
So, imagine you write python code from the above output, what you would do is:
query.format(((101, 105, 106, 107), (2, 2, 2, 2)))
You are actually providing a single parameter of type tuple
with a two elements. But what's important here is that you provide format
with a single parameter. The format
function will try to access the second parameter, which you don't provide. It breaks.
Have a look at this SO article. It shows you how to use the *
operator. It basically transforms a list
or tuple
into a sequence of items. Perfect for functions parameters and so forth.
So, applied to your current case:
temp2 = query.format(*eval(val))
And the trick is done.
Now, let's trash the Code 1 and use what we've learn with Code 2. We need to unpack the tuple
of tuple
into parameters to feed in to format
. So, why not just do:
# I renamed `finTup` to `vars` since I don't know what it means
def get_query(query, vars):
return query.format(*vars)
It basically combines the logic of Code 1 and Code 2 into a single line.
Upvotes: 2