snippetpythonMinor
Generate SQL query by loop
Viewed 0 times
sqlloopgeneratequery
Problem
I need to perform SQL query which will get products from database based on few dimensions which I will pass in URL.
Example output for /search?a1=34&a2=37&c1=50&c2=75
What do you think about my solution?
import itertools
sql_where = ''
dimensions = ['a','b', 'c', 'd', 'e', 'f', 'f2', 'g']
for dimension in dimensions:
for onetwo, direction in zip( range(1, 3), itertools.cycle('><') ):
globals()[dimension+str(onetwo)] = str( request.GET.get( dimension+str(onetwo) ) )
sql_where += " AND ( `{dimension}` {direction}= '{get_dimension}' OR '{get_dimension}' = ('None' OR '') )".format(dimension=dimension, direction=direction, get_dimension=globals()[dimension+str(onetwo)])
sql = """SELECT * FROM t_wishbone_dimensions WHERE 1=1""" + sql_where
print sqlExample output for /search?a1=34&a2=37&c1=50&c2=75
SELECT * FROM t_wishbone_dimensions
WHERE 1=1
AND ( `a` >= '34' OR '34' = ('None' OR '') )
AND ( `a` = 'None' OR 'None' = ('None' OR '') )
AND ( `b` = '50' OR '50' = ('None' OR '') )
AND ( `c` = 'None' OR 'None' = ('None' OR '') )
AND ( `d` = 'None' OR 'None' = ('None' OR '') )
AND ( `e` = 'None' OR 'None' = ('None' OR '') )
AND ( `f` = 'None' OR 'None' = ('None' OR '') )
AND ( `f2` = 'None' OR 'None' = ('None' OR '') )
AND ( `g` <= 'None' OR 'None' = ('None' OR '') )What do you think about my solution?
Solution
Since I didn't want to setup a webserver for this, I added a bare class, which should behave in the same way as your
You should avoid setting keys in
You can make your string formatting a bit easier to understand if you split it up a bit. I made the string itself a constant (avoiding having to allocate it multiple times) and used positional arguments, instead of keywords (which, admittedly, hurts the readability slightly).
Instead of doing a string addition every loop, it is better to append to a list and do one
I would also use
To improve readability you should separate the
Lastly, python has an official style guide, PEP8, which recommends having a blank after a comma in an argument list (in
Final code:
Output:
request.GET:class request:
GET = dict(a1=34, a2=37, c1=50, c2=75)You should avoid setting keys in
globals(), it clutters the namespace too much. Instead just use the default keyword of the get method of a dictionary, which will give you the specified value if the key is not present.get_dimension = request.GET.get(dim, 'None')You can make your string formatting a bit easier to understand if you split it up a bit. I made the string itself a constant (avoiding having to allocate it multiple times) and used positional arguments, instead of keywords (which, admittedly, hurts the readability slightly).
Instead of doing a string addition every loop, it is better to append to a list and do one
join at the end, because string addition means creating an intermediate new string, since strings are immutable.sql = "SELECT * FROM t_wishbone_dimensions WHERE 1=1" + "\n".join(sql_where)I would also use
itertools.product to replace your double loop, so something like:directions = {'1': '>', '2': '<'}
dimensions = ['a', 'b', 'c', 'd', 'e', 'f', 'f2', 'g']
for dimension, i in itertools.product(dimensions, ('1', '2')):
direction = directions[i]
...To improve readability you should separate the
ANDs with a newline each (like you did in your example output).Lastly, python has an official style guide, PEP8, which recommends having a blank after a comma in an argument list (in
dimensions after 'a', one was missing), as well as not adding unnecessary whitespace (so usually no str( something ), but just str(something)). Final code:
import itertools
class request:
# should handle the same same as your `request.GET`
GET = dict(a1=34, a2=37, c1=50, c2=75)
dimensions = ['a', 'b', 'c', 'd', 'e', 'f', 'f2', 'g']
DIRS = {'1': '>', '2': '<'}
AND_STR = "AND ( `{0}` {1}= '{2}' OR '{2}' = ('None' OR '') )"
sql_where = ['']
for dimension, i in itertools.product(dimensions, ('1', '2')):
val = request.GET.get(dimension+i, 'None')
sql_where.append(AND_STR.format(dimension, DIRS[i], val))
sql = "SELECT * FROM t_wishbone_dimensions WHERE 1=1" + "\n".join(sql_where)
print sqlOutput:
SELECT * FROM t_wishbone_dimensions WHERE 1=1
AND ( `a` >= '34' OR '34' = ('None' OR '') )
AND ( `a` = 'None' OR 'None' = ('None' OR '') )
AND ( `b` = '50' OR '50' = ('None' OR '') )
AND ( `c` = 'None' OR 'None' = ('None' OR '') )
AND ( `d` = 'None' OR 'None' = ('None' OR '') )
AND ( `e` = 'None' OR 'None' = ('None' OR '') )
AND ( `f` = 'None' OR 'None' = ('None' OR '') )
AND ( `f2` = 'None' OR 'None' = ('None' OR '') )
AND ( `g` <= 'None' OR 'None' = ('None' OR '') )Code Snippets
class request:
GET = dict(a1=34, a2=37, c1=50, c2=75)get_dimension = request.GET.get(dim, 'None')sql = "SELECT * FROM t_wishbone_dimensions WHERE 1=1" + "\n".join(sql_where)directions = {'1': '>', '2': '<'}
dimensions = ['a', 'b', 'c', 'd', 'e', 'f', 'f2', 'g']
for dimension, i in itertools.product(dimensions, ('1', '2')):
direction = directions[i]
...import itertools
class request:
# should handle the same same as your `request.GET`
GET = dict(a1=34, a2=37, c1=50, c2=75)
dimensions = ['a', 'b', 'c', 'd', 'e', 'f', 'f2', 'g']
DIRS = {'1': '>', '2': '<'}
AND_STR = "AND ( `{0}` {1}= '{2}' OR '{2}' = ('None' OR '') )"
sql_where = ['']
for dimension, i in itertools.product(dimensions, ('1', '2')):
val = request.GET.get(dimension+i, 'None')
sql_where.append(AND_STR.format(dimension, DIRS[i], val))
sql = "SELECT * FROM t_wishbone_dimensions WHERE 1=1" + "\n".join(sql_where)
print sqlContext
StackExchange Code Review Q#139931, answer score: 4
Revisions (0)
No revisions yet.