CakePHP 3 - How to write COALESCE(…) in query builder?

拟墨画扇 提交于 2019-12-24 00:57:20

问题


How do I write this kind of COALESCE() statement in the query builder?

SQL

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

PHP

I can retrieve both the child and parent values and then go through the result set and just use the parent one if the child one is empty, but if there is a more elegant way to build it into the query itself, I would prefer that.

$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

So this is what I have at the moment, but it doesn't work.

$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();

Returns:

object(Cake\ORM\Entity) {

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

The child value is NULL and the parent value is 1.00 so I would expect the entity value to be 'value' => (float) 1.00 but I assume it's coming out of the query as FALSE converted to (float) 0.

Update 2

It seems aliasing the coalesce to a name which already exists as a normal field does not work. It requires a unique field name for the coalesce result.

Update 3

I did another test and selected the name field from the two tables instead, and it just returns the actual strings I entered into the function (they do not get evaluated as column names):

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

The returned entity has:

'value' => 'Nodes.name'

So my new question would be how to get the query builder to evaluate the strings as table/field names?


回答1:


I could not get Cake's coalesce() function to evaluate the parameters as fields, it was just returning the actual strings of the field names.

I got it working by manually creating the COALESCE statement instead.

// 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();



回答2:


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

Haven't tried it but I guess it's:

$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();

If this isn't working check the unit tests of the core how to call this function.



来源:https://stackoverflow.com/questions/40534557/cakephp-3-how-to-write-coalesce-in-query-builder

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!