繁体   English   中英

使用查询参数创建 SQL 命令,该参数检查 NULL 和其他值

[英]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 )表名也可以使用psycopg2提供的SQL标识符替换,但找不到找出如何替换整个 WHERE 子句或至少是运算符。

不幸的是,我无法更改代码列中的 NULL 值(例如使用默认值),因为这些 NULL 值是通过 JOIN 操作创建的。

我目前唯一的选择是根据输入值使用不同的 SQL 查询,但是由于 SQL 查询很长(我为这个问题缩短了它)而且我有很多类似的查询,它会导致很多类似的代码...那么我怎样才能使这个 WHERE 子句动态化?

编辑:除了标记为正确的答案之外,我想添加我自己的解决方案,它不是那么优雅,但在更复杂的场景中可能会有所帮助,因为 NULL 字段被替换为 COALESCE 的“默认”值:

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 语句会大大增加我的整个代码库(每个查询都很长,并且经常以稍微调整的方式使用)。

考虑COALESCENULL一个默认值。 下面假设z.code是一个 varchar 或文本。 如果是整数/数字,请将'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

在线演示

我不知道 phyton 语法,但这是一个想法:

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 以及其他值并返回正确的结果。 也就是说,问题在于如果 insent 值为空,则比较不会返回任何内容。 这将解决问题 - 可能会稍微降低性能。

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
                    })

此致,
比亚尼

您可以使用z.code IS NOT DISTINCT FROM %(own_id)s这就像=但其中 NULL 被视为正常值(即 NULL = NULL, NULL != 任何非空值)。

请参阅Postgres 比较运算符

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM