我有一个架构,其中包含公司的地址列表。对于报告,我需要对这些公司进行一些过滤,并包括它们所在的所有区域的列表。我要编写的查询的相关核心部分是:
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 :(得分: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
。这也可以通过特殊方式处理。
答案 1 :(得分: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']