sqlalchemy:如何通过一个查询连接多个表?

bar*_*kin 83 python sql join sqlalchemy

我有以下SQLAlchemy映射类:

class User(Base):
    __tablename__ = 'users'
    email = Column(String, primary_key=True)
    name = Column(String)

class Document(Base):
    __tablename__ = "documents"
    name = Column(String, primary_key=True)
    author = Column(String, ForeignKey("users.email"))

class DocumentsPermissions(Base):
    __tablename__ = "documents_permissions"
    readAllowed = Column(Boolean)
    writeAllowed = Column(Boolean)

    document = Column(String, ForeignKey("documents.name"))
Run Code Online (Sandbox Code Playgroud)

我需要得到一个这样的表user.email = "user@email.com":

email | name | document_name | document_readAllowed | document_writeAllowed
Run Code Online (Sandbox Code Playgroud)

如何使用SQLAlchemy的一个查询请求?以下代码对我不起作用:

result = session.query(User, Document, DocumentPermission).filter_by(email = "user@email.com").all()
Run Code Online (Sandbox Code Playgroud)

谢谢,

Abd*_*der 78

试试这个

q = (Session.query(User,Document,DocumentPermissions)
    .filter(User.email == Document.author)
    .filter(Document.name == DocumentPermissions.document)
    .filter(User.email == 'someemail')
    .all())
Run Code Online (Sandbox Code Playgroud)

  • "根本没有加入" - 这有点误导.它将具有sql,例如`select a from a,b,c`,这是一个交叉连接.然后过滤器使其成为内部连接. (25认同)
  • 什么样的"加入"呢?内,外,十字架还是什么? (6认同)
  • 这实际上根本不进行连接,它返回元组中的行对象.在这种情况下,它会返回`[(<user>,<document>,<documentpermissions>),...]`/ (6认同)
  • 您可以通过不使用`.all()来打印查询.所以`打印Session.query ....`来确切地看到它在做什么. (5认同)
  • 我是SQLAlchemy的新手。我注意到`.filter()`如果以逗号分隔可以接收多个条件。最好在圆括号内使用一个带有逗号分隔的`.filter()`,还是像上述答案一样使用多个`.filter()`? (2认同)

let*_*bee 43

一个好的风格是设置一些关系和一个主键用于权限(实际上,通常它是为所有设置整数主键的好方式,但无论如何):

class User(Base):
    __tablename__ = 'users'
    email = Column(String, primary_key=True)
    name = Column(String)

class Document(Base):
    __tablename__ = "documents"
    name = Column(String, primary_key=True)
    author_email = Column(String, ForeignKey("users.email"))
    author = relation(User, backref='documents')

class DocumentsPermissions(Base):
    __tablename__ = "documents_permissions"
    id = Column(Integer, primary_key=True)
    readAllowed = Column(Boolean)
    writeAllowed = Column(Boolean)
    document_name = Column(String, ForeignKey("documents.name"))
    document = relation(Document, backref = 'permissions')
Run Code Online (Sandbox Code Playgroud)

然后用连接做一个简单的查询:

query = session.query(User, Document, DocumentsPermissions).join(Document).join(DocumentsPermissions)
Run Code Online (Sandbox Code Playgroud)


Ull*_*uri 24

正如@letitbee所说,最佳做法是将主键分配给表并正确定义关系以允许正确的ORM查询.话虽如此...

如果您有兴趣按以下方式编写查询:

SELECT
    user.email,
    user.name,
    document.name,
    documents_permissions.readAllowed,
    documents_permissions.writeAllowed
FROM
    user, document, documents_permissions
WHERE
    user.email = "user@email.com";
Run Code Online (Sandbox Code Playgroud)

然后你应该去做类似的事情:

session.query(
    User, 
    Document, 
    DocumentsPermissions
).filter(
    User.email == Document.author
).filter(
    Document.name == DocumentsPermissions.document
).filter(
    User.email == "user@email.com"
).all()
Run Code Online (Sandbox Code Playgroud)

相反,如果你想做类似的事情:

SELECT 'all the columns'
FROM user
JOIN document ON document.author_id = user.id AND document.author == User.email
JOIN document_permissions ON document_permissions.document_id = document.id AND document_permissions.document = document.name
Run Code Online (Sandbox Code Playgroud)

然后你应该做的事情:

session.query(
    User
).join(
    Document
).join(
    DocumentsPermissions
).filter(
    User.email == "user@email.com"
).all()
Run Code Online (Sandbox Code Playgroud)

关于那个的一点说明......

query.join(Address, User.id==Address.user_id) # explicit condition
query.join(User.addresses)                    # specify relationship from left to right
query.join(Address, User.addresses)           # same, with explicit target
query.join('addresses')                       # same, using a string
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请访问文档.

  • 做这个。请参阅-联接中没有指定太多内容。这是因为,如果已经使用这些表之间的正确外键设置了表/数据库模型-SQLAlchemy将为您连接适当的列。 (3认同)

Mat*_*ong 7

扩展Abdul的答案,您可以KeyedTuple通过连接列来获取而不是离散的行集合:

q = Session.query(*User.__table__.columns + Document.__table__.columns).\
        select_from(User).\
        join(Document, User.email == Document.author).\
        filter(User.email == 'someemail').all()
Run Code Online (Sandbox Code Playgroud)