'Use a Python f-string to build an SQL query 'IN' clause
I'm trying to use an f-string in Python to build my SQL query.
The query below seems fine:
code = ('123', '234')
print(f"select * from tbl where code in {code} ")
Output:
"select * from tbl where code in ('123', '234') "
However, if there is only one element in the tuple, it does not work:
code = ('123')
print(f"select * from tbl where code in {code} ")
Output:
select * from tbl where code in 123
Why does that happen? What's the best way to solve the issue? I can use a condition to check the tuple length, but I feel like there should be a better way...
Solution 1:[1]
('123')
is not a tuple. Python interprets it simply as a string, '123'
. In order to get a tuple with a single element you need to add a comma after the element: ('123',)
. Then the code
code = ('123',)
print( f"select * from tbl where code in {code} ")
gives:
select * from tbl where code in ('123',)
However, this is still not good since now the comma appears in the query. This can be fixed with some more formatting:
code = ('123',)
scode = ", ".join(f"'{s}'" for s in code)
print( f"select * from tbl where code in ({scode}) ")
This gives:
select * from tbl where code in ('123')
This will work for tuples of any size. For example,
code = ('123', '456')
scode = ", ".join(f"'{s}'" for s in code)
print( f"select * from tbl where code in ({scode}) ")
gives:
select * from tbl where code in ('123', '456')
If the additional comma in a tuple with a single element seems easy to miss, you can use the above code but with lists instead of tuples. So: code = ['123']
or code = ['123', '456']
.
Solution 2:[2]
I normally do it to inject parameters and let PyMySQL, or whatever you use, inject the values.
code = ('123', '234')
# The below will produce a string %s,%s
format_strings = ','.join(['%s'] * len(code))
# The query will end up being:
# select * from tbl where code in(%s,%s)
sql_query = f"select * from tbl where code in({format_strings})"
with connection.cursor() as cursor:
cursor.execute(sql_query, code)
For the second, as bb1 mentioned, it's not technically a tuple. You'll need to append a comma after the last element.
code = ('123',)
# The below will produce a string %s,%s
format_strings = ','.join(['%s'] * len(code))
# The query will end up being:
# select * from tbl where code in(%s)
sql_query = f"select * from tbl where code in({format_strings})"
with connection.cursor() as cursor:
cursor.execute(sql_query, code)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Peter Mortensen |
Solution 2 | Peter Mortensen |