【问题标题】:Cakephp3 case mysql statement is not creating the correct queryCakephp3 case mysql 语句未创建正确的查询
【发布时间】:2017-01-06 10:30:33
【问题描述】:

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

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 语句。

【问题讨论】:

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


    【解决方案1】:

    两个参数都必须是数组

    Cookbook 中似乎存在一些文档问题,API 也可能对该主题更加清晰。 $conditions 参数和 $values 参数都必须是数组才能使其工作。

    强制类型以强制转换值结束

    另外你传递了错误的 SQL 表达式,包括错误的类型,将类型定义为 integer 将导致在 $values 中传递的数据被强制转换为这些类型,这意味着你将留下 @ 987654329@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')
    

    另见

    【讨论】:

    • 谢谢!这是一个奖励。如果我想抽象出 $conversionCase 结果以便可以在使用相同 case 语句的其他查询中使用它,我是否必须制作自定义查找器方法?
    猜你喜欢
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多