php - 在 CakePHP 3 中使用 IFNULL ... GROUP_CONCAT()

标签 php mysql cakephp-3.5

我有一个普通的 MySQL 查询,如下所示,运行良好:

SELECT d.*, IFNULL(
     (SELECT GROUP_CONCAT(value) FROM display_substances `ds` 
         WHERE `ds`.`display_id` = `d`.`id`
         AND ds.substance_id = 2 
         GROUP BY `ds`.`display_id`
     ), 'Not Listed'
) `substances` FROM displays `d`;

这个的背景是我有2个表,displaysdisplay_substances 。我想渲染 displays 中每一行的表格以及 display_substances 中的相应值对于给定的物质 ID(在上面的查询中由 ds.substance_id = 2 表示)。

并非 displays 中的每一行有相应的display_substances值(value)。如果是这种情况,它应该输出“Not Listed”字样。这实际上意味着如果 display_substances 中没有相应的行- 那么没有数据display.id - 因此该特定行的数据在数据库中“未列出”。上面的查询正是这样做的。

我希望能够使用 CakePHP 的 ORM 语法编写查询。

表的结构如下。

mysql> DESCRIBE displays;
+----------+----------------------+------+-----+---------+----------------+
| Field    | Type                 | Null | Key | Default | Extra          |
+----------+----------------------+------+-----+---------+----------------+
| id       | smallint(5) unsigned | NO   | PRI | NULL    | auto_increment |
| label    | varchar(255)         | NO   |     | NULL    |                |
+----------+----------------------+------+-----+---------+----------------+

mysql> DESCRIBE display_substances;
+--------------+-----------------------+------+-----+---------+----------------+
| Field        | Type                  | Null | Key | Default | Extra          |
+--------------+-----------------------+------+-----+---------+----------------+
| id           | mediumint(8) unsigned | NO   | PRI | NULL    | auto_increment |
| display_id   | smallint(5) unsigned  | NO   | MUL | NULL    |                |
| substance_id | mediumint(8) unsigned | NO   | MUL | NULL    |                |
| value        | text                  | NO   |     | NULL    |                |
+--------------+-----------------------+------+-----+---------+----------------+

表类存在并定义了适当的关系。

// src/Model/Table/DisplaysTable.php
$this->hasMany('DisplaySubstances', [
    'foreignKey' => 'display_id'
]);

// src/Model/Table/DisplaysSubstancesTable.php
$this->belongsTo('Displays', [
   'foreignKey' => 'display_id',
   'joinType' => 'INNER'
]);

到目前为止我有这个:

    $substance_id = 2;

    $data = 
        $DisplaySubstances->find()
        ->contain(['Displays'])
        ->where(['DisplaySubstances.substance_id' => $substance_id)
        ->select(['Displays.id', 'Displays.label', 'Displays.anchor', 'DisplaySubstances.value'])
        ->enableHydration(false)->toArray();

这将为我提供 displays 中的行其中 display_substances 中有相应的值对于物质 ID 2。这实际上是我们拥有数据的所有内容,但不包括任何“未列出”的行。

我不知道怎么写IFNULL...GROUP_CONCAT我的普通 SQL 查询的一部分使用 Cake 的 ORM 语法。

我已阅读 How to use group_contact in cakephp query?所以可以看到可以使用 GROUP_CONCAT->select()健康)状况。但链接的示例要简单得多,因为它不使用 IFNULL条件和相应的操作(返回“Not Listed”)。

如果可能的话,请有人建议如何用 Cake 的 ORM 语法编写它?

CakePHP 版本为 3.5.18

最佳答案

IFNULLGROUP_CONCAT 都是 SQL 函数,因此您可以使用函数构建器,它可用于创建您想要的任何函数调用,其神奇的调用处理程序如果调用的方法没有具体实现,则将创建通用函数调用,即 $functionsBuilder->IFNULL()$functionsBuilder->GROUP_CONCAT() 将正常工作。

函数构建器还接受表达式,因此您可以将另一个查询对象传递给 IFNULL() 调用,即示例 SQL 中的子查询。

$subquery = $DisplaySubstances->find()
    ->select(function (\Cake\ORM\Query $query) {
        return [
            $query->func()->GROUP_CONCAT(['value' => 'identifier'])
        ];
    })
    ->where(function (\Cake\Database\Expression\QueryExpression $exp) use ($substance_id) {
        return [
            $exp->equalFields('DisplaySubstances.display_id', 'Displays.id'),
            'DisplaySubstances.substance_id' => $substance_id
        ];
    })
    ->group('DisplaySubstances.display_id');

$query = $Displays->find()
    ->select(function (\Cake\ORM\Query $query) use ($subquery) {
        // Before CakePHP 3.8.3 queries need to be wrapped in an additional expression
        // in order for the query builder to generate them wrapped in parentheses in SQL
        $subquery = $query->newExpr($subquery);

        return [
            'substances' => $query->func()->IFNULL([$subquery, 'Not Listed'])
        ];
    })
    ->select($Displays);

另请参阅

关于php - 在 CakePHP 3 中使用 IFNULL ... GROUP_CONCAT(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60669670/

相关文章:

php - 词干提取避免将流行单词与不同含义进行匹配

php - PHP 不允许多次登录

php - 如何从谷歌地图 API 检索数据

mysql - 获取论坛中所有主题的回复总数

mysql - 带有聚合函数的 SQL HAVING 子句?

java - 如何使用struts2统计从数据库中找到的记录数并显示在jsp页面中?

PHP 垃圾收集器不断删除我的 session

php - 如何授予apache写入主目录的权限?