2010-01-06 13 views
12

SQLAlchemy का उपयोग करके, मेरे पास दो तालिकाओं - उपयोगकर्ताओं और स्कोर के साथ कई संबंध हैं। मैं पिछले 10 दिनों में अपने कुल स्कोर द्वारा क्रमबद्ध शीर्ष 10 उपयोगकर्ताओं से पूछताछ करने की कोशिश कर रहा हूं।संबंधित ऑब्जेक्ट द्वारा SQLAlchemy फ़िल्टर क्वेरी

users: 
    id 
    user_name 
    score 

scores: 
    user 
    score_amount 
    created 

मेरे वर्तमान क्वेरी है:

top_users = DBSession.query(User).options(eagerload('scores')).filter_by(User.scores.created > somedate).order_by(func.sum(User.scores).desc()).all() 

मैं जानता हूँ कि यह स्पष्ट रूप से सही नहीं है, यह सिर्फ मेरी सर्वश्रेष्ठ अनुमान दिया है। हालांकि, प्रलेखन और googling को देखने के बाद मुझे एक जवाब नहीं मिल रहा है।

संपादित करें:

SELECT user.*, SUM(scores.amount) as score_increase 
FROM user LEFT JOIN scores ON scores.user_id = user.user_id 
WITH scores.created_at > someday 
ORDER BY score_increase DESC 
+0

त्रुटि अपने में शामिल होने के लिए इस से समझाया गया है एफएक्यू एंट्री: http: //www.sqlalchemy।org/Trac/wiki/पूछे जाने वाले प्रश्न # ImusinglazyFalsetocreateaJOINOUTERJOINandSQLAlchemyisnotconstructingthequerywhenItrytoaddaWHEREORDERBYLIMITetc.whichreliesupontheOUTERJOIN – zzzeek

उत्तर

14

एकल में शामिल हो गए पंक्ति भी तरह से, एक group_by सभी उपयोगकर्ता स्तंभों के लिए में जोड़ा साथ हालांकि MySQL तुम सिर्फ "आईडी" स्तंभ यदि आप चुनते हैं पर समूह दूँगी:

sess.query(User, func.sum(Score.amount).label('score_increase')).\ 
       join(User.scores).\ 
       filter(Score.created_at > someday).\ 
       group_by(User).\ 
       order_by("score increase desc") 

या यदि आपने अभी चाहते हैं परिणाम में उन:

sess.query(User).\ 
      join(User.scores).\ 
      filter(Score.created_at > someday).\ 
      group_by(User).\ 
      order_by(func.sum(Score.amount)) 

दो ऊपर, जिसे आप "उपयोगकर्ता" के सभी स्तंभो में समूहीकरण रहे हैं कि में एक अक्षमता है (या आप "केवल कुछ स्तंभों पर समूह" बात MySQL के प्रयोग कर रहे हैं, जो केवल MySQL है)। कि कम से कम करने के लिए, सबक्वेरी दृष्टिकोण:

subq = sess.query(Score.user_id, func.sum(Score.amount).label('score_increase')).\ 
        filter(Score.created_at > someday).\ 
        group_by(Score.user_id).subquery() 
sess.query(User).join((subq, subq.c.user_id==User.user_id)).order_by(subq.c.score_increase) 

समान परिदृश्य का एक उदाहरण पर ORM ट्यूटोरियल में है: के खिलाफ कसौटी के साथ संयोजन के रूप में eagerload() का उपयोग करने में http://docs.sqlalchemy.org/en/latest/orm/tutorial.html#selecting-entities-from-subqueries

+0

हाय धन्यवाद। यह अच्छी तरह से काम करता है और दस्तावेज़ीकरण बहुत मदद करता है। मैं उपयोगकर्ता के लिए score_increase तक पहुंच कैसे प्राप्त करूं? उदाहरण के लिए ले लो वेरिएबल top_users और प्रत्येक उपयोगकर्ता के माध्यम से मैं लूप को असाइन किया गया है। user.score_increase काम नहीं करता है, न ही user.UserScore.score_increase करता है। – Marc

+0

तीसरे क्वेरी का उपयोग कर, यदि आप sess.query (उपयोगकर्ता, subq.c.score_increase) के माध्यम से पुनरावृति, आप (उपयोगकर्ता, score_increase) – zzzeek

+0

हम्म मैं यहाँ कुछ कमी की जानी चाहिए की tuples मिल जाएगा। यदि यह मायने रखता है, तो मैं टर्बोगियर्स 2 का उपयोग कर रहा हूं और मैं तीसरे प्रश्न का परिणाम एक वैरिएबल टॉप_यूसर को असाइन कर रहा हूं जो मेरे टेम्पलेट्स में उपलब्ध है। मैं फिर loop के माध्यम से - top_users में उपयोगकर्ता के लिए: print user.user_name + '' + user.score_increase - मूल रूप से मैं यह दिखाना चाहता हूं कि उपयोगकर्ता स्कोर ने पिछले x दिनों की संख्या में वृद्धि की है। मुझे समझ में नहीं आता कि top_users tuple के भीतर शामिल डेटा तक कैसे पहुंचे। उपयोगकर्ता के लिए – Marc

1

आपको प्रत्येक उपयोगकर्ता के लिए कुल स्कोर की गणना करने के लिए एक सबक्वेरी उपयोग करने के लिए की आवश्यकता होगी: शायद यह है कि अगर मैं खाका खींचा MySQL क्वेरी कैसे दिखाई देते हैं में मदद मिलेगी। सबक्वायरीज़ का वर्णन यहां किया गया है: http://www.sqlalchemy.org/docs/05/ormtutorial.html?highlight=subquery#using-subqueries

0

मुझे लगता है कि आप कॉलम (संबंध नहीं) में शामिल होने के लिए उपयोग कर रहे हैं, जिसे स्कोर.यूसर_आईडी कहा जाता है, इसलिए यदि यह मामला नहीं है तो इसे बदलें।

आप कुछ इस तरह करने की आवश्यकता होगी:

DBSession.query(Score.user_id, func.sum(Score.score_amount).label('total_score')).group_by(Score.user_id).filter(Score.created > somedate).order_by('total_score DESC')[:10] 

हालांकि इस (user_id, total_score) की tuples का परिणाम देगा। मुझे यकीन है कि अगर गणना स्कोर वास्तव में आप के लिए महत्वपूर्ण है नहीं कर रहा हूँ, लेकिन अगर यह है, तो आप शायद कुछ इस तरह करना चाहते हैं जाएगा:

users_scores = [] 
q = DBSession.query(Score.user_id, func.sum(Score.score_amount).label('total_score')).group_by(Score.user_id).filter(Score.created > somedate).order_by('total_score DESC')[:10] 
for user_id, total_score in q: 
    user = DBSession.query(User) 
    users_scores.append((user, total_score)) 

इस में 11 प्रश्नों निष्पादित किया जा रहा है, तथापि परिणाम देगा। यह सब एक ही प्रश्न में करना संभव है, लेकिन स्क्लेक्लेमी में विभिन्न सीमाओं के कारण, यह संभवतः एक बहुत बदसूरत बहु-शामिल क्वेरी या सबक्वायरी (इंजन पर निर्भर) बनाएगा और यह बहुत ही प्रभावशाली नहीं होगा।

यदि आप इस तरह कुछ करने की योजना बनाते हैं और आपके पास बड़ी संख्या में स्कोर हैं, तो उपयोगकर्ता तालिका पर वर्तमान स्कोर को denormalizing पर विचार करें। यह रखरखाव के लिए और अधिक काम है, लेकिन परिणामस्वरूप एक गैर-जॉइन क्वेरी होगी:

DBSession.query(User).order_by(User.computed_score.desc()) 

आशा है कि मदद करता है।

+1

उफ़। ऐसी कोई सीमा नहीं है जिसके बारे में मुझे पता है। प्रतिक्रिया के लिए – zzzeek

संबंधित मुद्दे