使用IFNULL。。。CakePHP 3中的组_CONCAT()
我有一个普通的MySQL查询,如下所示,运行良好:使用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
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);
另见
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,值)