【发布时间】:2016-11-10 18:24:53
【问题描述】:
如何在查询构建器中编写这种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'
所以我的新问题是如何让查询构建器将字符串评估为表/字段名称?
【问题讨论】:
-
请注意,
COALESCE(n.value, p.value) AS value是写这篇文章的首选方式(并不是说它对你的问题有帮助!) -
ORM 也支持 COALESCE:api.cakephp.org/3.3/…
-
@rjdown 谢谢,我已经更新了问题。
-
@BadHorsie 我意识到很久以前有人问过这个问题,但我正在尝试在 Cake 3.7 中做同样的事情。您是设法通过 ORM 让它工作还是坚持手动编写表达式?
-
@Andy 我可以让它工作的唯一方法是按照我下面的回答。我猜它仍在使用 ORM,但不是很优雅。
标签: php cakephp cakephp-3.0 cakephp-3.x