tags:

views:

1293

answers:

5

Does anyone know if there's a way to automatically expand a list in Python, separated by commas? I'm writing some Python code that uses the MySQLdb library, and I'm trying to dynamically update a list of rows in a MySQL database with certain key values.

For instance, in the code below, I'd like to have the numeric values in the record_ids list expand into a SQL "IN" clause.

import MySQLdb
record_ids = [ 23, 43, 71, 102, 121, 241 ]

mysql = MySQLdb.connect(user="username", passwd="secret", db="apps")
mysql_cursor = mysql.cursor()

sqlStmt="UPDATE apps.sometable SET lastmod=SYSDATE() where rec_id in ( %s )"

mysql_cursor.execute( sqlStmt, record_ids )
mysql.commit()

Any help would be appreciated!

+10  A: 

try:

",".join( map(str, record_ids) )

",".join( list_of_strings ) joins a list of string by separating them with commas

if you have a list of numbers, map( str, list ) will convert it to a list of strings

hasen j
Thanks, this did the trick!
m0j0
+2  A: 

Further to the given answers, note that you may want to special case the empty list case as "where rec_id in ()" is not valid SQL, so you'll get an error.

Also be very careful of building SQL manually like this, rather than just using automatically escaped parameters. For a list of integers, it'll work, but if you're dealing with strings received from user input, you open up a huge SQL injection vulnerability by doing this.

Brian
+1 Please Use Bind Variables. http://stackoverflow.com/questions/1973/what-is-the-best-way-to-avoid-sql-injection-attacks
S.Lott
This will only be reading data from a database and updating data. It will never be using data entered from the Internet.
m0j0
Careful: lots of data in databases is ultimately entered by users. Even if your case is perfectly safe, some later corder with a similar problem may decide to copy existing code. It's a good idea to care about these things even when its safe. Better to reinforce and exhibit good habits than bad.
Brian
+1  A: 

I do stuff like this (to ensure I'm using bindings):

sqlStmt=("UPDATE apps.sometable SET lastmod=SYSDATE() where rec_id in (%s)"
    % ', '.join(['?' for n in record_ids]))

mysql_cursor.execute(sqlStmt, record_ids)
mysql.commit()

This works for all dynamic lists you want to bind without leaving you susceptible to SQL injection attacks.

Dustin
I don't think question marks work for MySQL bindings.
m0j0
That is the downside of python's DB API. I've done the above for sqlite and postgres, but it's up to the driver to decide how bindings work. The same principle applies, though. Generate bindings, and feed in the data.
Dustin
A: 

Slightly different alternative to Dustin's answer:

sqlStmt=("UPDATE apps.sometable SET lastmod=SYSDATE() where rec_id in (%s)"
    % ', '.join(['?' * len(record_ids])))
Dave
That doesn't expand properly, but this does: ', '.join('?' * len(record_ids)) -- I kind of like that, though it feels slightly wrong.
Dustin
A: 

Alternitavely, using replace:

sqlStmt="UPDATE apps.sometable SET lastmod=SYSDATE() where rec_id in " +
    record_ids.__str__().replace('[','(').replace(']',')')
Joao