CakePHP 3 - 如何在查询生成器中编写 COALESCE(...)?
CakePHP 3 - How to write COALESCE(...) in query builder?
如何在查询生成器中编写这种 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();
Returns:
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
字段,它只是 returns 我输入函数的实际字符串(它们不会被评估为列名) :
return $q->select([
'value' => $q->func()->coalesce([
'Nodes.name',
'Parents.name'
])
]);
返回的实体有:
'value' => 'Nodes.name'
所以我的新问题是如何让查询构建器将字符串评估为 table/field 名称?
见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();
如果这不起作用,请检查核心单元测试如何调用此函数。
我无法使用 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();
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/ 一个清楚的例子。
如何在查询生成器中编写这种 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();
Returns:
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
字段,它只是 returns 我输入函数的实际字符串(它们不会被评估为列名) :
return $q->select([
'value' => $q->func()->coalesce([
'Nodes.name',
'Parents.name'
])
]);
返回的实体有:
'value' => 'Nodes.name'
所以我的新问题是如何让查询构建器将字符串评估为 table/field 名称?
见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();
如果这不起作用,请检查核心单元测试如何调用此函数。
我无法使用 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();
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/ 一个清楚的例子。