SQLAlchemy中与过滤器的自引用关系

时间:2018-03-20 18:20:26

标签: python sql sqlalchemy

我正在尝试使用自定义JOIN逻辑创建自引用SQLAlchemy关系。

我们的数据库有一个事件表,其中包含' eventID' event' eventDate'和' userID'列。我实施的关系是以前的事件'。我想使用' userID'加入Events表格。 where eventDate> eventDate用于具有相同userID的每个其他事件。

构造的SQL查询应如下所示:

SELECT original.eventID, previous.eventID, ... etc
FROM   Events as original
JOIN   Events as previous 
       ON  previous.userID = original.userID 
       AND previous.eventDate < original.eventDate

我的表定义如下:

from sqlalchemy import Column, ForeignKey, String, DateTime
from sqlalchemy.ext.declarative import declarative_base

class Event(Base):
    __tablename__ = 'event'

    # Attributes
    eventID = Column(String(length=256), primary_key=True)
    eventDate = Column(DateTime)
    userID = Column(String(length=256), ForeignKey('users.userID'))

class Users(Base):
    __tablename__ = 'users'

    # Attributes
    userID = Column(String(length=256), primary_key=True)
    userName = Column(String)

如何定义事件中的关系以获得所需的效果?

1 个答案:

答案 0 :(得分:0)

您需要alternate join conditioncustom foreign conditions,因为有no actual foreign key relationship加入:

class Event(Base):                                                            
    __tablename__ = 'event'            

    # Attributes
    eventID = Column(String(length=256), primary_key=True)
    eventDate = Column(DateTime)
    userID = Column(String(length=256), ForeignKey('users.userID'))

    previousEvents = relationship(
        "Event", primaryjoin=and_(userID == foreign(userID),
                                  eventDate > foreign(eventDate)),
        viewonly=True)      

使用foreign()注释创建没有实际外键的连接条件。也可以使用foreign_keysrelationship()参数,但是您必须非常小心地排列比较以便以正确的顺序获取列,因为相同的列用于加入双方。

如果您希望创建一个加入以前事件的查询,则需要alias

In [13]: prev_event = aliased(Event)

In [14]: print(session.query(Event).join(prev_event, Event.previousEvents))
SELECT event."eventID" AS "event_eventID", event."eventDate" AS "event_eventDate", event."userID" AS "event_userID" 
FROM event JOIN event AS event_1 ON event_1."userID" = event."userID" AND event_1."eventDate" < event."eventDate"

或者如果您希望使用联接加载:

In [17]: print(session.query(Event).options(joinedload(Event.previousEvents)))
SELECT event."eventID" AS "event_eventID", event."eventDate" AS "event_eventDate", event."userID" AS "event_userID", event_1."eventID" AS "event_1_eventID", event_1."eventDate" AS "event_1_eventDate", event_1."userID" AS "event_1_userID" 
FROM event LEFT OUTER JOIN event AS event_1 ON event_1."userID" = event."userID" AND event_1."eventDate" < event."eventDate"
相关问题