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

hkmswyz6  于 2022-11-24  发布在  PHP
关注(0)|答案(3)|浏览(176)

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

查询语句

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'

因此,我的新问题是如何让查询构建器将字符串作为表/字段名进行计算?

8nuwlpux

8nuwlpux1#

我无法让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();
vnjpjtjt

vnjpjtjt2#

CakePHP的coalesce()使用以下格式来区分字段名和文字值:

'value' => $q->func()->coalesce([
                    'User.last_name' => 'identifier',
                    ', ',
                    'User.first_name' => 'identifier'
                ])

上面的代码应该产生类似Smith, John的结果。
预设行为是将项目视为常值。
请访问https://api.cakephp.org/3.3/class-Cake.Database.FunctionsBuilder.html#_coalesce
文档根本没有很好地解释这一点。H/T到https://www.dereuromark.de/2020/02/06/virtual-query-fields-in-cakephp/是一个清晰的例子。

mec1mxoz

mec1mxoz3#

请访问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();

如果这不起作用,请检查核心的单元测试如何调用此函数。

相关问题