elegent sql building

Eddie Corns eddie at holyrood.ed.ac.uk
Thu Dec 20 14:01:42 EST 2001


cmedcoff at home.com (Charles Medcoff) writes:

>I recently read (parts of) "Dive Into Python" which inspired me to
>write something like the following:


>def buildSql(ids, engineTypes, transTypes):
>    return "SELECT * FROM vehicle WHERE id in (%s) AND engineType IN
>(%s) AND transType IN (%s)" % \
>    (",".join(["'%s'" % (id) for id in ids]), 
>     ",".join(["'%s'" % (e ) for e  in engineTypes]), 
>     ",".join(["'%s'" % (t ) for t in transTypes]))

>print buildSql(['vin1', 'vin2', 'vin3'], ['4cy', '6cy'], ['4sp',
>'5sp'] )

>Now you can imagine where the inputs to buildSql might trickle down
>from a user interface.  This is nice; perhaps even elegent.  There is
>a problem with it though.  What if any one of, or all of, the inputs 
>are empty?  The code needs to figure out whether to include the
>"WHERE" and the "AND"'s and where to put them.  A chain of if's would
>be inelegent.  Is there a better solution?  Suggestions appreciated.

First attempt:

def buildSql(ids, engineTypes, transTypes):
    return " WHERE ".join(filter(None,["SELECT * FROM vehicle"," AND ".join(filter(None,["%s IN (%s)" % (b,a) * max(0,min(1,len(a))) for a,b in zip([",".join(["'%s'" % i for i in x]) for x in [ids,engineTypes,transTypes]],["id","engineType","transType"])]))]))

There's a fairly nasty trick in there!

Second (much better) attempt:

def buildSql(ids, engineTypes, transTypes):
    return " WHERE ".join(filter(None,["SELECT * FROM vehicle"," AND ".join([" IN ".join ([b,"(%s)"%a]) for a,b in zip([",".join(["'%s'" % i for i in x]) for x in [ids,engineTypes,transTypes]],["id","engineType","transType"]) if a])]))


>>> print buildSql(['vin1', 'vin2', 'vin3'], ['4cy', '6cy'], ['4sp','5sp'] )
SELECT * FROM vehicle WHERE id IN ('vin1','vin2','vin3') AND engineType IN ('4cy','6cy') AND transType IN ('4sp','5sp')

>>> print buildSql(['vin1', 'vin2', 'vin3'], ['4cy', '6cy'], [] )
SELECT * FROM vehicle WHERE id IN ('vin1','vin2','vin3') AND engineType IN ('4cy','6cy')

>>> print buildSql(['vin1', 'vin2', 'vin3'], [], [] )
SELECT * FROM vehicle WHERE id IN ('vin1','vin2','vin3')

>>> print buildSql([], [], [] )
SELECT * FROM vehicle

>>> print buildSql([], ['4cy', '6cy'], [] )
SELECT * FROM vehicle WHERE engineType IN ('4cy','6cy')



Homework exercise: fill in the blank to generalise it better :)

def buildSql(table, values, names):
  return ...


buildSql ("engines", [[1,2],[],[],[11,22]], ["id","type","size","weight"])
--> SELECT * FROM engines WHERE id IN ('1','2') AND weight IN ('11','22')


At the end of the day I think using 'if' would be more sane!!

Eddie



More information about the Python-list mailing list