使用 cakePHP 对单个字段进行 SQL Sum 不适用于 paginate()
Posted
技术标签:
【中文标题】使用 cakePHP 对单个字段进行 SQL Sum 不适用于 paginate()【英文标题】:SQL Sum on single field with cakePHP don't work with paginate() 【发布时间】:2014-04-29 15:46:25 【问题描述】:我需要从“orcamentos”表中获取“valor”字段的总和。 我正在使用它并且它正在工作,但我知道这不是正确的方法:
//function index() from OrcamentosController.php
$orcamentoSubprojetosTotal = $this->Orcamento->query(
"SELECT
SUM(Orcamento.valor) AS TotalOrcamentoSuprojetos
FROM
orcamentos AS Orcamento
WHERE
Orcamento.subprojeto_id IS NOT NULL;"
);
$this->set(compact('orcamentoSubprojetosTotal'));
我发现了这个问题cakephp sum() on single field(以及其他sum() function in cakephp query、using virtual fields to sum values in cakephp),但现在我将这一行添加到我的控制器中:
$this->Orcamento->virtualFields['total'] = 'SUM(Orcamento.valor)';
paginate() 停止工作并只显示一个条目,如下所示:
第 1 页,共 1 页,共显示 2 条记录中的 1 条记录,从记录 1 开始,到 2 结束
这是我的 index() 函数:
public function index($tipoOrcamento = null)
$this->Orcamento->recursive = 0;
/*
$orcamentoSubprojetosTotal = $this->Orcamento->query(
"SELECT
SUM(Orcamento.valor) AS TotalOrcamentoSuprojetos
FROM
orcamentos AS Orcamento
WHERE
Orcamento.subprojeto_id IS NOT NULL;"
);
$this->set(compact('orcamentoSubprojetosTotal'));
*/
$this->set(compact('tipoOrcamento'));
if($tipoOrcamento == 'subtitulo')
$this->set('orcamentos', $this->Paginator->paginate('Orcamento', array('Orcamento.subtitulo_id IS NOT NULL')));
elseif($tipoOrcamento == 'subprojeto')
$this->set('orcamentos', $this->Paginator->paginate('Orcamento', array('Orcamento.subprojeto_id IS NOT NULL')));
else
$this->set('orcamentos', $this->Paginator->paginate('Orcamento'));
我可以使用 query() 或者有人可以帮助我处理虚拟字段吗?
谢谢。
【问题讨论】:
其实我只需要一种访问总和的方法,我不需要虚拟字段。我用 cakePHP 做的方式好吗? 我的问题真的是执行 SUM 查询的正确方法是什么,很抱歉给您带来麻烦。 【参考方案1】:不要使用虚拟字段
virtual field 用于以下用途:
public $virtualFields = array(
'name' => 'CONCAT(User.first_name, " ", User.last_name)'
);
如果从不属于/单行的东西中使用虚拟字段 - 它不会做你所期望的事情,这可以从 paginate
生成的查找调用的次要影响中看出。
使用字段
改为使用field 方法并传入表达式:
$integer = $Model->field(
'SUM(valor)',
array('NOT' => array('subprojeto_id' => null))
);
哪个会执行:
SELECT SUM(valor) from x where NOT (subprojecto_id IS NULL);
这也将返回一个标量值,而如问题所示调用查询将返回一个嵌套数组。
【讨论】:
非常感谢!这就是我一直在寻找的,抱歉没有正确询问。我需要使用 $this->Model->field 或者我收到错误“调用非对象上的成员函数字段()”,但它有效!只是为了理解,使用 field() 相当于我对原始查询所做的事情,但是使用 cakephp 必须提供的内容,对吗? 如果你需要的话,使用查询没有什么问题——它是相同的sql,有效地使用字段只是更少的编写代码和更方便,因为它意味着你不需要做$actualValue = $returned[0][0]
;
是的,field() 很容易使用。我仍然有一个问题:array('NOT' => array('subprojeto_id' => null))
工作完美,但如果我尝试array('NOT' => array('subtitulo_id' => null))
,它会给我错误:错误:SQLSTATE[23000]:完整性约束违规:1052 列 'subtitulo_id' in where 子句不明确。在我的表中,subtitulo 条目的 subprojeto 字段将为 null,而 subprojeto 条目的 subtitulo 字段将为 null。它正在处理查询,为什么它不能与 field() 一起使用?
因为您在多个表中都有该字段 - 并且通过 this 进行该模型的递归值为 0 - 这意味着 hasOne 和 belongsTo 关联在查询中加入。在您的模型/应用程序模型中将递归设置为 -1(一个好的做法)或使用条件数组中的模型别名 (array('Orcamento.subprojeto_id' => null)
)。查看您正在生成的 sql 将是一个好主意 - 如果不是原因,您至少可以理解问题。
好的,成功了。我试图通过查看SQL查询来找到问题,但是我现在正在学习SQL和php,所以我不明白很多东西。感谢您的帮助!【参考方案2】:
当然,当您使用 SUM 时,您会得到一条记录
你可以做两件事:
-
在
find()
调用之前创建virtualField
,并在查询之后取消设置。
在您的分页器设置中使用'fields' => arra(...)
,并在您不想求和时仅列出您需要检索的字段而不是虚拟字段
【讨论】:
我认为通过声明一个虚拟字段,我只是在字段列表中添加了一个字段,因此分页器可以像以前一样工作,但它会多一个字段。我只想有一种访问总和的方法,它不需要是虚拟字段。我用的方式好吗? 是的,使用虚拟字段是正确的方法。当您想要获取 SUM 并在 find() 调用之后取消设置 virtualField 时,只需使用 find() ,这样它就不会影响分页。否则分页查询将包含模型的所有字段(甚至是虚拟字段)以上是关于使用 cakePHP 对单个字段进行 SQL Sum 不适用于 paginate()的主要内容,如果未能解决你的问题,请参考以下文章
CakePHP 2.2.4 无法使用 HAVING 子句和计算字段对结果进行分页 - Haversine 公式
CakePHP:从单个模型中检索多个记录以以一种形式进行编辑