Python 在SqlAlchemy中,选择未测试的PostgreSQL数组无法按预期工作
我做了一个SQL查询,它复制了一行,实际上是在表中删除并插入新的行,同时按给定的时间戳拆分其原始TSRANGE字段。 据我测试,它工作得很好。下面是一个演示,以说明我的意思并为方便起见: -演示初始化 创建随机表 uid VARCHAR36主键, 我是瓦查尔20, tsrange\u字段tsrange ; 创建扩展pgcrypto;-“gen_random_uuid”函数需要 插入public.random_表uid,id,tsrange_字段 gen_random_uuid,‘random_id’,tsrange'2000-01-01','2020-01-01','['的值; -实际查询 以拆分器作为 选择uid,datetime 从随机表 加入unnestARRAY['2015-04-15'::时间戳,'2016-04-15'::时间戳,'2017-01-01'::时间戳,'2017-04-15'::时间戳]日期时间 在tsrange_字段@>datetime上 其中id='random_id' lowerrandom_table.tsrange_字段为空或lowerrandom_table.tsrange_字段!=日期时间 并且upperrandom_table.tsrange_字段为空或upperrandom_table.tsrange_字段!=日期时间 ,分为 从随机表中删除 使用拆分器 其中splitters.uid=random_table.uid 返回random_table.uid、id、tsrange_字段 插入随机_表uid、id、tsrange_字段 在id、tsrange\U字段中选择DISTINCT gen_random_uuid作为uid,id, 混乱[ 塔斯兰奇 案例 当LAGsplitters.datetime超过按拆分器划分的分区时。按拆分器划分的uid顺序。datetime不为NULL 然后Lagspitters.datetime超过按拆分器划分的分区。uid按拆分器排序。datetime ELSE lowertsrange_字段 终止 splitters.datetime, '[' , 塔斯兰奇 splitters.datetime, 案例 当LEADsplitters.datetime超过按拆分器划分的分区时。按拆分器划分的uid顺序。datetime不为NULL 然后按拆分器在分区上引导splitters.datetime.uid按拆分器排序.datetime ELSE UpperTSU字段 终止 '[' ]AS-tsu域 FROM to_be_splitted将拆分器连接到to_be_splitted.uid=splitters.uid 按TSU字段排序 返回*; 现在我想在sqlalchemy中翻译它,这就是我的问题所在。我生成了以下代码: pip安装psycopg2,sqlalchemy 从日期时间导入日期时间 从sqlalchemy导入和_,case,cast,column,column,create_引擎,delete,func, insert、MetaData、or、select、Table、VARCHAR 来自sqlalchemy.dialogs.postgresql导入数组、TSRANGE、数组 元数据=元数据 随机表=表 “随机表”,元数据, 列'uid',VARCHAR36,主键=True, 列'id',VARCHAR20, 列'tsrange_field',tsrange 引擎=创建引擎'postgresql://test:test@本地主机:5432/test' def split_rowid,*日期时间: 此函数包含翻译尝试 splits=func.unnest[datetime中dt的dt]。别名“datetime” datetime\u col=列“datetime” 拆分器= 选择[RANDOM\u TABLE.c.uid,datetime\u col] 。从随机表格中选择。连接 分裂, onclause=RANDOM\u TABLE.c.tsrange\u field.op'@>'datetime\u col .何处_ 随机_TABLE.c.id==id, 或_func.lowerRANDOM_TABLE.c.tsrange_字段==无, 函数lowerRANDOM_TABLE.c.tsrange_field.op'!='datetime_col, 或_func.upperRANDOM_TABLE.c.tsrange_字段==无, 函数upperRANDOM\u TABLE.c.tsrange\u field.op'!='datetime\u col, .cte“拆分器” 待拆分= 删除随机表 .其中splitters.c.uid==RANDOM_TABLE.c.uid .returningRANDOM\u TABLE.c.uid,RANDOM\u TABLE.c.tsrange\u字段 .cte“待分割” window_params={'partition_by':列'uid', 'order_by':datetime_col} 上一个拆分器=函数lagdatetime列**窗口参数 下一个拆分器=函数前置日期时间列**窗口参数 下界大小写=大小写 [上一个拆分器!=无,上一个拆分器], else=函数lowercolumn'tRange\u field' 上界大小写=大小写 [下一个拆分器!=无,下一个拆分器], else_uu=func.uppercolumn'tsrange_field' 拆分范围=[ func.tsrange下限大小写,日期时间列,“[”, func.tsrangedatetime列,上限大小写,[' ] 拆分查询=选择[ 函数gen\u random\u uuid.标签'uid', 函数unnestsplit\u tsranges.别名“tsrange\u field”不起作用 ].独特的 列“tsrange\u字段” .从中选择 分裂 .joinsplitters,onclause=to_be_split.c.uid==splitters.c.uid .订购 列“tsrange\u字段” 整个查询= 插入随机表 .从中选择[列'uid',列'tsrange\u field',拆分查询 .returningcolumn'uid',column'tsrange\u field' 返回整个查询 带发动机。连接为接头: query=split_row'random_id',datetime.now 进口pdb;pdb.set_跟踪 printconn.executequery.fetchall 不幸的是,它失败了,并显示以下消息:Python 在SqlAlchemy中,选择未测试的PostgreSQL数组无法按预期工作,python,postgresql,sqlalchemy,Python,Postgresql,Sqlalchemy,我做了一个SQL查询,它复制了一行,实际上是在表中删除并插入新的行,同时按给定的时间戳拆分其原始TSRANGE字段。 据我测试,它工作得很好。下面是一个演示,以说明我的意思并为方便起见: -演示初始化 创建随机表 uid VARCHAR36主键, 我是瓦查尔20, tsrange\u字段tsrange ; 创建扩展pgcrypto;-“gen_random_uuid”函数需要 插入public.random_表uid,id,tsrange_字段 gen_random_uuid,‘random_i
Traceback (most recent call last):
File "/home/tryph/sql_split/.env/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1244, in _execute_context
cursor, statement, parameters, context
File "/home/tryph/sql_split/.env/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 552, in do_execute
cursor.execute(statement, parameters)
psycopg2.ProgrammingError: can't adapt type 'Function'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "stuck.py", line 85, in <module>
print(conn.execute(query).fetchall())
File "/home/tryph/sql_split/.env/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 988, in execute
return meth(self, multiparams, params)
File "/home/tryph/sql_split/.env/lib/python3.6/site-packages/sqlalchemy/sql/elements.py", line 287, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/home/tryph/sql_split/.env/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1107, in _execute_clauseelement
distilled_params,
File "/home/tryph/sql_split/.env/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1248, in _execute_context
e, statement, parameters, cursor, context
File "/home/tryph/sql_split/.env/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1466, in _handle_dbapi_exception
util.raise_from_cause(sqlalchemy_exception, exc_info)
File "/home/tryph/sql_split/.env/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 383, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb, cause=cause)
File "/home/tryph/sql_split/.env/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 128, in reraise
raise value.with_traceback(tb)
File "/home/tryph/sql_split/.env/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1244, in _execute_context
cursor, statement, parameters, context
File "/home/tryph/sql_split/.env/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 552, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) can't adapt type 'Function'
[SQL: WITH splitters AS
(SELECT random_table.uid AS uid, datetime
FROM random_table JOIN unnest(%(unnest_3)s) AS datetime ON random_table.tsrange_field @> datetime
WHERE random_table.id = %(id_1)s AND (lower(random_table.tsrange_field) IS NULL OR (lower(random_table.tsrange_field) != datetime)) AND (upper(random_table.tsrange_field) IS NULL OR (upper(random_table.tsrange_field) != datetime))),
to_be_split AS
(DELETE FROM random_table USING splitters WHERE splitters.uid = random_table.uid RETURNING random_table.uid, random_table.tsrange_field)
INSERT INTO random_table (uid, tsrange_field) SELECT DISTINCT ON (tsrange_field) gen_random_uuid() AS uid, tsrange_field.unnest_1
FROM unnest(%(unnest_2)s) AS tsrange_field, to_be_split JOIN splitters ON to_be_split.uid = splitters.uid ORDER BY tsrange_field RETURNING uid, tsrange_field]
[parameters: {'unnest_2': [<sqlalchemy.sql.functions.Function at 0x7fba18954a20; tsrange>, <sqlalchemy.sql.functions.Function at 0x7fba18954b00; tsrange>], 'unnest_3': [datetime.datetime(2019, 5, 3, 23, 37, 1, 773118)], 'id_1': 'random_id'}]
(Background on this error at: http://sqlalche.me/e/f405)
查看生成的SQL,我注意到原始SQL查询的SELECT中的unnestARRAY[…]AS tsrange_字段在FROM子句中呈现,我不知道为什么。此外,消息psycopg2.ProgrammingError:can't adapt type'Function'没有提供很大的帮助,并且似乎与最不合理的错误呈现无关
任何关于发生了什么以及如何修复的提示都将不胜感激。正如您所指出的,有问题的部分是
split_query = select([
func.gen_random_uuid().label('uid'),
func.unnest(split_tsranges).alias('tsrange_field') # does not work
])
问题是,它用于生成适合FROM子句的命名别名,因此SQLAlchemy将其移到了那里。使用标签“tsrange\u field”生成为tsrange\u field。另一个问题是SQLAlchemy将列表按原样传递给DB-API驱动程序,而DB-API驱动程序不知道如何处理SQLAlchemy构造。在调用中包装列表,以便SQLAlchemy使用嵌套表达式呈现数组文字:
split_tsranges = array([
func.tsrange(lower_bound_case, datetime_col, '[)'),
func.tsrange(datetime_col, upper_bound_case, '[)')
])
我应该亲眼看到别名问题。。。非常感谢这个非常有用的答案。现在它工作得很好