2012-12-31 22 views
18

私のカテゴリ用のテーブルがあり、各カテゴリにはid、name、およびparent_idがあります。MySQLをDoctrine Query Builderに変換する。 IFとCONCATの問題選択時のサブクエリの別のアプローチ

Select IF(a.parent_id IS NULL, a.name, CONCAT((SELECT b.name FROM category b WHERE b.id = a.parent_id), "/", a.name)) as n, a.id, a.parent_id 
FROM category a 
ORDER BY n 

私は私のDoctrine2クエリビルダにそのような

$em = $this->getDoctrine()->getEntityManager(); 
    $qb = $em->createQueryBuilder(); 
    $q = $qb 
      ->select("c.id") 
      ->addSelect(
       "IF(c.parent_id IS NULL, c.name, CONCAT((" . 
       $em->createQueryBuilder() 
        ->select("t.name") 
        ->from("MyBundle:Category", "t") 
        ->getQuery()->getDQL() . 
       "), \"/\", c.name))" 
      ) 
      ->from("MyBundle:Category", "c"); 
    echo $q->getQuery()->getSQL(); 
    exit; 

何かを、それを変換したいが、私はIF、およびCONCATを使用傾けます。

答えて

45

私は解決策を見つけました。

IFの代わりにCASEを使用できます。私はCASEを使用していたときに、これをチェックしますが、私はできませんCONCAT私のフィールド:

$em = $this->getDoctrine()->getEntityManager(); 
$qb = $em->createQueryBuilder(); 
$q = $qb 
     ->select("c.id") 
     ->addSelect("CASE WHEN (c.parent IS NULL) THEN c.name ELSE 'something' END") 
     ->from("MyBundle:Category", "c") 
     ->leftJoin("c.parent", "t"); 

echo $q->getQuery()->getSQL(); 

別の解決策はIFのように、あなた自身のDQL関数を作成し、このようにそれを使用している:

$em = $this->getDoctrine()->getEntityManager(); 
$qb = $em->createQueryBuilder(); 
$q = $qb 
     ->select("c.id") 
     ->addSelect("IF(c.parent IS NULL, c.name, CONCAT(CONCAT(t.name, '/'), c.name))") 
     ->from("MyBundle:Category", "c") 
     ->leftJoin("c.parent", "t"); 

echo $q->getQuery()->getSQL(); 

のためにhttp://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#adding-your-own-functions-to-the-dql-language

私はこのIFのための私のクラスとconfig.ymlを他の人を助けるためにここに掲載します。ここで がIfFunctionクラスです(私はhttps://github.com/beberlei/DoctrineExtensions/blob/master/src/Query/Mysql/IfElse.phpからのことだ):

doctrine: 
    dbal: 
     driver: "%database_driver%" 
     host:  "%database_host%" 
     port:  "%database_port%" 
     dbname: "%database_name%" 
     user:  "%database_user%" 
     password: "%database_password%" 
     charset: UTF8 

    orm: 
     auto_generate_proxy_classes: "%kernel.debug%" 
     auto_mapping: true 
     dql: #ADDED THIS LINE 
      string_functions: #ADDED THIS LINE 
       IF: MyName\MiscBundle\Doctrine\ORM\Query\AST\Functions\IfFunction #ADDED THIS LINE 

ありがとう:

<?php 
namespace MyName\MiscBundle\Doctrine\ORM\Query\AST\Functions; 

use Doctrine\ORM\Query\AST\Functions\FunctionNode; 
use Doctrine\ORM\Query\Lexer; 

/** 
* Usage: IF(expr1, expr2, expr3) 
* 
* If expr1 is TRUE (expr1 <> 0 and expr1 <> NULL) then IF() returns expr2; 
* otherwise it returns expr3. IF() returns a numeric or string value, 
* depending on the context in which it is used. 
* 
* @author Andrew Mackrodt <[email protected]> 
* @version 2011.06.19 
*/ 
class IfFunction extends FunctionNode 
{ 
    private $expr = array(); 

    public function parse(\Doctrine\ORM\Query\Parser $parser) 
    { 
     $parser->match(Lexer::T_IDENTIFIER); 
     $parser->match(Lexer::T_OPEN_PARENTHESIS); 
     $this->expr[] = $parser->ConditionalExpression(); 

     for ($i = 0; $i < 2; $i++) 
     { 
      $parser->match(Lexer::T_COMMA); 
      $this->expr[] = $parser->ArithmeticExpression(); 
     } 

     $parser->match(Lexer::T_CLOSE_PARENTHESIS); 
    } 

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) 
    { 
     return sprintf('IF(%s, %s, %s)', 
      $sqlWalker->walkConditionalExpression($this->expr[0]), 
      $sqlWalker->walkArithmeticPrimary($this->expr[1]), 
      $sqlWalker->walkArithmeticPrimary($this->expr[2])); 
    } 
} 

その後あなたがこのようなあなたのconfig.ymlを更新する必要があります(ただ、最後の3行を追加しました)

+2

symfonyの最新バージョン - dqlノードはentity_managerの下にある必要があります – Harold

+0

Fantastic!それは働いた、ケースステートメント。 –

0

カテゴリに「親」という名前の関係があるとすると、これは効果的ですか? :

$em = $this->getDoctrine()->getEntityManager(); 
$qb = $em->createQueryBuilder(); 
$q = $qb 
     ->select("c.id") 
    ->addSelect("IF (c.parent_id IS NULL, c.name, CONCAT(t.name, '/', c.name))" 
     ->from("MyBundle:Category", "c") 
    ->leftJoin("c.parent t")); 

echo $q->getQuery()->getSQL(); 
+0

チップをありがとう、この方法でも動作します。しかし、 'addSelect'で' IF'を使うことはできません。 '[Syntax Error]行0、col 13:エラー:予期される関数 'IF'を取得しました –

1

また、組み合わせることができCASECONCAT

$q = $this->createQueryBuilder('a') 
    ->select('a.id') 
    ->addSelect('CASE WHEN(a.parent IS NULL) THEN \'\' else CONCAT(:variable, a.name, \'string\') END as name') 
    ->setParameter('variable', $variable) 
    ... ; 
関連する問題