使用检查 NULL 和其他值的查询参数创建 SQL 命令
Create SQL command with a query parameter that checks for NULL but also for other values
我正在尝试使用 Python / Postgres 编写动态 SQL 命令。在我的 where 子句中,我想使用一个查询参数(这是用户定义的),它必须在代码列 (varchar) 中查找 NULL 值,但在其他情况下也会查找特定数字。
如果我必须检查某个值,我会使用这个:
cursor.execute("""
select
z.code as code
from
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id
where
z.code = %(own_id)s;
""", {
'own_id': entry
})
但是,如果我必须检查 NULL 值,SQL 更具体地说,WHERE 子句必须是
select
z.code as code
from
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id
WHERE
z.code IS NULL;
第一个语句中使用的查询参数对第二个语句不起作用,因为它只能替换等式右侧的值,而不能替换运算符。我在这里 (https://realpython.com/prevent-python-sql-injection/#using-query-parameters-in-sql) 读到 table 名称也可以使用 psycopg2 提供的 SQL 标识符来替换,但找不到如何替换整个 WHERE 子句或至少是运算符.
不幸的是,我无法更改代码列中的 NULL 值(例如,使用默认值),因为这些 NULL 值是通过 JOIN 操作创建的。
目前我唯一的选择是根据输入值进行不同的 SQL 查询,但是由于 SQL 查询很长(我针对这个问题缩短了它)而且我有很多类似的查询会导致很多类似的代码......那么我怎样才能使这个 WHERE 子句动态化呢?
编辑:
除了标记为正确的答案之外,我想添加我自己的解决方案,它不是那么优雅,但在更复杂的情况下可能会有帮助,因为 NULL 字段被替换为 COALESCE 的 'default' 值:
create view orsc as
select
coalesce(z.code), 'default') as code
from
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id;
SELECT
orsc.code as code2
from
orsc
WHERE
code2 = 'default'; //or any other value
EDIT2:请参阅标记答案的评论,为什么可能根本不需要视图。
EDIT3:此 没有帮助,因为它仅要求检查 NULL 值。除此之外,答案中显示的 IF 语句会大大增加我的整个代码库(每个查询都很长,并且经常以稍微调整的方式使用)。
我不懂python的语法,但是思路是这样的:
condition String;
if own_id = "NULL"{
condition= " z.code IS NULL ";
}else{
condition= " z.code = " + own_id;
}
cursor.execute("""
select
z.code as code
from
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id
where
%(condition);
""", {
'condition': entry
})
正如我在评论中链接的解决方案一样,确实没有办法使用 if
块。你可以试试这个:
pre_query="""
select
z.code as code
from
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id
where
"""
args={entry}
zcode="z.code = %s"
if entry == None:
zcode="z.code IS NULL"
args={}
end_query=";" // other conditions
full_query=pre_query+zcode+end_query
cursor.execute(full_query,args)
如果我没理解错的话,您希望能够发送 null 以及其他值并返回正确的结果。也就是说,问题在于如果输入值为 null,则比较不返回任何内容。这将解决问题——也许性能会有所下降。
cursor.execute("""
select
z.code as code
from
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id
where
z.code is not distinct from %(own_id)s;
""", {
'own_id': entry
})
此致,
比亚尼
考虑COALESCE
给NULL
一个默认值。下面假定 z.code
是一个 varchar 或文本。如果 integer/numeric,请将 'default'
更改为数字值(例如 9999)。
sql = """SELECT
z.code as code
FROM
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id
WHERE
COALESCE(z.code, 'default') = %(own_id)s;
"""
cursor.execute(sql, {'own_id': entry})
cursor.execute(sql, {'own_id': 'default'}) # RETURNS NULLs IN z.code
您可以使用 z.code IS NOT DISTINCT FROM %(own_id)s
,它类似于 =
,但 NULL 被视为正常值(即 NULL = NULL,NULL != 任何非空值)。
我正在尝试使用 Python / Postgres 编写动态 SQL 命令。在我的 where 子句中,我想使用一个查询参数(这是用户定义的),它必须在代码列 (varchar) 中查找 NULL 值,但在其他情况下也会查找特定数字。
如果我必须检查某个值,我会使用这个:
cursor.execute("""
select
z.code as code
from
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id
where
z.code = %(own_id)s;
""", {
'own_id': entry
})
但是,如果我必须检查 NULL 值,SQL 更具体地说,WHERE 子句必须是
select
z.code as code
from
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id
WHERE
z.code IS NULL;
第一个语句中使用的查询参数对第二个语句不起作用,因为它只能替换等式右侧的值,而不能替换运算符。我在这里 (https://realpython.com/prevent-python-sql-injection/#using-query-parameters-in-sql) 读到 table 名称也可以使用 psycopg2 提供的 SQL 标识符来替换,但找不到如何替换整个 WHERE 子句或至少是运算符.
不幸的是,我无法更改代码列中的 NULL 值(例如,使用默认值),因为这些 NULL 值是通过 JOIN 操作创建的。
目前我唯一的选择是根据输入值进行不同的 SQL 查询,但是由于 SQL 查询很长(我针对这个问题缩短了它)而且我有很多类似的查询会导致很多类似的代码......那么我怎样才能使这个 WHERE 子句动态化呢?
编辑: 除了标记为正确的答案之外,我想添加我自己的解决方案,它不是那么优雅,但在更复杂的情况下可能会有帮助,因为 NULL 字段被替换为 COALESCE 的 'default' 值:
create view orsc as
select
coalesce(z.code), 'default') as code
from
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id;
SELECT
orsc.code as code2
from
orsc
WHERE
code2 = 'default'; //or any other value
EDIT2:请参阅标记答案的评论,为什么可能根本不需要视图。
EDIT3:此
我不懂python的语法,但是思路是这样的:
condition String;
if own_id = "NULL"{
condition= " z.code IS NULL ";
}else{
condition= " z.code = " + own_id;
}
cursor.execute("""
select
z.code as code
from
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id
where
%(condition);
""", {
'condition': entry
})
正如我在评论中链接的解决方案一样,确实没有办法使用 if
块。你可以试试这个:
pre_query="""
select
z.code as code
from
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id
where
"""
args={entry}
zcode="z.code = %s"
if entry == None:
zcode="z.code IS NULL"
args={}
end_query=";" // other conditions
full_query=pre_query+zcode+end_query
cursor.execute(full_query,args)
如果我没理解错的话,您希望能够发送 null 以及其他值并返回正确的结果。也就是说,问题在于如果输入值为 null,则比较不返回任何内容。这将解决问题——也许性能会有所下降。
cursor.execute("""
select
z.code as code
from
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id
where
z.code is not distinct from %(own_id)s;
""", {
'own_id': entry
})
此致,
比亚尼
考虑COALESCE
给NULL
一个默认值。下面假定 z.code
是一个 varchar 或文本。如果 integer/numeric,请将 'default'
更改为数字值(例如 9999)。
sql = """SELECT
z.code as code
FROM
s_order as o
LEFT JOIN
s_code as z ON o.id = z.id
WHERE
COALESCE(z.code, 'default') = %(own_id)s;
"""
cursor.execute(sql, {'own_id': entry})
cursor.execute(sql, {'own_id': 'default'}) # RETURNS NULLs IN z.code
您可以使用 z.code IS NOT DISTINCT FROM %(own_id)s
,它类似于 =
,但 NULL 被视为正常值(即 NULL = NULL,NULL != 任何非空值)。