2016-11-28 128 views
1

我有一個模式,其中包含公司的地址列表。對於報告中,我需要做的這些公司的一些過濾和包括他們在所有地區的列表查詢我想寫的相關核心部分是:我使用如何創建從子查詢返回數組的查詢?

SELECT name, ARRAY(SELECT DISTINCT state 
        FROM location 
        WHERE location.foo_id=foo.id) 
FROM foo; 

的基本代碼測試這個是非常簡單的(注意,我使用PostgreSQL作爲我的數據庫):

import sqlalchemy as sa 
from sqlalchemy.sql import distinct, func 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import relationship, sessionmaker 


Base = declarative_base() 


class Company(Base): 
    __tablename__ = 'company' 
    id = sa.Column(sa.Integer, sa.Sequence('company_id_seq'), primary_key=True) 
    name = sa.Column(sa.Unicode) 


class Location(Base): 
    __tablename__ = 'location' 
    id = sa.Column(sa.Integer, sa.Sequence('location_id_seq'), primary_key=True) 
    company_id = sa.Column(sa.Integer, sa.ForeignKey(Company.id)) 
    company = relationship(Company, backref='locations') 
    state = sa.Column(sa.Unicode, nullable=False) 

engine = sa.create_engine('postgresql:///pytest', echo=False) 
Base.metadata.create_all(engine) 
Session = sessionmaker(bind=engine) 

session = Session() 
for (name, states) in [ 
     ('Acme', ['Alabama', 'Georgia']), 
     ('Example Inc', ['Florida', 'Florida']), 
     ('Empty', [])]: 
    session.add(Company(
     name=name, 
     locations=[Location(state=s) for s in states])) 
session.flush() 

# Desired result: 
# 
# [('Acme', ['Alabama', 'Georgia']), 
# ('Example Inc', ['Florida']), 
# ('Empty', [])] 

states_per_foo = session.query(distinct(Location.state))\ 
    .filter(Location.company_id == Company.id) 
search_query = session.query(Company, func.array(states_per_foo)) 
print(search_query.all()) 

我已經試過到目前爲止失敗,併產生各種SQLAlchemy的錯誤或無效SQL所有排列。

+0

更新我的產生正是你正在尋找 – van

回答

3

下面的代碼:

sq = (
    session 
    .query(Location.state.distinct()) 
    .filter(Location.company_id == Company.id) 
    .correlate(Company) 
    .as_scalar() 
) 
q = session .query(Company.name, func.array(sq).label("states")) 

正好產生(忽略一些額外的括號)你想編寫SQL查詢:

SELECT company.name, 
     array(
       (SELECT DISTINCT location.state AS anon_1 
       FROM location 
       WHERE location.company_id = company.id)) AS states 
FROM company 

,其結果是:

('Acme', ['Georgia', 'Alabama']) 
('Example Inc', ['Florida']) 
('Empty', []) 

原始版本: 稍作修改:添加.distinct()爲了刪除重複項。

不是SQL查詢你所尋找的,但下面的查詢結果:

q = (
    session 
    .query(Company.name, func.array_agg(Location.state.distinct())) 
    .outerjoin(Location) 
    .group_by(Company.name) 
) 
for x in q.all(): 
    print(x) 

(通過Company.name因爲分組排序):

('Acme', ['Alabama', 'Georgia']) 
('Empty', [None]) 
('Example Inc', ['Florida']) 

[None]而不是[]Empty。這可以用特殊的方式處理。

0
import sqlalchemy as sa 
engine = sa.create_engine('postgresql://...') 
result = engine.execute('''SELECT name, 
           ARRAY(SELECT DISTINCT state 
            FROM location 
            WHERE location.foo_id=foo.id) 
          FROM foo''') 
rows = result.fetchall() 
for row in rows: 
    print(type(row[0])) # <class 'str'> 
    print(row[0])  # Acme 
    print(type(row[1])) # <class 'list'> 
    print(row[1])  # ['Alabama', 'Georgia'] 
+0

的結果,我不認爲這是一個有效的解決方案版本的答案,因爲它本質上繞過所有SQLAlchemy的邏輯,並刪除我建立的查詢能力分段。 –

+0

這取決於你的最終目標。如果你想報告公司和地區,它可能是最好的選擇,因爲它不使用ORM,從而最大限度地減少大表的開銷。如果你需要一些額外的行動,它會不那麼方便。 –