Python 中使用 psycopg2 和 POSTGRESQL 的 SELECT 查询的可选参数的正确函数定义
Correct function definition for optional parameters of a SELECT query in Python using psycopg2 with POSTGRESQL
我想 SELECT 从我的 PostgreSQL 数据库中使用函数中的可选过滤器参数,但我正在努力获得正确的语法。
def search(title: str = '', author: str = "", year: int, isbn: int):
conn = psycopg2.connect(
" dbname='mydb' user='postgres' password='pwd' host='localhost' port='5432' ")
curs = conn.cursor()
curs.execute("SELECT * FROM book WHERE title=? OR author=? OR year=? OR isbn=?",
(title, author, year, isbn))
rows = curs.fetchall()
conn.close()
return rows
然后我想通过只向函数传递一个参数(作者姓名)来进行搜索,并让 SELECT 语句能够 ignore/skip 未传递的字段。当我执行
print(search(author="John"))
输出为
Traceback (most recent call last):
File "backend.py", line 48, in <module>
print(search(author="John"))
File "backend.py", line 39, in search
(title, author, year, isbn))
psycopg2.errors.UndefinedFunction: operator does not exist: text =?
LINE 1: SELECT * FROM book WHERE title=? OR author=? OR year=? OR is...
^
HINT: No operator matches the given name and argument type. You might need to add an explicit type cast.
我知道这与 SELECT 语句的数据类型与数据库列类型不匹配有关,该错误反映了没有用于比较这两种数据类型的 = 运算符。但是我如何定义我的函数参数和 SELECT 语句来让我的查询工作?
psycopg2 使用 %s
作为字符串替换的占位符,而不是 ?
。尝试改变?到 %s,它应该可以工作。
编辑:
@Parfait 提出了一个关于你的 where 逻辑的好点。改变? to %s 将修复您的语法错误,但仍然无法修复逻辑。处理此问题的一种常见方法是将所有参数默认为 None
并将查询更改为如下内容:
curs.execute("""
SELECT * FROM BOOK
WHERE (title = %(title)s OR %(title)s IS NULL)
AND (author = %(author)s OR %(author)s IS NULL)
AND (year = %(year)s OR %(year)s IS NULL)
AND (isbn = %(isbn)s OR %(isbn)s IS NULL)""",
{"title": title, "author": author, "year": year, "isbn": isbn})
这不是最高效的方法,但可能是最简单的方法。
或者,考虑传递 None
作为默认值,转换为 NULL
并使用 SQL 的 COALESCE
到 select 第一个非空值。如果参数是 None
,则查询中的列将彼此相等,这实际上不应用过滤器。
def search(title = None, author = None, year = None, isbn = None):
conn = psycopg2.connect(
" dbname='mydb' user='postgres' password='pwd' host='localhost' port='5432' ")
sql = """SELECT * FROM book
WHERE COALESCE(title, 'N/A') = COALESCE(%s, title, 'N/A')
AND COALESCE(author, 'N/A') = COALESCE(%s, author, 'N/A')
AND COALESCE(year, -1) = COALESCE(%s, year, -1)
AND COALESCE(isbn, -1) = COALESCE(%s, isbn, -1)
"""
curs = conn.cursor()
curs.execute(sql, (title, author, year, isbn))
rows = curs.fetchall()
conn.close()
return rows
我想 SELECT 从我的 PostgreSQL 数据库中使用函数中的可选过滤器参数,但我正在努力获得正确的语法。
def search(title: str = '', author: str = "", year: int, isbn: int):
conn = psycopg2.connect(
" dbname='mydb' user='postgres' password='pwd' host='localhost' port='5432' ")
curs = conn.cursor()
curs.execute("SELECT * FROM book WHERE title=? OR author=? OR year=? OR isbn=?",
(title, author, year, isbn))
rows = curs.fetchall()
conn.close()
return rows
然后我想通过只向函数传递一个参数(作者姓名)来进行搜索,并让 SELECT 语句能够 ignore/skip 未传递的字段。当我执行
print(search(author="John"))
输出为
Traceback (most recent call last):
File "backend.py", line 48, in <module>
print(search(author="John"))
File "backend.py", line 39, in search
(title, author, year, isbn))
psycopg2.errors.UndefinedFunction: operator does not exist: text =?
LINE 1: SELECT * FROM book WHERE title=? OR author=? OR year=? OR is...
^
HINT: No operator matches the given name and argument type. You might need to add an explicit type cast.
我知道这与 SELECT 语句的数据类型与数据库列类型不匹配有关,该错误反映了没有用于比较这两种数据类型的 = 运算符。但是我如何定义我的函数参数和 SELECT 语句来让我的查询工作?
psycopg2 使用 %s
作为字符串替换的占位符,而不是 ?
。尝试改变?到 %s,它应该可以工作。
编辑:
@Parfait 提出了一个关于你的 where 逻辑的好点。改变? to %s 将修复您的语法错误,但仍然无法修复逻辑。处理此问题的一种常见方法是将所有参数默认为 None
并将查询更改为如下内容:
curs.execute("""
SELECT * FROM BOOK
WHERE (title = %(title)s OR %(title)s IS NULL)
AND (author = %(author)s OR %(author)s IS NULL)
AND (year = %(year)s OR %(year)s IS NULL)
AND (isbn = %(isbn)s OR %(isbn)s IS NULL)""",
{"title": title, "author": author, "year": year, "isbn": isbn})
这不是最高效的方法,但可能是最简单的方法。
或者,考虑传递 None
作为默认值,转换为 NULL
并使用 SQL 的 COALESCE
到 select 第一个非空值。如果参数是 None
,则查询中的列将彼此相等,这实际上不应用过滤器。
def search(title = None, author = None, year = None, isbn = None):
conn = psycopg2.connect(
" dbname='mydb' user='postgres' password='pwd' host='localhost' port='5432' ")
sql = """SELECT * FROM book
WHERE COALESCE(title, 'N/A') = COALESCE(%s, title, 'N/A')
AND COALESCE(author, 'N/A') = COALESCE(%s, author, 'N/A')
AND COALESCE(year, -1) = COALESCE(%s, year, -1)
AND COALESCE(isbn, -1) = COALESCE(%s, isbn, -1)
"""
curs = conn.cursor()
curs.execute(sql, (title, author, year, isbn))
rows = curs.fetchall()
conn.close()
return rows