问题描述
我在使用 CakePHP 4 中的 sql 函数包装器时遇到困难。我使用的是 sqlite 3 和 CakePHP 4.2.3 StrawBerry。 我的数据库表有一个名为“日期”的文本字段。 “日期”中的最小值和最大值是:“2020-01-15”和“2020-12-31”。我有一个简单的查询:
$query = $this->find();
$query->select(['minDate' => $query->func()->min('date'),'maxDate' => $query->func()->max('date')])
->where(['date <>' => ''])
->enableHydration(false);
$results = $query->toList();
$maxDate = $results[0]['maxDate'];
$minDate = $results[0]['minDate'];
SELECT (MIN(date)) AS minDate,(MAX(date)) AS maxDate FROM temp_income TempIncome WHERE date <> :c0
但是,代码返回 $minDate 和 $maxDate 的“浮动”值:
$minDate = 2020
$maxDate = 2020
如果我直接在 sqlite Studio 中运行此语句,我会得到正确的结果(将 '' 放入 for :c0)
minDate = '2020-01-15'
maxDate = '2020-12-31'
如果我使用连接管理器和相同的 sql 在 CakePHP 中运行查询,我会得到正确的答案。
$connection = ConnectionManager::get('default');
$results = $connection->execute("SELECT min(date) as minDate,max(date) as maxDate from temp_income where date <> ''")->fetchAll('assoc');
minDate = '2020-01-15'
maxDate = '2020-12-31'
cake 函数包装器 func()->min(‘date’)
正在进行不需要的类型转换。
深入研究,在 vendor/cakePHP/cakePHP/src/database/FunctionsBuilder.PHP 中,如果没有定义其他类型,则 min 和 max 的构建器设置为返回 'float',显然在这种情况下不是.我不知道为什么。我还没有挖那么远。
public function max($expression,$types = []): AggregateExpression
{
return $this->aggregate('MAX',$this->toLiteralParam($expression),$types,current($types) ?: 'float');
}
public function min($expression,$types = []): AggregateExpression
{
return $this->aggregate('MIN',current($types) ?: 'float');
}
min() 和 max() 的正确行为,至少在 Oracle 和 sql Server 中,并且在 sqlite 中显然是因为原始查询工作正常,是返回参数的数据类型。
这是 CakePHP 函数包装器中的错误吗?还是我遗漏了什么?
谢谢!
解决方法
格雷格·施密特是对的。 min() 和 max() 都接受类型参数。您需要深入研究 FunctionsBuilder 类的文档才能找到它: https://api.cakephp.org/4.1/class-Cake.Database.FunctionsBuilder.html#min
就我而言:
$query->select(['minDate' => $query->func()->min('date',['text']),'maxDate' => $query->func()->max('date',['text'])])
回想起来,从我之前发布的函数声明中可以清楚地看出这一点:
public function max($expression,$types = []): AggregateExpression
上面的代码解决了问题。