2016-11-10 73 views
1

如何在查询生成器中编写这种COALESCE()语句?CakePHP 3 - 如何在查询生成器中编写COALESCE(...)?

SQL

SELECT COALESCE(n.value, p.value) AS value 
FROM nodes n 
LEFT JOIN parents p ON p.id = n.parent_id 

PHP

我可以检索两个孩子和家长的值,然后再通过结果集,只是使用父之一,如果孩子有一个为空,但如果有一种更优雅的方式将其构建到查询中,我宁愿这样做。

$child = $this->Nodes->find() 
    ->select(['id', 'value']) 
    ->where(['Nodes.id' => $id]) 
    ->contain([ 
     'Parents' => function ($q) { 
      return $q->select('value'); 
     } 
    ]) 
    ->first(); 

if (empty($child->value)) { 
    $child->value = $child->parent->value; 
} 

更新1

所以这是我的时刻,但它不工作。

$child = $this->Nodes->find() 
    ->select(['id', 'value']) 
    ->where(['Nodes.id' => $id]) 
    ->contain([ 
     'Parents' => function ($q) { 
      return $q->select([ 
       'value' => $q->func()->coalesce([ 
        'Nodes.value', 
        'Parents.value' 
       ]) 
      ]); 
     } 
    ]) 
    ->first(); 

返回:

object(Cake\ORM\Entity) { 

    'id' => (int) 234, 
    'value' => (float) 0, 
    '[new]' => false, 
    '[accessible]' => [ 
     '*' => true 
    ], 
    '[dirty]' => [], 
    '[original]' => [], 
    '[virtual]' => [], 
    '[errors]' => [], 
    '[invalid]' => [], 
    '[repository]' => 'Nodes' 
} 

孩子值为NULL和父值是1.00,所以我期望的实体值是'value' => (float) 1.00但我相信它的到来了查询作为FALSE转化为(float) 0

更新2

似乎走样聚结已经存在作为一个正常的场不起作用的名称。它需要一个唯一的字段名称作为合并结果。

更新3

我做了另一个试验,从两个表,而不是选择name领域,它只是返回我进入功能(他们没有得到评估为列名),实际的字符串:

return $q->select([ 
    'value' => $q->func()->coalesce([ 
     'Nodes.name', 
     'Parents.name' 
    ]) 
]); 

返回的实体有:

'value' => 'Nodes.name' 

所以我的新questio ñ将是如何让查询生成器评估字符串作为表/字段名称?

+1

注意'COALESCE(n.value,p.value)AS value'是写这篇的首选方式 – rjdown

+0

COALESCE也由ORM支持(不,它可以帮助你的问题了!):HTTP ://api.cakephp.org/3.3/class-Cake.Database.FunctionsBuilder.html#_coalesce – burzum

+0

@rjdown谢谢,我已经更新了这个问题。 – BadHorsie

回答

3

我无法获得Cake的coalesce()函数来将参数评估为字段,它只是返回字段名称的实际字符串。

我通过手动创建COALESCE声明来解决问题。

// Create the query object first, so it can be used to create a SQL expression 
$query = $this->Nodes->find(); 

// Modify the query 
$query 
    ->select([ 
     'id', 
     'value' => $query->newExpr('COALESCE(Nodes.value, Parents.value)') 
    ]) 
    ->where(['Nodes.id' => $id]) 
    ->contain('Parents') 
    ->first(); 
1

http://book.cakephp.org/3.0/en/orm/query-builder.html#using-sql-functions

还没有尝试过,但我想这是:

$child = $this->Nodes->find() 
    ->select(['id', 'value']) 
    ->where(['Nodes.id' => $id]) 
    ->contain([ 
     'Parents' => function ($q) { 
      return $q->select(['value' => $query->func()->coalesce([ 
       /* Fields go here... I think. :) */ 
      ])]); 
     } 
    ]) 
    ->first(); 

如果不工作检查核心的单元测试如何调用该函数。

+0

谢谢* burzum *。不幸的是我无法工作。我发现了它的一些问题,目前那个问题是,我无法获得'coalesce()'来评估我的字段名称为字段。它只是给出了我放入数组的字符串。查看更新的问题。 – BadHorsie