0

Best practice for passing a SQL query in Python is to use (?) placeholders. I'm running into an issue where I have an IN expression for my SQL query and cannot determine how to pass the variable arguments to the placeholder. Edit: This differs from other answers (as pointed out in comments) in that other answers don't include unpacking. My working code is:

cursor = conn.cursor()
query = "Select touchtonekey, COUNT(touchtonekey) as touchedthismanytimes from vw_callhandlertraffic\
            where callhandlername = ? and createddatetime between ?\
            and ? and touchtonekey IN ('1','2') Group By touchtonekey Order by touchtonekey"

data = cursor.execute(query,'My CallHandler','2019-10-09 13:00:00',
                      '2019-12-09 13:59:59')

But when I try to remove the IN arguments with this code:

query = "Select touchtonekey, COUNT(touchtonekey) as touchedthismanytimes from vw_callhandlertraffic\
            where callhandlername = ? and createddatetime between ?\
            and ? and touchtonekey IN ? Group By touchtonekey Order by touchtonekey"

data = cursor.execute(query,'My CallHandler','2019-10-09 13:00:00',
                      '2019-12-09 13:59:59', "('1','2')")

I get:

Right hand side of IN expression must be a COLLECTION type.

And If I remove the quotes from the parenthesis, I get:

Invalid application buffer type. (-11116) (SQLBindParameter)
3
  • 1
    Does this answer your question? python list in sql query as parameter Commented Dec 18, 2019 at 19:20
  • Specifically, this answer, where you need to create placeholders. Note that some SQL dialects have limits to how many parameters you can have in an IN clause Commented Dec 18, 2019 at 19:22
  • Oops, this answer, even. They basically say the same thing. But actually, they're missing unpacking Commented Dec 18, 2019 at 19:32

2 Answers 2

1

This is almost a dupe of python list in sql query as parameter but there's a couple of things missing:

  1. You have other parameters, not just for your IN clause, so you'll need some unpacking
  2. A note about the fact that some SQL dialects (e.g. SQLite) will have limits on the number of parameters you can pass.

Corrected code:

cursor = conn.cursor()

membership_data = [1, 2] 
placeholders = ', '.join(['?' for item in membership_data])

query = """
        SELECT touchtonekey, COUNT(touchtonekey) AS touchedthismanytimes 
        FROM vw_callhandlertraffic
        WHERE callhandlername = ? AND createddatetime BETWEEN ? AND ? 
            AND touchtonekey IN ({}) 
        GROUP BY touchtonekey 
        ORDER BY touchtonekey
        """.format(placeholders) # Add the placeholders to your IN clause

data = cursor.execute(query,
                      ('My CallHandler',
                      '2019-10-09 13:00:00',
                      '2019-12-09 13:59:59',
                      *membership_data)) # Unpack the list

Note the use of *, the "splat"/"unpacking" operator to make a flat tuple of arguments to execute

Sign up to request clarification or add additional context in comments.

3 Comments

This was a perfect solution. Thank you for the help @roganjosh.
@RandyStegnerSr. if you feel that this has answered your question, please see What should I do when someone answers my question? (which applies to your previous question also)
What would I do without you @roganjosh? I appreciate you helping me on more than just the problem I had! It's users like you that make Stack Overflow so awesome.
0

While I was typing up my question I figured it out. Since I didn't see an answer on Stack Overflow (I may have just not been able to find one) I figured I would post the question and then answer it in case it helps someone else. The key is to always use the = ? syntax and then include the IN keyword in the parameter like so:

cursor = conn.cursor()

    query = "Select touchtonekey, COUNT(touchtonekey) as 
             touchedthismanytimes from vw_callhandlertraffic\
             where callhandlername = ? and createddatetime between ?\
             and ? and touchtonekey = ? Group By touchtonekey Order by\ 
             touchtonekey"

    data = cursor.execute(query,'My CallHandler','2019-10-09 13:00:00',
                                 '2019-12-09 13:59:59',"IN ('1','2')")

5 Comments

Nope, this isn't figured out. This is hard-coded. Your initial idea was on the correct lines, you just didn't quite execute it correctly.
@roganjosh agreed, you should never have to include the keyword IN as part of your parameter substitution
@roganjosh, then what is the correct way to execute? I'm not a developer, I simply created a few scripts for some telecom reporting. Any help is appreciated.
I linked to it under your question, twice
I'm sorry about that as I totally missed it. I failed to refresh page. Duly noted for the future though. Thanks for helping a noob.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.