CakePHP 3 在 SQL 中放置不必要的括号导致错误

CakePHP 3 putting un-necessary parentheses in SQL causing error

CakePHP 3.7。尝试使用 ORM 编写包含 MySQL COALESCE 条件的查询。

遵循了 的建议,最后不得不使用 newExpr() 手动编写它,因为这是给定的解决方案。

我的代码如下:

$TblRegulatoryAlerts = TableRegistry::getTableLocator()->get('TblRegulatoryAlerts');
$subscribed_to = $TblRegulatoryAlerts->getUserRegulations($u_id, $o_id, false); 

$query = $this->find()
        ->contain('Filters.Groups.Regulations')
        ->select(['id', 'date', 'comment', 'Filters.label', 'Filters.anchor', 'Groups.label']);

$query->select($query->newExpr('COALESCE((SELECT COUNT(*) 
        FROM revision_filters_substances 
        WHERE revision_filter_id = RevisionFilters.id), 0) AS count_substances'));

$query->where(['date >=' => $date_start, 'date <=' => $date_end, 'Regulations.id' => $regulation_id, 'Filters.id IN' => $subscribed_to]);

$query->enableHydration(false)->orderDesc('date');

这会产生以下 SQL(debug($query->sql()) 的输出:

SELECT RevisionFilters.id AS `RevisionFilters__id`, RevisionFilters.date AS `RevisionFilters__date`, RevisionFilters.comment AS `RevisionFilters__comment`, Filters.label AS `Filters__label`, Filters.anchor AS `Filters__anchor`, Groups.label AS `Groups__label`, (COALESCE((SELECT COUNT(*) FROM revision_filters_substances WHERE revision_filter_id = RevisionFilters.id), 0) AS count_substances) FROM revision_filters RevisionFilters INNER JOIN dev_hub_subdb.filters Filters ON Filters.id = (RevisionFilters.filter_id) INNER JOIN dev_hub_subdb.groups Groups ON Groups.id = (Filters.group_id) INNER JOIN dev_hub_subdb.regulations Regulations ON Regulations.id = (Groups.regulation_id) WHERE ...

不幸的是,这并没有执行,因为 Cake 在 COALESCE 语句周围放置了不必要的括号,这改变了 SQL.

在上面的代码中它生成:

(COALESCE((SELECT COUNT(*) FROM revision_filters_substances WHERE revision_filter_id = RevisionFilters.id), 0) AS count_substances)

而它需要省略 COALESCE 周围的括号,所以它只是:

COALESCE((SELECT COUNT(*) FROM revision_filters_substances WHERE revision_filter_id = RevisionFilters.id), 0) AS count_substances

这可能吗?

不要在表达式中指定别名,而是使用 Query::select() 方法的 key => value 语法指定别名,如下所示:

$query->select([
    'count_substances' => $query->newExpr('...')
]);

它仍然会将表达式括在括号中,但这样会有效,因为它不包含别名。

也就是说,使用函数构建器 coalesque() 方法应该可以正常工作,链接问题中描述的问题也可以通过使用 key => value 语法来解决,其中值可以指定参数的种类,如 ['Nodes.value' => 'identifier'],没有它会将值绑定为字符串。

但是您的示例不应该有任何此类问题,使用函数构建器 coalesce() 方法应该可以正常工作。

$query->select([
    'count_substances' => $query->func()->coalesce($countSubquery, 1, ['integer'])
]);

type 参数是可选的,没有它它可以与大多数 DBMS 一起工作,但为了最大的兼容性,应该指定它以便正确绑定整数值,它也会自动设置 return函数的类型(转换类型)也为 integer