2014-06-28 15 views
3

我試圖創建一個使用SQLAlchemy的核心下列PostgreSQL的查詢:SQLAlchemy的核心:創建LAST_VALUE窗函數對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的不支持「行之間UNBOUNDED PRECEDING和無界關注對象」,基於在這個支持請求: https://bitbucket.org/zzzeek/sqlalchemy/issue/3049/support-range-specificaiton-in-window

有沒有辦法使用該條款,或沒有?

回答

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的核心將不會看到select(*select_cols)等同於select([all_cols.ground, etc])在這種情況下。可能是因爲over方法需要在select的上下文中計算,否則您將失去對FROM表的引用。

  • 要使用DISTINCT ON和PostgreSQL,確保一次選擇後的不同來。如果僅用於SELECT本身,它將成爲該列的標準DISTINCT子句。

  • 小心標籤本身 - 返回的列只會定義key,而不是name就像來自對象的普通表列。

如果有人還想對付我獎金問題,隨意:)不過不知道是否有在SQLAlchemy中尚未使用的方式。