使用IFNULL。。。CakePHP 3中的组_CONCAT()

使用IFNULL。。。CakePHP 3中的组_CONCAT(),php,mysql,cakephp-3.5,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' ) `sub

我有一个普通的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`;
背景是我有两个表,
显示
显示
。我想为给定的物质ID(在上面的查询中由
ds.substance\u ID=2
表示)呈现
display
中每一行的表格以及
display\u substances
中的相应值

并非
显示
中的每一行都有相应的
显示
值。如果是这种情况,则应输出“未列出”字样。这实际上意味着,如果
display\u 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 2的相应值。这实际上就是我们拥有数据的所有内容,但不包括任何“未列出”的行

我不知道如何使用Cake的ORM语法编写我的普通SQL查询的
IFNULL…GROUP\u CONCAT
部分

我已经阅读了,因此可以看到在
->select()
条件下使用
GROUP\u CONCAT
。但是链接的示例要简单得多,因为它不使用
IFNULL
条件和相应的操作(返回“notlisted”)

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


CakePHP版本是3.5.18

IFNULL
GROUP_CONCAT
都是SQL函数,因此您可以使用functions builder,它可以用来创建您想要的任何函数调用,如果调用的方法没有具体实现,它的神奇调用处理程序将创建一个通用函数调用,ie
$functionsBuilder->IFNULL()
$functionsBuilder->GROUP_CONCAT()
将正常工作

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

$subquery=$DisplaySubstances->find()
->选择(函数(\Cake\ORM\Query$Query){
返回[
$query->func()->GROUP_CONCAT(['value'=>'identifier'])
];
})
->其中(函数(\Cake\Database\Expression\QueryExpression$exp)使用($substance\u id){
返回[
$exp->equalFields('DisplaySubstances.display\u id','Displays.id'),
'DisplaySubstances.substance\u id'=>$substance\u id
];
})
->组('DisplaySubstances.display_id');
$query=$Displays->find()
->选择(函数(\Cake\ORM\Query$Query)使用($subquery){
//在CakePHP 3.8.3之前,需要将查询包装在附加表达式中
//为了让查询生成器生成它们,将它们包装在SQL中的括号中
$subquery=$query->newExpr($subquery);
返回[
“物质”=>$query->func()->IFNULL([$subquery,'未列出']))
];
})
->选择($Displays);
另见


我刚刚有机会尝试一下。它给出了一个SQL错误
error:SQLSTATE[42000]:语法错误或访问冲突:1064您的SQL语法有错误;检查与您的MariaDB服务器版本相对应的手册,以了解从第1行的display_substances DisplaySubstances WHERE(Di)中选择(GROUP_CONCAT(value))的正确语法。我无法发现此错误的位置,因为它看起来像是有效的SQL。整个查询是
SELECT(IFNULL)(SELECT(GROUP_CONCAT(value))从display_substances DisplaySubstances其中(DisplaySubstances.display_id=(Displays.id)和DisplaySubstances.substances_id=:c0)按DisplaySubstances.display_id进行分组:param1))作为
物质
,.id作为显示,.name作为显示,.label作为显示,Display.link作为显示锚定,Display.group作为显示锚定组,Display.comment作为显示注释s_uucomment`FROM displays`@Andy请尝试在外部托管这样的代码片段(例如gist),它们在注释中非常不可读。也就是说,子查询应该用括号括起来,即
IFNULL((SELECT…)
(注意双括号,一个用于函数调用,一个作为包装).CakePHP在默认情况下应该这样做,可能您使用的版本太旧,或者您修改的示例代码会改变输出(尽管我不确定这是怎么可能的)@Andy Ah瞧,是我修复的:P作为一种解决方法,将查询包装在另一个表达式中在旧版本中应该可以使用:
$query->newExpr($subquery)
非常感谢@ndm。我可以在CakePHP 3.5.13上确认这一点(无关):建议:索引(实质id,显示id,值)