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

时间:2017-01-06 10:30:33

标签: php mysql cakephp cakephp-3.0 cakephp-3.x

我试图创建一个使用案例返回列总和的查询(它记录时间和格式的分钟或小时,如果它以小时为单位,乘以60到转换为分钟)。我非常接近,但是查询没有填充ELSE的{​​{1}}部分。 取景器方法是:

CASE

生成的查询是:

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');
}

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

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

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

我知道可能有更好的方法来做到这一点,但此时我想至少知道如何使用内置的QueryBuilder正确地做CASE语句。

1 个答案:

答案 0 :(得分:1)

两个参数都必须是数组

看起来Cookbook中存在一些文档问题,API也可能在这个问题上更加清晰。 $conditions参数和$values参数都必须是数组才能使其正常工作。

强制类型以投射值

结束

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

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

'Times.time' => 'identifier'

然而,遗憾的是,似乎存在一个错误(或至少是一个未记录的限制),导致else部分无法正确识别此语法,因此现在您必须使用手动方式,即通过正确的表达式对象,顺便说一句,你可能应该为Times.time*60做过,因为如果正在应用/需要自动标识符引用,它将会破坏。

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')

另见