2017-01-27 16 views
1

での制限は、私は2つのクラスを持っています。contains_eagerとSQLAlchemyの

私はそれを達成するためにクエリを作成します。

query = db.session.query(A).join(B).options(db.contains_eager(A.children)).filter(B.name=='SOME_TEXT') 

は今、私は私が行うクエリの唯一の50のアイテムが必要です。

query.limit(50).all() 

結果が制限なしで、私は積極的なロードの禅を読んで50以上ある場合でも50その後、以下が含まれています。しかし、それを達成するためにいくつかのトリックが必要です。私の考えの1つは2つの質問をすることです。 1つはIDを取るinnerjoinと最初のクエリでこのIDを使用します。

しかし、おそらくもっと良い解決策があります。

答えて

2

まず、一歩前に戻ってSQLを見てください。あなたの現在のクエリは制限がa JOIN bないaにある

SELECT * FROM a JOIN b ON b.id_a = a.id WHERE b.name == '...' LIMIT 50; 

お知らせですが、aに制限を置く場合は、bのフィールドでフィルタすることはできません。この問題には2つの解決策があります。

SELECT * FROM a 
WHERE EXISTS (SELECT 1 FROM b WHERE b.id_a = a.id AND b.name = '...') 
LIMIT 50; 

これは、DBのバックエンドに依存して非効率的であることができる:最初はこのように、b.nameにフィルタリングするスカラーサブクエリを使用することです。第2の解決策は、参加した後、このように、aにDISTINCTを行うことです。どちらの場合にはあなたがbから任意の列を得ることはありませんどのように

SELECT DISTINCT a.* FROM a JOIN b ON b.id_a = a.id 
WHERE b.name == '...' 
LIMIT 50; 

注意してください。どうやって入手するのですか?別の参加をしてください!今

SELECT * FROM (
    SELECT DISTINCT a.* FROM a JOIN b ON b.id_a = a.id 
    WHERE b.name == '...' 
    LIMIT 50; 
) a JOIN b ON b.id_a = a.id 
WHERE b.name == '...'; 

は、SQLAlchemyの中でこのすべてを書き込みます:

好奇心のうち
subquery = (
    session.query(A) 
      .join(B) 
      .with_entities(A) # only select A's columns 
      .filter(B.name == '...') 
      .distinct() 
      .limit(50) 
      .subquery() # convert to subquery 
) 
aliased_A = aliased(A, subquery) 
query = (
    session.query(aliased_A) 
      .join(B) 
      .options(contains_eager(aliased_A.children)) 
      .filter(B.name == "...") 
) 
+0

、例えば、(おそらくセミ結合として計画された)が存在する使用してから何DBバックエンドを被ります。 –

+0

@IljaEveriläこれは、データベースエンジン、バージョン、クエリなどの複数の要素に大きく依存するものの1つで、直接的な回答を与えるのは難しいです。 *一般的な意味では、サブクエリよりもジョインは通常は*より効率的です。いつものように、それを把握するためのプロファイル。 – univerio

+0

それはちょうど事であり、EXISTSは、少なくともいくつかのdbsでは、セミジョインとして実装でき、実装されています。もちろん、それはすべてのクエリには当てはまらないかもしれませんが、通常この種の単純なケースで起こります。しかし、結局私はあなたがお金にちょうど良いと思う:プロフィールと参照してください。 –

関連する問題