使用psycopg2和POSTGRESQL在Python中更正SELECT查询的可选参数的函数定义

使用psycopg2和POSTGRESQL在Python中更正SELECT查询的可选参数的函数定义,python,sql,python-3.x,postgresql,psycopg2,Python,Sql,Python 3.x,Postgresql,Psycopg2,我想在函数中使用可选的过滤器参数从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.c

我想在函数中使用可选的过滤器参数从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语句能够忽略/跳过尚未传递的字段。当我执行

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.
回溯(最近一次呼叫最后一次):
文件“backend.py”,第48行,在
打印(搜索(author=“John”))
搜索中第39行的文件“backend.py”
(标题、作者、年份、isbn))
psycopg2.errors.UndefinedFunction:运算符不存在:text=?
第1行:从书名=?或作者=?或年份=?还是。。。
^
提示:没有与给定名称和参数类型匹配的运算符。您可能需要添加显式类型转换。

我理解这与SELECT语句的数据类型和数据库列类型之间的不匹配有关,并且该错误反映了没有用于比较这两种数据类型的=运算符。但是如何定义函数参数和SELECT语句以使查询工作?

psycopg2使用
%s
作为字符串替换的占位符,而不是
。试着换一下衣服?到%s,它应该可以工作

编辑: @关于你的where逻辑,冻糕提出了一个很好的观点。改变?到%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})

这不是最有效的方法,但它可能是最简单的。

< P>可选地,考虑传递<代码> No.<代码>作为默认值,将其转换为<代码> NUL>代码>,并使用SQL的<代码> CueSeCs<代码>来选择第一个非空值。如果参数为
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

谢谢现在感觉有点傻-我以前有一个sqlite数据库。我的逻辑对我来说似乎很好,至少它返回了正确的结果。避免在此处发布代码和结果,因为它不打算放在注释中。@oldnoob。。。如果您的所有字符串列都不维护空值,则会出现这种情况。调用零长度字符串,
'
,与
NULL
不同。将行的
作者
字段设置为
NULL
后,我的查询仍然能够包括和排除使用各种参数组合的行搜索,为该特定字段返回
None
。这不需要对每个列进行NOTNULL约束吗?或者使用
不同,而不是
=
?@Jeremy,说得好<代码>合并
应位于等式的两侧。