SQLAlchemy Multi Table&外键加入

时间:2016-04-11 20:44:23

标签: python postgresql sqlalchemy

有四张桌子; userscompanycompany_branchusers_branch。用户是属于公司的人。公司拥有分支机构,用户可以在任何给定时间属于单个分支机构。但是,users_branch表用于跟踪从一个分支更改为另一个分支的历史记录。例如。要获取ID为1的用户的当前分支,可以运行SELECT company_id, company_branch_id FROM users_branch WHERE user_id = 1 ORDER BY created_at DESC LIMIT 1

我所遇到的挑战是,无法找出正确的SQLAlchemy ORM语法,而且还无法找到SQL raw以获取给定时间内某个公司的用户列表,并在返回users_id, users_email_address, company_id, company_name, compancy_branch_id and company_branch_name时执行此操作每个条目。我到目前为止所尝试的查询都没有返回任何内容,或者他们在users_branch中返回重复的值,我只想为每个用户提供最新的分支

Here is the link到sqlfiddle示例postgresql数据库。在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)

2 个答案:

答案 0 :(得分:0)

首先,让我首先说你的架构有点非规范化。 users_branch.company_id没有必要,因为users_branch.company_branch_id也可以为您提供company_id。可能有充分的理由,但这可能会增加一些混乱。

由于users_branch表,这很棘手。它基本上需要按user_id分组并选择最大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;

但这并不能很好地映射到SQLAlchemy ORM。

答案 1 :(得分:0)

我想我已经找到了我需要的东西。下面的原始SQL代码似乎给了我正确的答案,只返回用户所在的当前分支。我花了一段时间,但我也发现了SQlAlchemy的等价物。我会把它留在这里作为一段时间的答案,看看是否有其他人可以进一步调整它。

原始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

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)