简体   繁体   English

SQLAlchemy多表和外键联接

[英]SQLAlchemy Multi Table & Foreign Key Join

Got four tables; 有四张桌子; users , company , company_branch and users_branch . userscompanycompany_branchusers_branch Users are people belonging to company. 用户是属于公司的人。 A company has got branches and a user can belong to a single branch at any given time. 公司有分支机构,用户可以在任何给定时间属于一个分支机构。 However, the users_branch table exists to keep track of the history of changing from one branch to another. 但是,users_branch表用于跟踪从一个分支更改为另一个分支的历史记录。 Eg To get the current branch of a user with id 1, one would run a SELECT company_id, company_branch_id FROM users_branch WHERE user_id = 1 ORDER BY created_at DESC LIMIT 1 . 例如,要获取ID为1的用户的当前分支,可以在SELECT company_id, company_branch_id FROM users_branch WHERE user_id = 1 ORDER BY created_at DESC LIMIT 1运行SELECT company_id, company_branch_id FROM users_branch WHERE user_id = 1 ORDER BY created_at DESC LIMIT 1

The challange I have is that am not able to figure out the correct not SQLAlchemy ORM syntax but also SQL raw to get list of users in a certain company at a given time and do so while returning the users_id, users_email_address, company_id, company_name, compancy_branch_id and company_branch_name for each entry. 我面临的挑战是,我无法找出正确的而非SQLAlchemy ORM语法,也无法找出SQL Raw以在给定的时间获取特定公司中的用户列表,并在返回users_id, users_email_address, company_id, company_name, compancy_branch_id and company_branch_name同时这样做users_id, users_email_address, company_id, company_name, compancy_branch_id and company_branch_name每个条目的users_id, users_email_address, company_id, company_name, compancy_branch_id and company_branch_name The queries I've tried so far either return nothing or they return repeated values in the users_branch wheareas I only want the latest branch for each user 到目前为止,我尝试过的查询不返回任何内容,或者在users_branch wheareas中返回重复的值,我只希望每个用户都拥有最新的分支

Here is the link to the sqlfiddle sample postgresql database. 这是 sqlfiddle示例postgresql数据库的链接 In SQAlchemy the models are Users, Company, CompanyBranch, UsersBranch as seen below: 在SQAlchemy中,模型为Users, Company, CompanyBranch, UsersBranch ,如下所示:

class Users(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    email_address = Column(String(70), nullable=False, unique=True)

class Company(Base):
    __tablename__ = 'company'
    id = Column(Integer, primary_key=True)
    created_at = Column(DateTime, server_default=text('NOW()'), nullable=False)
    created_by = Column(ForeignKey('users.id'), nullable=False)
    company_name = Column(String(100), nullable=False, unique=True)

class CompanyBranch(Base):
    __tablename__ = 'company_branch'
    id = Column(Integer, primary_key=True)
    created_at = Column(DateTime, server_default=text('NOW()'), nullable=False)
    created_by = Column(ForeignKey('users.id'), nullable=False)
    company_id = Column(ForeignKey('company.id'), nullable=False)
    branch_name = Column(String(100), nullable=False, unique=True)

class UsersBranch(Base):
    __tablename__ = 'users_branch'
    id = Column(Integer, primary_key=True)
    created_at = Column(DateTime, server_default=text('NOW()'), nullable=False)
    created_by = Column(ForeignKey('users.id'), nullable=False)
    user_id = Column(ForeignKey('users.id'), nullable=False)
    company_id = Column(ForeignKey('company.id'), nullable=False)
    company_branch_id = Column(ForeignKey('company_branch.id'), nullable=False)

First, let me start by saying your schema is a little denormalized. 首先,让我先说一下您的架构有点非规范化。 users_branch.company_id is not necessary because users_branch.company_branch_id can also give you the company_id . users_branch.company_id是不必要的,因为users_branch.company_branch_id也可以给您company_id There may be a good reason for it, but it might be adding some confusion here. 这样做可能有充分的理由,但是这可能会增加一些混乱。

This is tricky because of the users_branch table. 由于users_branch表,这很棘手。 It essentially requires grouping by user_id and selecting the row with the max created_at . 本质上,它需要按user_id分组,并选择具有max created_at最大值的行。

SELECT DISTINCT ON (users_branch.user_id)
  *
FROM
  users
  JOIN users_branch ON users.id = users_branch.user_id
  JOIN company_branch ON users_branch.company_branch_id = company_branch.id
  JOIN company ON company_branch.company_id = company.id
WHERE users_branch.created_at < [some date]
ORDER BY users_branch.user_id, users_branch.created_at DESC;

This doesn't map well to the SQLAlchemy ORM, though. 但是,这并不能很好地映射到SQLAlchemy ORM。

I think I've nailed what I needed. 我想我已经钉了我需要的东西。 The following raw SQL code seems to give me the proper answer of returning only the current branch where user's are. 以下原始SQL代码似乎给了我正确的答案,即仅返回用户所在的当前分支。 Took me a while but I also figured out the SQlAlchemy equivalent. 花了我一段时间,但我也想出了SQlAlchemy等效项。 I'll leave it here as an answer for a while and see if anyone else can tune it further. 我将其留在此处作为答案一会儿,看看是否还有其他人可以进一步调整它。

Raw SQL 原始SQL

SELECT DISTINCT ON (users_branch.user_id) users.email_address, company.id as company_id, company.company_name, company_branch.id AS company_branch_id, company_branch.branch_name
FROM
  users
  JOIN users_branch ON users.id = users_branch.user_id
  JOIN company_branch ON users_branch.company_branch_id = company_branch.id
  JOIN company ON company_branch.company_id = company.id
WHERE users_branch.created_at in (SELECT max(users_branch.created_at) FROM users_branch GROUP BY users_branch.user_id) AND 
users_branch.company_id = 1 AND
users_branch.company_branch_id = 3

SQL Alchemy SQL炼金术

query = session.query(Users.id.label('user_id'), Users.email_address, Company.id.label('company_id'), Company.company_name,
CompanyBranch.id.label("company_branch_id"), CompanyBranch.branch_name).distinct(UsersBranch.user_id). \
join(UsersBranch, and_(Users.id == UsersBranch.user_id)). \
join(CompanyBranch, and_(UsersBranch.company_branch_id == CompanyBranch.id)).\
join(Company, and_(CompanyBranch.company_id == Company.id)).\
filter(UsersBranch.created_at.in_(session.query(func.max(UsersBranch.created_at)).group_by(UsersBranch.user_id))).\
filter(UsersBranch.company_id == 1).\
filter(UsersBranch.company_branch_id == 3)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM