Python 使用一个查询参数创建SQL命令,该参数不仅检查NULL值,还检查其他值

Python 使用一个查询参数创建SQL命令,该参数不仅检查NULL值,还检查其他值,python,sql,postgresql,psycopg2,Python,Sql,Postgresql,Psycopg2,我正在尝试使用Python/Postgres编写一个动态SQL命令。在where子句中,我希望使用一个查询参数(由用户定义),该参数必须在代码列(varchar)中查找空值,但在其他情况下也要查找特定的数字 如果我必须检查某个值,我会使用以下方法: cursor.execute(""" select z.code as code from

我正在尝试使用Python/Postgres编写一个动态SQL命令。在where子句中,我希望使用一个查询参数(由用户定义),该参数必须在代码列(varchar)中查找空值,但在其他情况下也要查找特定的数字

如果我必须检查某个值,我会使用以下方法:

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
                    })
但是,如果我必须检查空值,则必须检查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;
第一条语句中使用的查询参数不适用于第二条语句,因为它只能替换等式右侧的值,而不能替换运算符。我在这里读到()表名也可以使用psycopg2提供的SQL标识符进行替换,但无法找到如何替换整个WHERE子句或至少替换运算符

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

目前我唯一的选择是根据输入值使用不同的SQL查询,但是由于SQL查询很长(我在这个问题中缩短了它),而且我有许多类似的查询,这将导致许多类似的代码……那么我如何使这个WHERE子句成为动态的呢

编辑: 除了标记为正确的答案外,我还想添加我自己的解决方案,该解决方案不太优雅,但在更复杂的场景中可能会有所帮助,因为空字段被替换为“默认”值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:这没有帮助,因为它只要求检查空值。除此之外,答案中所示的IF语句将极大地增加我的整个代码库(每个查询都很长,并且经常以稍微调整的方式使用)

我不知道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值为null,则compassion不会返回任何内容。这将解决问题——也许性能会略有下降

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

致以最诚挚的问候,

Bjarni

考虑
合并
NULL
提供默认值。下面假设
z.code
是一个varchar或文本。如果是整数/数字,请将
“默认值”
更改为数字值(例如9999)


您可以使用
z。code与%(own_id)s
没有区别,后者类似于
=
,但空值被视为正常值(即空值=空值,空值!=任何非空值)


请参阅。

没有,很遗憾没有。答案建议使用IF生成一个或另一个SQL命令,这是可以工作的,但对我来说不适合如上所述。@richyen您能确认链接的讨论没有回答我的问题吗?所以给我一个盒子,上面写着一个类似的问题可能会回答我的问题,它不会消失。或者,也许我的问题的投票会有所帮助…谢谢你优雅的解决方案。我发现了一个类似但更复杂的解决方案,我把它作为编辑添加到了我的问题中。很高兴听到这个消息,也很高兴能提供帮助。但是,对于您的解决方案,为什么要创建视图?在别处使用?它在功能上与此解决方案没有区别。视图仍在运行时处理。如果介绍,也许考虑A。谢谢第二次!我在第一步中使用了视图,因为我需要在第二个查询中执行求和操作。以前从未听说过CTE,但它们使整个查询更加紧凑,现在已经利用了它!
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