Cakephp3 case mysql 语句没有创建正确的查询

Cakephp3 case mysql statement is not creating the correct query

我正在尝试创建一个查询,该查询 returns 使用案例的列的总和(它记录了时间和以分钟或小时为单位的格式,如果以小时为单位,则乘以 60 为转换为分钟)。我非常接近,但是查询没有填充 CASEELSE 部分。 查找方法是:

public function findWithTotalTime(Query $query, array $options)
{

    $conversionCase = $query->newExpr()
        ->addCase(
            $query->newExpr()->add(['Times.time' => 'hours']),
            ['Times.time*60', 'Times.time'],
            ['integer', 'integer']
        );
  return $query->join([
    'table' => 'times',
    'alias' => 'Times',
    'type' => 'LEFT',
    'conditions' => 'Times.category_id = Categories.id'
  ])->select([
    'Categories.name',
    'total' => $query->func()->sum($conversionCase)
  ])->group('Categories.name');
}

结果查询是:

SELECT Categories.name AS `Categories__name`, (SUM((CASE WHEN 
Times.time = :c0 THEN :c1 END))) AS `total` FROM categories Categories 
LEFT JOIN times Times ON Times.category_id = Categories.id GROUP BY 
Categories.name

它在 CASE 结束之前缺少 ELSE 语句,根据 API 文档:

...the last $value is used as the ELSE value...

https://api.cakephp.org/3.3/class-Cake.Database.Expression.QueryExpression.html

我知道可能有更好的方法来执行此操作,但此时我想至少知道如何使用内置的 QueryBuilder 正确执行 CASE 语句。

两个参数都必须是数组

看起来 Cookbook 中存在一些文档问题,API 在该主题上也可能更清楚一些。 $conditions 参数和 $values 参数都必须是数组才能工作。

强制类型以转换值结束

此外,您传递的 SQL 表达式错误,包括错误的类型,将类型定义为 integer 将导致传入 $values 的数据转换为这些类型,这意味着您将剩下 0s.

您使用的语法在处理需要安全传递的用户输入时很有用。但是,在您的情况下,您想要传递硬编码标识符,因此您要做的是使用 key => value 语法将值作为文字或标识符传递。这看起来像:

'Times.time' => 'identifier'

然而,不幸的是,似乎有一个错误(或至少是一个未记录的限制)导致其他部分无法正确识别此语法,所以现在您必须使用手动方式,即传递适当的表达式对象,顺便说一句,您可能应该为 Times.time*60 做任何事情,否则它会在自动标识符引用 applied/required.

的情况下中断

tl;dr,示例时间

这是一个包含所有上述技术的完整示例:

use Cake\Database\Expression\IdentifierExpression;

// ...

$conversionCase = $query
    ->newExpr()
    ->addCase(
        [
            $query->newExpr()->add(['Times.time' => 'hours'])
        ],
        [
            $query
                ->newExpr(new IdentifierExpression('Times.time'))
                ->add('60')
                ->tieWith('*'), // setConjunction() as of 3.4.0
            new IdentifierExpression('Times.time')
        ],
    );

如果您确定自己永远不会使用自动标识符引用,那么您可以将乘法片段传递为:

'Times.time * 60' => 'literal'

或:

$query->newExpr('Times.time * 60')

另见