【发布时间】:2014-09-03 17:02:09
【问题描述】:
我在 SQL 查询的 WHERE 子句中有一个可选条件。如果参数opt_y由用户提供,则检查条件cond2 <> opt_y,否则跳过。另一个条件 (cond1 = x) 保持不变。
以下方法中,哪个更高效 & secure(避免SQL注入)。我正在使用 Django 原始查询管理器来运行我的 SQL(我了解性能取决于具体情况,但如果存在一些明显的缺陷,例如 db 引擎无法优化特定技术或无法有效使用缓存,请突出显示)。当然,如果有更好的方法,请分享。
预期查询
MyTable.objects.raw("""
SELECT id, RANK() OVER (PARTITION BY name ORDER BY age)
FROM mytable
WHERE cond1 = %s AND cond2 <> %s """, [x, opt_y])
)
方法一: CASE 语句
MyTable.objects.raw("""
SELECT id, RANK() OVER (PARTITION BY name ORDER BY age)
FROM mytable
WHERE cond1 = %s AND
CASE WHEN %s IS NULL THEN true ELSE cond2 <> %s END""", [x, opt_y, opt_y])
)
方法二:组合字符串
query = """SELECT id, RANK() OVER (PARTITION BY name ORDER BY age)
FROM mytable
WHERE cond1 = %s """
params = [x]
if opt_y:
q += """AND cond2 <> %s"""
params.append(opt_y)
MyTable.objects.raw(query, params)
方法三:逻辑运算
MyTable.objects.raw("""
SELECT id, RANK() OVER (PARTITION BY name ORDER BY age)
FROM mytable
WHERE cond1 = %s AND (%s IS NULL OR cond2 <> %s)""", [x, opt_y, opt_y])
)
更新,增加1个方法:
方法 4: 这更像是一种 hack
if not opt_y:
opt_y = -1 #Or some value that will NEVER appear in a column
MyTable.objects.raw("""
SELECT id, RANK() OVER (PARTITION BY name ORDER BY age)
FROM mytable
WHERE cond1 = %s AND cond2 <> %s""", [x, opt_y])
)
使用 Django 1.6 和 PostgreSQL 9.3
【问题讨论】:
标签: sql django postgresql django-queryset