在 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_func
的filter
关键字中不起作用。有什么可以的吗?
如果我猜对了:您想要一个可以调用的函数,默认情况下,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,))
详情见:
- SQL injection
- bobby-tables.com
- psycopg2 documentation - 阅读有关传递查询参数的部分
我想对 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_func
的filter
关键字中不起作用。有什么可以的吗?
如果我猜对了:您想要一个可以调用的函数,默认情况下,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,))
详情见:
- SQL injection
- bobby-tables.com
- psycopg2 documentation - 阅读有关传递查询参数的部分