PostgreSQL v14 Psycopg2 v2.9.3
我可以直接在 PostgreSQL / pgsql 中执行此操作,但是我似乎无法在 Psycopg2 中实现它。
给出一个示例表:
CREATE TABLE accounts (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
account_name TEXT,
account_number TEXT NOT NULL,
other_account_info TEXT
)
-- Enforces uniqueness for the pair, both non-null
CREATE UNIQUE INDEX accounts_name_number_unique_idx ON accounts (account_name, account_number);
-- Enforces uniqueness for the account_number for a non-null account_name
CREATE UNIQUE INDEX accounts_number_unique_idx ON accounts (account_number) WHERE account_name IS NULL;
我想通过执行以下操作来使用 2 个字段来匹配帐户记录:
SELECT *
FROM accounts
WHERE (account_name, account_number) =ANY(VALUES('name', number'), ('name1', 'number2'))
当我直接在 psql 中运行它时,这当然工作得很好,但是我无法让 psycopg2 正确格式化 SQL。
注意:我不想简单地执行
WHERE account_name = %(account_name)s AND account_number = %(account_number)s
,因为我将有未知数量的 account_name / account_number 对进行查询,并且不想动态生成 SQL。
我尝试过以下方法:
template: str = f"""
SELECT *
FROM accounts
WHERE (account_name, account_number) = ANY(VALUES%(account_list)s)
"""
inserts: dict = {'account_list': ('account_name1', 'account_number1')}
execute(cur=_cursor, sql=template, argslist=inserts)
这有效!但是,一旦我向参数添加第二个 account_name 和 account_number 并将其设为元组的元组,它就会中断:
UndefinedFunction: operator does not exist: text = record
template: str = f"""
SELECT *
FROM accounts
WHERE (account_name, account_number) = ANY(VALUES%(account_list)s)
"""
inserts: dict = { 'account_list': (('account_name1', 'account_number1',),('account_name2', 'account_number2',)) }
execute(cur=_cursor, sql=template, argslist=inserts)
我还尝试将参数设置为列表并从 SQL 模板中删除“VALUES”,但它破坏了,我得到
DatatypeMismatch: cannot compare dissimilar column types text and unknown at record column 1
template: str = f"""
SELECT *
FROM accounts
WHERE (account_name, account_number) = ANY(%(account_list)s)
"""
inserts: dict = { 'account_list': [('account_name1', 'account_number1'),('account_name2', 'account_number2')] }
execute(cur=_cursor, sql=template, argslist=inserts)
我认识到在某些情况下,我需要强制转换各个参数,但我不知道如何在 psycopg2 中执行此操作。
任何帮助将不胜感激!
与使用
any()
相比,使用 unnest()
来创建您感兴趣的 account_name 和 account_number 对的临时表并将其加入到您的帐户表中可能更容易。
sql = "select * from accounts
join unnest(%(names)s, %(numbers)s) as query(name, number)
on query.name = accounts.account_name and
query.number = accounts.account_number;"
accounts = (('account_name1', 'account_number1',),
('account_name2', 'account_number2',))
names, numbers = = map(list, zip(*accounts))
cur.execute(sql, {"names": names, "number": numbers})