在Python 3.8中,我使用pg8000 1.21.3调用Postgress 11存储过程,该存储过程将自定义数据类型数组作为参数。下面是概念模式和存储过程的工作证明:
DROP PROCEDURE IF EXISTS myproc;
DROP TABLE IF EXISTS mytable;
DROP TYPE mytype;
CREATE TYPE mytype AS (
an_int INT,
a_bool BOOL,
a_decimal DECIMAL,
a_string TEXT
);
CREATE TABLE mytable(
id SERIAL PRIMARY KEY,
an_int INT,
a_bool BOOL,
a_decimal DECIMAL,
a_string TEXT
);
CREATE PROCEDURE myproc(
IN myarray mytype[]
)
AS $$
BEGIN
INSERT INTO mytable(
an_int,
a_bool,
a_decimal,
a_string
) SELECT
an_int,
a_bool,
a_decimal,
a_string
FROM
unnest(myarray);
END;
$$
LANGUAGE 'plpgsql';
CALL myproc(
array[
(1, 1, 2.1, 'foo'),
(NULL, NULL, NULL, NULL)
]::mytype[]
);
SELECT * FROM mytable;
select的输出是:
id | an_int | a_bool | a_decimal | a_string
----+--------+--------+-----------+----------
1 | 1 | t | 2.1 | foo
2 | | | |
(2 rows)
这意味着当我从SQL调用存储过程时,我可以创建一个全为空值的行。
我现在正在尝试使用pg8000从Python实现相同的功能。要传递一个包含一些null值的数组,唯一可行的方法是用一个空字符串替换None
。这适用于整数和文本数据类型,但对于布尔和小数则失败:
import pg8000
arr = [(1, True, 3.2, 'foo'),
(None, True, 3.2, 'foo'),
(1, True, 3.2, None),
(1, False, 3.2, 'foo'),
(1, None, 3.2, 'foo'), # <---- boolean null fails
(1, False, None, 'foo'), # <---- decimal null fails
]
sql = """CALL myproc(%s::mytype[]);"""
stm = [str(item) for item in arr]
stm = [item.replace('None', '') for item in stm]
with pg8000.connect(host="localhost", database="mydb", user="myuser", password="mypass") as con:
with con.cursor() as cursor:
cursor.execute(
sql,
args=(stm,)
)
con.commit()
误差为:pg8000.dbapi.ProgrammingError: {'S': 'ERROR', 'V': 'ERROR', 'C': '22P02', 'M': 'invalid input syntax for type boolean: " "', 'F': 'bool.c', 'L': '154', 'R': 'boolin'}
如何使用pg8000参数插值为所有这些数据类型传递空值,也就是说,不对sql语句进行硬编码?
1条答案
按热度按时间dnph8jn41#
使用pg8000的1.29.6版本,您应该能够:
因为pg8000现在将
tuple
解释为复合类型。