2

我有一个香草 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 张桌子,displays并且display_substances. 我想为给定的物质 ID(在上面的查询中表示)呈现每一行的表displays和相应的值。display_substancesds.substance_id = 2

并非每一行displays都有对应的display_substances值。如果是这种情况,它应该输出“未列出”字样。这实际上意味着,如果没有相应的行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();

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

我不知道如何IFNULL...GROUP_CONCAT使用 Cake 的 ORM 语法编写我的香草 SQL 查询的一部分。

我已经阅读了如何在 cakephp 查询中使用 group_contact?所以可以看出可以GROUP_CONCAT->select()条件下使用。但是链接的示例要简单得多,因为它不使用IFNULL条件和相应的操作(返回“未列出”)。

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

CakePHP 版本是 3.5.18

4

1 回答 1

2

IFNULL并且GROUP_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);

也可以看看

于 2020-03-13T13:22:48.993 回答