Python SQLAlchemy多表&;外键联接

Python SQLAlchemy多表&;外键联接,python,postgresql,sqlalchemy,Python,Postgresql,Sqlalchemy,有四张桌子用户,公司,公司分支机构和用户分支机构。用户是属于公司的人。公司有分支机构,用户可以在任何给定时间属于单个分支机构。但是,用户分支表的存在是为了跟踪从一个分支到另一个分支的更改历史。例如,要获取id为1的用户的当前分支机构,可以运行选择公司id,公司分支机构id FROM users\u branch,其中用户id=1订单由DESC LIMIT 1创建 我面临的挑战是,我无法找到正确的非SQLAlchemy ORM语法,也无法找到SQL raw来获取特定公司在给定时间的用户列表,并在返

有四张桌子<代码>用户,
公司
公司分支机构
用户分支机构
。用户是属于公司的人。公司有分支机构,用户可以在任何给定时间属于单个分支机构。但是,用户分支表的存在是为了跟踪从一个分支到另一个分支的更改历史。例如,要获取id为1的用户的当前分支机构,可以运行
选择公司id,公司分支机构id FROM users\u branch,其中用户id=1订单由DESC LIMIT 1创建

我面临的挑战是,我无法找到正确的非SQLAlchemy ORM语法,也无法找到SQL raw来获取特定公司在给定时间的用户列表,并在返回每个条目的
用户id、用户电子邮件地址、公司id、公司名称、公司分支机构id和公司分支机构名称时执行此操作。到目前为止,我尝试过的查询要么不返回任何内容,要么返回users\u分支中的重复值,而我只希望每个用户都有最新的分支

到sqlfiddle示例postgresql数据库。在SQAlchemy中,模型是
用户、公司、公司分支、用户分支
,如下所示:

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)

首先,让我先说你的模式有点非规范化
users\u branch.company\u id
不是必需的,因为
users\u branch.company\u branch\u id
也可以为您提供
company\u id
。这可能有一个很好的理由,但这可能会增加一些混乱

这很棘手,因为
users\u分支
表。它本质上需要按
用户id
进行分组,并选择在
处创建的最大

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;
选择DISTINCT ON(用户\u分支。用户\u id)
*
从…起
使用者
在users.id=users\u branch.user\u id上加入users\u branch
在用户上加入公司分支机构。公司分支机构\u id=公司分支机构.id
在company\u branch.company\u id=company.id上加入公司
用户在<[某个日期]创建分支机构
按用户\u branch.user\u id订购,用户\u branch.created\u在DESC;

但是,这与SQLAlchemy ORM不太匹配。

我想我已经确定了我需要的东西。下面的原始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炼金术

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)

包含在
users\u branch
表中的
company\u id
用于查询目的。我将测试您的代码并向您报告。谢谢。您的查询没有按预期工作,主要是因为您提供了在
某个日期创建的
。所需的结果应该是,如果用户更改了分支五次,这意味着他们在users\u branch表中有5个条目,那么查询应该只返回最新的条目。请参阅我在《描述限制1》中创建的命令》一文中给出的示例,该命令在为一个用户获取结果时有效。但是,现在我们需要特定公司的所有用户的最新条目。@lukik它不返回某个日期之前的最新条目吗?它会返回,但它会返回用户曾经“定位”的更老分支。我搜索了如何使用SQLMax函数,找到了一个答案,我已经发布了这个答案,它似乎对SQL和SQLAlchem都有效。如果能够选择在特定时间点指定用户列表,则会更加健壮。您的代码将允许我问一个问题,如“向我显示在特定时间在该分支中的用户”。。。这也涵盖了我获取最新用户分支的用例,因为我只需要在。我唯一的问题是,当我运行您的代码来显示特定分支中的当前用户时,它会显示不再在该分支中的用户,所以我认为您的代码可以做一些进一步的调整?但这不会提供在特定时间点具有分支的用户列表,只是最新的。它也稍微脆弱一点,因为它假设用户之间在
创建的
是唯一的(通常是唯一的,但不是你可以做出的普遍假设)。你的权利。拥有在特定时间点指定用户列表的选项将更加健壮。请参阅对您答案的评论