2016-11-10 3 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; 
} 

Update 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.

Update 2

кажется альясинга в сливаться, имя, которое уже существует как нормальное поле не работает. Это требует уникального имени поля для результата объединения.

Update 3

Я сделал еще один тест и выбрал name поле из двух таблиц вместо этого, и он просто возвращает фактические строки я введенные в функцию (они не получают оценены как имена столбцов):

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

Возвращаемый объект имеет:

'value' => 'Nodes.name' 

Так что мой новый Questio n было бы, как заставить построитель запросов оценивать строки как имена таблиц и полей?

+1

Заметим, что 'COALESCE (n.value, p.value) AS value' является предпочтительным способом написания этого – rjdown

+0

COALESCE также поддерживается ОРМ (не то, что он помогает ваш вопрос вообще!): HTTP : //api.cakephp.org/3.3/class-Cake.Database.FunctionsBuilder.html#_coalesce – burzum

+0

@rjdown Спасибо, я обновил вопрос. – BadHorsie

ответ

3

Я не мог получить функцию Cake's 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

 Смежные вопросы

  • Нет связанных вопросов^_^