1

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.

4b0
  • 21,981
  • 30
  • 95
  • 142
  • Code 2 is a static one, which I need to replace with dynamic code. – Lavanya Komarasamy Sep 24 '18 at 11:31
  • Give a suitable input and output – Atul Shanbhag Sep 24 '18 at 11:32
  • 2
    Please don't make more work for other people by vandalizing your posts. By posting on the Stack Exchange network, you've granted a non-revocable right, under the [CC BY-SA 3.0 license](//creativecommons.org/licenses/by-sa/3.0/), for Stack Exchange to distribute that content (i.e. regardless of your future choices). By Stack Exchange policy, the non-vandalized version of the post is the one which is distributed. Thus, any vandalism will be reverted. If you want to know more about deleting a post please see: [How does deleting work?](//meta.stackexchange.com/q/5221) – Nick is tired Jul 25 '19 at 10:28

1 Answers1

2

TL;DR

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

Step 1: Debugging

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.


Step 2: Fixing the code

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.


Step 3: Optimization

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.

Léopold Houdin
  • 1,515
  • 13
  • 18