简体   繁体   English

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

[英]Create SQL command with a query parameter that checks for NULL but also for other values

I am trying to write a dynamic SQL command using Python / Postgres.我正在尝试使用 Python/Postgres 编写动态 SQL 命令。 In my where clause I want to use a query parameter (which is user defined) that has to look for NULL values within a code column (varchar), but in other cases also for specific numbers.在我的 where 子句中,我想使用一个查询参数(它是用户定义的),它必须在代码列 (varchar) 中查找 NULL 值,但在其他情况下也查找特定数字。

If I have to check for a certain value I use this:如果我必须检查某个值,我会使用这个:

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

However if I have to check for NULL values the SQL and more specifically the WHERE clause would have to be但是,如果我必须检查 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;

The query parameter as used in the first statement does not work for the second since it can only replace the value on the right side of the equation, but not the operator.第一个语句中使用的查询参数不适用于第二个语句,因为它只能替换等式右侧的值,而不能替换运算符。 I have read here ( https://realpython.com/prevent-python-sql-injection/#using-query-parameters-in-sql ) that table names can also be substituted using SQL identifiers provided by psycopg2, but could not find out how to replace a whole WHERE clause or at least the operator.我在这里读过( https://realpython.com/prevent-python-sql-injection/#using-query-parameters-in-sql )表名也可以使用psycopg2提供的SQL标识符替换,但找不到找出如何替换整个 WHERE 子句或至少是运算符。

Unfortunately I cannot change the NULL values in the code column (eg using a default value) since these NULL values are created through the JOIN operation.不幸的是,我无法更改代码列中的 NULL 值(例如使用默认值),因为这些 NULL 值是通过 JOIN 操作创建的。

My only option at the moment would be to have different SQL queries based on the input value, but since the SQL query is quite long (I shortened it for this question) and I have many similar queries it would result in a lot of similar code...So how can I make this WHERE clause dynamic?我目前唯一的选择是根据输入值使用不同的 SQL 查询,但是由于 SQL 查询很长(我为这个问题缩短了它)而且我有很多类似的查询,它会导致很多类似的代码...那么我怎样才能使这个 WHERE 子句动态化?

EDIT: In addition to the answer marked as correct, I want to add my own solution, which is not so elegant, but might be helpful in more complicated scenarios, as the NULL fields are replaced with the 'default' value of COALESCE:编辑:除了标记为正确的答案之外,我想添加我自己的解决方案,它不是那么优雅,但在更复杂的场景中可能会有所帮助,因为 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 : See comments of marked answer why a view is probably not necessary at all. EDIT2 :查看标记答案的评论,为什么可能根本不需要视图。

EDIT3 : This question is not helpful since it asks only for checking for NULL values. EDIT3 :这个问题没有帮助,因为它只要求检查 NULL 值。 Besides this an IF statement as shown in the answer would substantially increase my whole codebase (each query is quite long and is used often in slightly adapted ways).除此之外,答案中显示的 IF 语句会大大增加我的整个代码库(每个查询都很长,并且经常以稍微调整的方式使用)。

Consider COALESCE to give NULL a default value.考虑COALESCENULL一个默认值。 Below assumes z.code is a varchar or text.下面假设z.code是一个 varchar 或文本。 If a integer/numeric, change 'default' to a number value (eg, 9999).如果是整数/数字,请将'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

Online Demo在线演示

I dont know the phyton syntax, but this is the idea:我不知道 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
                    })

As in the solution I had linked in the comments, there's really no way around using an if block.正如我在评论中链接的解决方案一样,真的没有办法使用if块。 You can try this:你可以试试这个:

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)

If I understand you correctly, you want to be able to send in null as well as other values and have the correct result returned.如果我理解正确,您希望能够发送 null 以及其他值并返回正确的结果。 That is, the problem is with the comparsion not returning anything if the insent value is null.也就是说,问题在于如果 insent 值为空,则比较不会返回任何内容。 This would solve the problem - perhaps with a little performance decrease.这将解决问题 - 可能会稍微降低性能。

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

Best regards,此致,
Bjarni比亚尼

you can use z.code IS NOT DISTINCT FROM %(own_id)s which is like = but where NULLs are treated like normal values (ie NULL = NULL, NULL != any non-null value).您可以使用z.code IS NOT DISTINCT FROM %(own_id)s这就像=但其中 NULL 被视为正常值(即 NULL = NULL, NULL != 任何非空值)。

See Postgres comparison operators .请参阅Postgres 比较运算符

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

相关问题 我如何在 dataframe 中创建一个新的 col3 来检查多个值(如果它们在 col1 中)并检查 col2 中的值 - How do I create a new col3 in a dataframe that checks for multiple values if they are in col1 and also check for values in col2 通过不查看其他列中的 null 值来创建列 - create column by looking not null values in other columns 折叠 dataframe 基于最小 integer 值,还填充其他列的 null 字符串值 - Collapse dataframe based on minimum integer value, but also filling null string values of other columns 当参数有时可以为NULL时,如何参数化SQL查询? - How to parameterize SQL query when the parameter can sometimes be NULL? 以一种检查SQL查询的方式模拟数据库调用 - Mocking database call in a way that it checks the SQL query 如何通过查看其他列中的 null 值来创建列 - How to create columns by looking not null values in other columns 从Pandas中的其他列中的非空值创建列 - Create column from non null values in other column in Pandas SQL中是否有一个函数将插入SQL查询值“ NULL”替换为NULL或“未知”替换为NULL - Is there a function in SQL to replace an insert sql query values 'NULL' as NULL or 'unknown' as NULL Python-如何从仅包含值的sql命令创建数组? - Python - How to create an array from a sql command with just the values? 将值重新映射到其他值并提供默认值 - Remap the values to other and give default value also
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM