web-dev-qa-db-ja.com

Doctrine 2でWHERE .. INサブクエリを実行する

特定のアイテムを持つすべての注文から注文アイテムを選択したいのですが。 SQLでは、次のようにします。

SELECT DISTINCT i.id, i.name, order.name 
FROM items i 
JOIN orders o ON i.order_id=o.id 
WHERE o.id IN (
   SELECT o2.id FROM orders o2
   JOIN items i2 ON i2.order_id=o2.id AND i2.id=5
)
AND i.id != 5
ORDER BY o.orderdate DESC
LIMIT 10

クエリビルダーでこのクエリを実行するにはどうすればよいですか?

56
chiborg

これは私がそれを試す方法です:

/** @var Doctrine\ORM\EntityManager $em */
$expr = $em->getExpressionBuilder();
$em->createQueryBuilder()
   ->select(array('DISTINCT i.id', 'i.name', 'o.name'))
   ->from('Item', 'i')
   ->join('i.order', 'o')
   ->where(
       $expr->in(
           'o.id',
           $em->createQueryBuilder()
               ->select('o2.id')
               ->from('Order', 'o2')
               ->join('Item', 
                      'i2', 
                      \Doctrine\ORM\Query\Expr\Join::WITH, 
                      $expr->andX(
                          $expr->eq('i2.order', 'o2'),
                          $expr->eq('i2.id', '?1')
                      )
               )
               ->getDQL()
       )
   )
   ->andWhere($expr->neq('i.id', '?2'))
   ->orderBy('o.orderdate', 'DESC')
   ->setParameter(1, 5)
   ->setParameter(2, 5)
   ;

もちろんこれをテストしませんでしたし、あなたのモデルについていくつかの仮定をしました。考えられる問題:

  • 制限:これはDoctrine 2の問題です。クエリビルダーは制限を受け入れるのがあまり得意ではないようです。 herehere および here
  • 通常、IN句は配列で使用されますが、サブクエリでも機能すると思います。
  • おそらく2つのパラメーターの代わりに同じパラメーター?1を使用できます(それらは同じ値であるため)が、よくわかりません。

結論として、これは最初はうまくいかないかもしれませんが、確実に正しい軌道に乗せるでしょう。その後、最終的な100%正解を教えてください。

97
faken

Clang1234が最後に投稿したコメントの混乱を避けるためです。

dqlクエリの例は実際に機能します。 expr-> in()が2番目のパラメーターを配列(この場合はdql文字列)にキャストするのは事実です。それがすることは、dqlクエリ文字列を最初の要素として配列を作成するだけです。それこそが、Expr\Funcが待っている配列です。 Doctrine 2コードでは、dqlクエリ文字列配列要素が正しく管理されます。詳細については、DBAL/Platforms/AbstractPlatform.phpメソッドgetInExpressionを参照してください。配列は内包されます。に())

9
user1370289