在 Postgresql 中使用 WHERE ... IN 搜索任何文本

Search for any text with WHERE ... IN in Postgresql

我想对 returns 所有结果的通配符进行 SQL 查询。

SELECT *
FROM my_table
WHERE column1 IN ('*');

我们的想法是按需注入项目,例如:

import psycopg2
conn = psycopg2.connect(DSN)
curs = conn.cursor()

def my_func(filter='*'):
    curs.execute("""SELECT *
                    FROM my_table
                    WHERE column1 IN (%s);""" % filter)
    return curs.fetchall()

my_func(filter=['value 1', 'value 2'])
# or
my_func()

后面的(*)在my_funcfilter关键字中不起作用。有什么可以的吗?

如果我猜对了:您想要一个可以调用的函数,默认情况下,return 一切。但是如果您将参数传递给函数,您希望能够进行更窄的过滤。

您想要 IN (...) 列表等同于写作 WHERE somecol LIKE '%'。即它匹配所有可能的输入并且始终为真。然后,您可以将 '%' 变成一个查询参数,稍后您可以将其替换为其他值。

如果是: 没有 IN (...) 列表的等价物。没有办法做到这一点。 somecol IN (1, 2) 等同于 somecol = ANY (ARRAY[1,2])。 SQL 中没有等于所有参数的值。这毫无意义。

还有NULL,它不等于包括它自己在内的所有输入。所以你可以写:

NOT coalesce(somecol NOT IN (NULL), false)

...但是如果你这样做的话,你会让全世界的程序员哭泣。我什至觉得写它很脏。此外,它会强制您将整个过滤器列表写为否定(即将过滤器指定为 "get rid of these things" 而不是 "keep these things"),这甚至可能是不可能的并且可能是不切实际的。

试图不修改查询是徒劳的。即使有可能,这也是一个非常糟糕的主意,因为它 确实 效率低下。您需要使用动态 SQL.

类似于(未测试):

def my_func(filter=None):
    query = """
        SELECT *
        FROM my_table
        """
    params = []
    if filter is not None:
        query += " WHERE column1 IN (%s)"
        params.add(filter)
    curs.execute(query, tuple(params))
    return curs.fetchall()

这就是查询生成器、ORM 等存在的原因。因为 SQL 是一种很好的语言,可以准确地说出你想要什么,而对于构建不同的请求方式的变体,这是一种真正糟糕的语言。

Python 有很多这样的工具。你可能想看看它们。


旁注:您的原始代码非常不安全从不 在 SQL 中使用字符串格式。想象一下,如果有人设法欺骗您的程序将过滤器值 ');DROP TABLE my_table;-- 传递给您的代码:

curs.execute("""SELECT *
                FROM my_table
                WHERE column1 IN (%s);""" % filter)

轰!你的table.

这就是您必须使用查询参数的原因。您的代码至少应该是:

curs.execute("""SELECT *
                FROM my_table
                WHERE column1 IN (%s);""", (filter,))

详情见: