在 HAVING 子句中使用聚合函数构建查询
Build query with aggregate functions in HAVING clause
我正在尝试弄清楚如何使用 CakePHP 的查询生成器在 having 子句中使用聚合函数。
背景:目的是使用复合主键(页面 ID 和 URL)更正 table 中的所有行,以便每个页面 ID 组只有一个默认视频.有的组没有,有的组不止"default"行,需要更正。我已经弄清楚了所有的步骤——除了这个细节。
这是我要构建的查询。
SELECT
video_page_id, video_url
FROM page_video
WHERE
video_page_id IN (
SELECT video_page_id
FROM page_video
GROUP BY video_page_id
HAVING SUM(video_is_default) < 1
)
AND video_order = 0
;
这就是我构建的:
// sub-select: all groups that have too few defaults.
// Returns list of page-IDs.
$qb = $this->getQueryBuilder();
$group_selection = $qb
->select(array(
'video_page_id',
))
->from('page_video')
->group('video_page_id')
->having(array(
'1 >' => $qb->func()->sum('video_is_default'),
))
;
// sub-select: compound-primary-key identifiers of all rows where
// `video_is_default` has to be modified from `0` to `1`.
// Returns list of two columns.
$qb = $this->getQueryBuilder();
$modifiable_selection = $qb
->select(array(
'video_page_id',
'video_url',
))
->from('page_video')
->where(array(
'video_page_id IN' => $group_selection,
'video_order = 0',
))
;
但后来我得到了这个例外:Column not found: 1054 Unknown column '1' in 'having clause'
关键是HAVING子句。我基本上不知道如何将聚合函数与数组的属性值属性结合起来。通常,为了制作 lower/greater-than 子句,您可以这样写:array('col1 >' => $value)
。但在这里,我需要翻转等式,因为复杂的表达式无法放入数组键中。现在 1
被解释为列名。
将其写成串联字符串似乎也无济于事。
array(
$qb->func()->sum('video_is_default') .' > 1',
)
异常:PHP Recoverable fatal error: Object of class Cake\Database\Expression\FunctionExpression could not be converted to string
我知道我能做到……
SELECT (…), SUM(video_is_default) AS default_sum FROM (…) HAVING default_sum < 1 (…)
… 但是子select 列数不再匹配。
异常:ERROR 1241 (21000): Operand should contain 1 column(s)
问完问题这么快就想出解决方案,我觉得很傻。
lt
方法接受复数值作为第一个参数。
->having(function($exp, $qb) {
$default_sum = $qb->func()->sum('video_is_default');
return $exp->lt($default_sum, 1);
})
我正在尝试弄清楚如何使用 CakePHP 的查询生成器在 having 子句中使用聚合函数。
背景:目的是使用复合主键(页面 ID 和 URL)更正 table 中的所有行,以便每个页面 ID 组只有一个默认视频.有的组没有,有的组不止"default"行,需要更正。我已经弄清楚了所有的步骤——除了这个细节。
这是我要构建的查询。
SELECT
video_page_id, video_url
FROM page_video
WHERE
video_page_id IN (
SELECT video_page_id
FROM page_video
GROUP BY video_page_id
HAVING SUM(video_is_default) < 1
)
AND video_order = 0
;
这就是我构建的:
// sub-select: all groups that have too few defaults.
// Returns list of page-IDs.
$qb = $this->getQueryBuilder();
$group_selection = $qb
->select(array(
'video_page_id',
))
->from('page_video')
->group('video_page_id')
->having(array(
'1 >' => $qb->func()->sum('video_is_default'),
))
;
// sub-select: compound-primary-key identifiers of all rows where
// `video_is_default` has to be modified from `0` to `1`.
// Returns list of two columns.
$qb = $this->getQueryBuilder();
$modifiable_selection = $qb
->select(array(
'video_page_id',
'video_url',
))
->from('page_video')
->where(array(
'video_page_id IN' => $group_selection,
'video_order = 0',
))
;
但后来我得到了这个例外:Column not found: 1054 Unknown column '1' in 'having clause'
关键是HAVING子句。我基本上不知道如何将聚合函数与数组的属性值属性结合起来。通常,为了制作 lower/greater-than 子句,您可以这样写:array('col1 >' => $value)
。但在这里,我需要翻转等式,因为复杂的表达式无法放入数组键中。现在 1
被解释为列名。
将其写成串联字符串似乎也无济于事。
array(
$qb->func()->sum('video_is_default') .' > 1',
)
异常:PHP Recoverable fatal error: Object of class Cake\Database\Expression\FunctionExpression could not be converted to string
我知道我能做到……
SELECT (…), SUM(video_is_default) AS default_sum FROM (…) HAVING default_sum < 1 (…)
… 但是子select 列数不再匹配。
异常:ERROR 1241 (21000): Operand should contain 1 column(s)
问完问题这么快就想出解决方案,我觉得很傻。
lt
方法接受复数值作为第一个参数。
->having(function($exp, $qb) {
$default_sum = $qb->func()->sum('video_is_default');
return $exp->lt($default_sum, 1);
})