2014-07-23 32 views
8

SQLAlchemy sorgularımı optimize etmek için çok uğraşıyorum. SQL bilgim çok basit ve SQLAlchemy dokümanlarından ihtiyacım olan şeyleri alamıyorum.SQLAlchemy: bir sorguda birkaç sayısı

class Parent(Base): 
    __tablename__ = "parents" 
    id = Column(Integer, primary_key = True) 
    children = relationship("Child", backref = "parent") 

class Child(Base): 
    __tablename__ = "children" 
    id = Column(Integer, primary_key = True) 
    parent_id = Column(Integer, ForeignKey("parents.id")) 
    naughty = Column(Boolean) 

nasıl olabilir ben:

aşağıdaki çok temel bire çok ilişki varsayalım her ebeveyn için (Parent, count_of_naughty_children, count_of_all_children) ait

  • Sorgu tuples? iyi zaman Googling geçirdikten sonra

, ben ayrı ayrı bu değerleri sorgulamak nasıl bulundu:

# The following returns tuples of (Parent, count_of_all_children): 
session.query(Parent, func.count(Child.id)).outerjoin(Child, Parent.children).\ 
    group_by(Parent.id) 
# The following returns tuples of (Parent, count_of_naughty_children): 
al = aliased(Children, session.query(Children).filter_by(naughty = True).\ 
    subquery()) 
session.query(Parent, func.count(al.id)).outerjoin(al, Parent.children).\ 
    group_by(Parent.id) 

Ben farklı şekillerde bunları birleştirmek çalıştı, ama İstediğimi elde başaramadı.

  • % 80'den fazla yaramaz çocuklara sahip tüm ebeveynleri sorgula? Düzenleme: yaramaz NULL olabilir.

Sanırım bu sorgu, bir önceki sayfaya dayanarak, yaramaz/tüm oranlara göre filtreleyecek.

Herhangi bir yardım için teşekkür ederiz.

DÜZENLEME: Çocuk naughty değişken, tedavi yanlış ve NULL 0 olarak, ve True 1. Test olarak eğer

avg = func.avg(func.coalesce(Child.naughty, 0)) # coalesce() treats NULLs as 0 
# avg = func.avg(Child.naughty) - if you want to ignore NULLs 
session.query(Parent).join(Child, Parent.children).group_by(Parent).\ 
    having(avg > 0.8) 

Bu ortalama bulur: Antti Haapala yardımına sayesinde, ikinci soruya çözüm buldu MySQL arka uçlu, ama başkaları üzerinde de çalışmalı.

cevap

7

count() sql aggretate fonksiyonu gibi bir şey oldukça basittir olsun; Her grupta boş olmayan toplam değerlerin sayısını verir. Bunu düşünerek, size uygun sonucu vermek için sorgunuzu ayarlayabiliriz.

SELECT 
parents.id AS parents_id, 
count(children.id) AS count_1, 
count(CASE WHEN (children.naughty = 1) 
     THEN children.id 
     ELSE NULL END) AS naughty 
FROM parents 
JOIN children ON parents.id = children.parent_id 
GROUP BY parents.id 
+0

Teşekkürler, bu mükemmel çalışıyor! – meandrobo

4

Sorunuz sadece% 80 çocuk yaramaz ebeveynleri almak için ise, çoğu veritabanında tamsayı için naughty döküm, daha sonra ortalama almak; daha sonra having bu ortalama 0.8'dan daha büyük.

Böylece

from sqlalchemy.sql.expression import cast 

naughtyp = func.avg(cast(Child.naughty, Integer)) 
session.query(Parent, func.count(Child.id), naughtyp).join(Child)\ 
    .group_by(Parent.id).having(naughtyp > 0.8).all() 
+0

Çok teşekkürler, hile yaptı: aşağıdaki sql üretir

print (Query([ Parent, func.count(Child.id), func.count(case( [((Child.naughty == True), Child.id)], else_=literal_column("NULL"))).label("naughty")]) .join(Parent.children).group_by(Parent) ) 

. Ama ben gerçek modelimde "yaramaz" kelimesinin boş olabileceğini söylemedim - üzgünüm, benim hatam. Boş değerler avg tarafından yok sayılıyor, bu yüzden bu çözüm tam olarak istediğim şey değil. – meandrobo

+2

func.coalesce() bu ^^ düzeltmek için bana yardımcı oldu – meandrobo