python - sqlalchemy - 连接表的限制就好像它们没有连接一样

标签 python sql postgresql sqlalchemy

我正在使用 sqlalchemy,我想从用户那里获取以下数据并按照给定表的顺序应用这些操作:

keyword to filter the data with, column to order by, limit and page number

现在我有很多 table 。大多数“子表”——没有子表——工作。但是我有一张表,里面有很多各种各样的关系..双方一对多,一对一和多对多

为了实现上述操作,我事先加入了所有的表。过滤和排序工作正常但限制没有给我想要的结果

加入声明:

records = m.Activity.query.join(m.Event, m.Activity.events) \
            .join(m.DateLocation, m.Activity.date_locations) \
            .join(m.Goal, m.Activity.goals) \
            .join(m.Type, m.Activity.type)

过滤和排序包含很多不必要的信息,基本上是这样的:

# filtering if column == event
records = records.filter(m.Event.name == keyword) 
# ordering if column == type and desc was chosen
records = records.order_by(m.Type.name.desc())

最后是限制和分页:

records = records.limit(limit)
records = records.offset((page - 1) * limit)

让我解释一下限制行为与我想要的:

此代码中的限制工作正常。因为我加入了所有的表,它会返回我给它的加入行的数量。如果加入导致额外的 5 行,例如我要求限制 5,它会返回前 5,不管原始表 id

我要的是加入前的限制行为。我加入他们只是为了按他们过滤或订购。之后,当我说 limit (5) 时,我想返回具有不同 id 的前 5 个结果

我尝试了以下方法(一次一个)但没有成功:

records = records.distinct(m.Activity.id).limit(limit)
records = records.group_by(m.Activity.id).limit(limit)
records = records.from_self().limit(limit)

我尝试了提供的解决方案 here .它确实有效,但是它在加入之前限制了数据集。这对我来说不起作用,因为我需要限制过滤后的数据

编辑:模型:

EventsInActivities = db.Table(
    'events_in_activities',
    db.Column('activity_id', db.String, db.ForeignKey('activity.id')),
    db.Column('event_id', db.Integer(), db.ForeignKey('event.id'))
)


class Event(db.Model, BaseMixin):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String)


class Type(db.Model, BaseMixin):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String, unique=True)
    activities = db.relationship("Activity", backref="type", lazy='dynamic')


class Goal(db.Model, BaseMixin):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    activity_id = db.Column(db.String, db.ForeignKey('activity.id'), primary_key=True)
    name = db.Column(db.String())


class DateLocation(db.Model, BaseMixin):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    activity_id = db.Column(db.String, db.ForeignKey('activity.id'), primary_key=True)
    start_date = db.Column(db.DateTime)
    end_date = db.Column(db.DateTime)
    location = db.Column(db.String())


class Activity(db.Model, BaseMixin):
    id = db.Column(db.String, primary_key=True)
    name = db.Column(db.String())
    type_id = db.Column(db.Integer, db.ForeignKey('type.id'))
    date_locations = db.relationship("DateLocation", order_by='DateLocation.start_date', cascade="all, delete", backref="activity", lazy='dynamic')
    goals = db.relationship("Goal", cascade="all, delete", backref="activity", lazy='dynamic')
    events = db.relationship('Event', secondary=EventsInActivities, backref=db.backref('activities', lazy='dynamic'))

最佳答案

您至少可以用 EXISTS 替换过滤器的一些连接子查询表达式,或 semijoins在某种方式。这样您的查询就可以避免为单个事件生成多行。仍然可以加入 Type,因为它是多对一的关系:

records = m.Activity.query.\
    join(m.Activity.type).\
    filter(m.Activity.events.any(name=keyword)).\
    filter(m.Activity.goals.any(name=...)).\
    filter(...).\
    order_by(m.Type.name.desc()).\
    limit(limit).\
    offset((page - 1) * limit)

将关键字参数传递给 any()是与 filter_by() 类似的简写.它也接受复杂的条件表达式作为位置参数。

distinct(m.Activity.id) 或 DISTINCT ON 应该也能正常工作,只要您随后将结果用作子查询,然后对其应用排序和限制:

records = m.Activity.query.\
    join(m.Activity.events).\
    join(m.Activity.date_locations).\
    join(m.Activity.goals).\
    filter(m.Event.name == keyword).\
    filter(...).\
    distinct(m.Activity.id).\
    from_self().\
    join(m.Activity.type).\
    order_by(m.Type.name.desc()).\
    limit(limit).\
    offset((page - 1) * limit)

关于python - sqlalchemy - 连接表的限制就好像它们没有连接一样,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51346000/

相关文章:

python - 确保外部 API 结果的连接和响应的最佳实践

python - 根据环境的不同,环境变量的值也不同

python - 在 Python 中通过 HTTP 将未知大小的数据从客户端流式传输到服务器

用于带动画的 GUI 的 Python 图形实用程序

php - MYSQL SELECT 不返回某些结果

sql - 如何从表中查找特定列?

sql - 如何找到 SQL Server 数据库的时区?

mysql - 开放地理数据库 : migrate mySQL data to postgreSQL

mysql - 在通用 SQL 中同时检索(选择)或创建(插入)新行而不会发生冲突

MySQL嵌套查询速度