Skip to content
Advertisement

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. 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.

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

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.

Unfortunately I cannot change the NULL values in the code column (e.g. using a default value) since these NULL values are created through the JOIN operation.

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?

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:

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.

EDIT3: This question is not helpful since it asks only for checking for NULL values. 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).

Advertisement

Answer

Consider COALESCE to give NULL a default value. Below assumes z.code is a varchar or text. If a integer/numeric, change 'default' to a number value (e.g., 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

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement