我试图欺骗sqlalchemy做一些奇怪的查询。我需要编写一个查询,在一对多数据库中选择父对象,其中子对象上的数据列的值不同于同一父对象的其他子对象的值。我知道在执行查询后我可以使用python轻松完成此操作,但出于性能考虑,我希望尽可能使用sqlalchemy的API来实现。
以下最小例子解释了我尝试做的事情。其中大部分是设置,因此只有最后两个代码块才与问题真正相关。
from sqlalchemy import Column, Integer, Enum, String, ForeignKey, create_engine
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from collections import namedtuple
Base = declarative_base()
Data_t = namedtuple('Data_t', 'data1, data2, data3')("1", "2", "3")
class Parent(Base):
__tablename__ = 'parents_table'
id = Column(Integer, primary_key=True)
children = relationship('Child')
def __repr__(self):
return ("Parent %s" % self.id)
class Child(Base):
__tablename__ = 'children_table'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parents_table.id'))
parent = relationship('Parent', back_populates='children')
data = Column(String, Enum(*Data_t._asdict().values(), name='data'))
def __init__(self, _parent, data):
self.parent = _parent
self.parent_id = _parent.id
self.data = data
def __repr__(self):
return "Child %s: %s" % (self.id, self.data)
# Create session
engine = create_engine('sqlite:///:memory:', echo=False)
engine.connect()
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
Session.configure(bind=engine)
session = Session()
# Create parents
parent1, parent2 = Parent(), Parent()
session.add(parent1)
session.add(parent2)
session.commit()
# Create children with differing data column values
for i in range(3):
child = Child(parent1, str(i + 1))
session.add(child)
# Create children with the same data column value
for i in range(3):
child = Child(parent2, str(1))
session.add(child)
session.commit()
# Run query - This query pulls all the contents of the parent table
# whereas I'd like to only select the parents where the children
# data values differ - i.e. I'd like to select parent 1, but not parent 2
for parent in session.query(Parent).all():
print(parent)
for child in parent.children:
print(" ", str(child))
此代码输出以下内容:
Parent 1
Child 1: 1
Child 2: 2
Child 3: 3
Parent 2
Child 4: 1
Child 5: 1
Child 6: 1
我希望能够只选择父母1,但我还没有在sqlalchemy的文档中找到任何能够产生此类查询的文档。< / p>
答案 0 :(得分:1)
过滤器的关键是COUNT(DISTINCT ..)
SQL子句:
from sqlalchemy import func
parents = (
session
.query(Parent)
.outerjoin(Child)
.group_by(Parent)
.having(func.count(Child.data.distinct()) > 1)
).all()
for parent in parents:
print(parent)
for child in parent.children:
print(" ", str(child))
奖励:如果您确实需要获取Child
,并且只想在一个SQL
语句中执行此操作,则可以在查询中添加以下选项,以便还会在同一查询中检索子项:
.options(joinedload(Parent.children)) # from sqlalchemy.orm import joinedload
答案 1 :(得分:0)
您可以按ID:
过滤查询for parent in session.query(Parent).filter(id==1):
print(parent)
for child in parent.children:
print(" ", str(child))