我尝试使用SQLAlchemy Core创建以下PostgreSQL查询:
SELECT DISTINCT ON (carrier) carrier,
LAST_VALUE(ground) OVER wnd AS ground,
LAST_VALUE(destinationzipstart) OVER wnd AS destinationzipstart,
LAST_VALUE(destinationzipend) OVER wnd AS destionationzipend
FROM tblshippingzone
WHERE sourcezipstart <= 43234
AND sourcezipend >= 43234
AND destinationzipstart NOT BETWEEN 99500 AND 99950
AND destinationzipstart NOT BETWEEN 96700 AND 96899
AND destinationzipstart >= 1000
AND (contiguous IS NULL OR contiguous = True)
AND ground IS NOT NULL
WINDOW wnd AS (
PARTITION BY carrier ORDER BY ground DESC, destinationzipstart);
这是我到目前为止所做的:
# Short-hand for accessing cols
all_cols = ShippingZoneDAL._table.c
# Window params
window_p = {'partition_by': all_cols.carrier,
'order_by': [desc(all_cols.ground), all_cols.destination_zip_start]}
# Select columns
select_cols = [distinct(all_cols.carrier).label('carrier'),
over(func.last_value(all_cols.ground), **window_p).label('ground'),
over(func.last_value(all_cols.destination_zip_start), **window_p).label('destination_zip_start'),
over(func.last_value(all_cols.destination_zip_end), **window_p).label('destination_zip_end')]
# Filter exprs
exprs = [all_cols.source_zip_start <= 43234,
all_cols.source_zip_end >= 43234,
~all_cols.destination_zip_start.between(99500, 99950), # Alaska zip codes
~all_cols.destination_zip_start.between(96700, 96899), # Hawaii zip codes
all_cols.destination_zip_start >= 1000, # Eliminates unusual territories
or_(all_cols.contiguous == True, all_cols.contiguous == None),
all_cols.ground != None]
# Build query
query = select(*select_cols).where(and_(*exprs))
但是在构建查询时出现错误:
ArgumentError: FROM expression expected
我在这里缺少什么想法?
奖励积分:
我最初希望窗口功能是这样的:
WINDOW wnd AS (
PARTITION BY carrier ORDER BY ground
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING);
但根据这项支持请求,似乎sqlalchemy并不支持“无限制前进和无约束”之间的“行”: https://bitbucket.org/zzzeek/sqlalchemy/issue/3049/support-range-specificaiton-in-window
有没有办法使用该条款,还是没有?
答案 0 :(得分:4)
这主要只是将各种方法重新安排到工作秩序中。如果有人碰到类似的东西,这就是答案:
# Short-hand for accessing cols
all_cols = ShippingZoneDAL._table.c
# Window params
window_p = {'partition_by': all_cols.carrier,
'order_by': [desc(desc(all_cols.ground)), all_cols.destination_zip_start]}
# Select columns
select_cols = select(
[all_cols.carrier,
func.last_value(all_cols.ground).over(**window_p).label(shipment_method),
func.last_value(all_cols.destination_zip_start).over(**window_p).label('destination_zip_start'),
func.last_value(all_cols.destination_zip_end).over(**window_p).label('destination_zip_end')])
# Filter exprs
exprs = [all_cols.source_zip_start <= 43234,
all_cols.source_zip_end >= 43234,
~all_cols.destination_zip_start.between(99500, 99950),
~all_cols.destination_zip_start.between(96700, 96899),
all_cols.destination_zip_start >= 1000,
or_(all_cols.contiguous == True, all_cols.contiguous == None),
all_cols.ground != None]
# Build query
query = select_cols.where(and_(*exprs)).distinct(all_cols.carrier)
使用上述解决方案时要记住的主要注意事项:
在此方案中,SQLAlchemy Core未见select(*select_cols)
与select([all_cols.ground, etc])
等效。可能是因为over
方法需要在select的上下文中计算,否则你将丢失对FROM表的引用。
要使用PostgreSQL中的DISTINCT ON
,请确保在主要选择之后 。如果仅在SELECT本身中使用,它将成为该列的标准DISTINCT子句。
请注意标签本身 - 返回的列只会定义key
,而不会像对象的普通表列那样name
。
如果有人还想解决我的奖励问题,请随意:)仍然不确定是否有一种方法可以在SQLAlchemy中使用它。