2016-04-11 25 views
0

Dört tablo aldınız; users, company, company_branch ve users_branch. Kullanıcılar şirkete ait kişilerdir. Bir şirketin şubeleri vardır ve bir kullanıcı herhangi bir zamanda tek bir şubeye ait olabilir. Ancak, users_branch tablosu, bir daldan diğerine geçiş tarihini takip etmek için var. Örneğin. Bir kullanıcının 1 numaralı kimliğini almak için, bir SELECT company_id, company_branch_id FROM users_branch WHERE user_id = 1 ORDER BY created_at DESC LIMIT 1 çalışır.SQLAlchemy Çoklu Tablo ve Yabancı Anahtarlar Katıl

Sahip olduğum sorun, doğru bir SQLAlchemy ORM sözdizimini değil, belirli bir zamanda belirli bir şirketteki kullanıcıların listesini almak için SQL işlenemediğini ve her bir giriş için users_id, users_email_address, company_id, company_name, compancy_branch_id and company_branch_name'u döndürürken bunu yapamıyorum. Şimdiye kadar denediğim sorgular ya hiçbir şey döndürmezler ya da users_branch içinde yinelenen değerler döndürürlerse, yalnızca her kullanıcı için en son şubeyi

Here is the link sqlfiddle örnek postgresql veritabanına istiyorum.

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) 

cevap

0

Birincisi, bana şema biraz Normalleştirilmemiş olduğunu söyleyerek başlayalım: aşağıda görüldüğü gibi SQAlchemy yılında modeller Users, Company, CompanyBranch, UsersBranch bulunmaktadır. users_branch.company_id gerekli değildir, çünkü users_branch.company_branch_id size company_id'u verebilir. Bunun için iyi bir neden olabilir, ancak burada bazı karışıklıklar da olabilir.

Bu, users_branch tablosu nedeniyle zor. Temel olarak user_id ile gruplandırmayı ve maksimum created_at ile satırı seçmeyi gerektirir. Yine de, SQLAlchemy ORM ile iyi bir şekilde eşleşmiyor bu olsa da, bu durum iyi bir şekilde SQLAlchemy ORM ile eşleşmiyor.

+0

'company_id'' users_branch' tabloya dahil edilen amaçlara sorgulamak için kasıtlı olduğunu. Kodunuzu test edip geri rapor edeceğim. Teşekkürler. – lukik

+0

Sorgunuz beklendiği gibi çalışmadı çünkü bir 'created_at <' some_date '' veriyorsunuz. Bir sonuç, bir kullanıcının user_branch tablosunda 5 girdisi olduğu anlamına gelen beş kez dalları değiştirmişse, sorgu yalnızca en son girişi döndürmelidir. Tek bir kullanıcı için sonuç alırken çalışacağım "order_by created_at DESC limit 1" post'unda verdiğim örneğe bakın. Ancak şimdi belirli bir şirketin tüm kullanıcıları için en son girişi istiyoruz. – lukik

+0

@lukik Belirli bir tarihten önce en son dönmez mi? – univerio

0

Sanırım ihtiyacım olan şeyi çivilemedim. Aşağıdaki ham SQL kodu bana sadece kullanıcının bulunduğu mevcut şubeye dönmenin uygun cevabı veriyor gibi görünüyor. Beni bir süre aldı ama aynı zamanda SQlAlchemy eşdeğerini de anladım. Bir süreliğine bir cevap olarak burada bırakacağım ve başka birinin daha fazla ayarlayabileceğini göreceğim.

Raw 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 Simya

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) 
+0

Ancak, bu, şubeleriyle kullanıcıların listesini yalnızca en geç belirli bir zamanda vermez. Aynı zamanda biraz daha kırılgan çünkü kullanıcılar arasında 'created_at' benzersiz olduğunu varsayar (ki bu genelde olabilir, ancak yapabileceğiniz evrensel bir varsayım değildir). – univerio

+0

Sağınız. Belirli bir noktada kullanıcıların listesini belirtme seçeneğine sahip olmak çok daha sağlam olacaktır. Cevabınız hakkındaki yorumları görün – lukik

İlgili konular