英文:
CodeIgniter 4: How to write conditional statements using the query builder chain. I.e., if...then
问题
以下是您要求的翻译:
在实际服务器中,以下代码返回一个mysqli_sql_exception错误。我已经从以下代码块中追踪到了错误:
public function getByOPCR($opcr_id, $kpi_ids)
{
return $this->select('opcr_success_indicators.*, kpis.name, kpis.datatype')
->join('kpis', 'opcr_success_indicators.kpi_id = kpis.id', 'left')
->where('opcr_success_indicators.opcr_id', $opcr_id)
->whereIn('opcr_success_indicators.kpi_id', $kpi_ids)
->findAll();
}
其中$opcr_id
是一个数字,$kpi_ids
是一个数组。
在我的本地环境中一切正常运行,但服务器返回以下错误:
在您的SQL语法中存在一个错误;请检查与您的MySQL服务器版本相对应的手册,以获取正确的语法用法,位于第5行附近
我正在使用以下服务器信息的CodeIgniter 4:
本地环境:
- Apache 2.4.46
- MariaDB 10.4.14
- PHP 7.4.9 (VC15 X86 64位线程安全) + PEAR
实际服务器:
- PHP 7.4
- MySQL 8
我花了相当多的时间来弄清楚在实际服务器上出了什么问题。非常感谢您的帮助 🙏
我设法获取了使用的lastQuery,并返回一个有效的语法:
SELECT `opcr_success_indicators`.*, `kpis`.`name`, `kpis`.`datatype`
FROM `opcr_success_indicators`
LEFT JOIN `kpis` ON `opcr_success_indicators`.`kpi_id` = `kpis`.`id`
WHERE `opcr_success_indicators.opcr_id` = '1'
AND `opcr_success_indicators.kpi_id` IN ('1','2','3')
我尝试记录d($kpi_ids[0])
,它返回一个未定义的偏移量0。
在此之前,以下内容返回了一个有效的数组。
d($kpi_ids);
d(gettype($kpi_ids));
dd(array_keys($kpi_ids));
当执行查询时一切都崩溃了:->findAll()
或 get()->getResult()
英文:
The following returns a mysqli_sql_exception error in the live server. I have traced the error from the following block of code:
public function getByOPCR($opcr_id, $kpi_ids)
{
return $this->select('opcr_success_indicators.*, kpis.name, kpis.datatype')
->join('kpis', 'opcr_success_indicators.kpi_id = kpis.id', 'left')
->where('opcr_success_indicators.opcr_id', $opcr_id)
->whereIn('opcr_success_indicators.kpi_id', $kpi_ids)
->findAll();
}
where
$opcr_id
is a number and
$kpi_ids
is an array
Everything works fine in my localhost, but the server returns the following:
> You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 5
I'm using CodeIgniter 4 with the following server information:
Localhost:
- Apache 2.4.46
- MariaDB 10.4.14
- PHP 7.4.9 (VC15 X86 64bit thread safe) + PEAR
Live Server
- PHP 7.4
- MySQL 8
I've been spending quite a lot of time figuring out what's wrong in the live server. Your help is greatly appreciated 🤧
I managed to get the lastQuery used and it returns a valid syntax:
SELECT `opcr_success_indicators`.*, `kpis`.`name`, `kpis`.`datatype`
FROM `opcr_success_indicators`
LEFT JOIN `kpis` ON `opcr_success_indicators`.`kpi_id` = `kpis`.`id`
WHERE `opcr_success_indicators.opcr_id` = '1'
AND `opcr_success_indicators.kpi_id` IN ('1','2','3')
I tried logging d($kpi_ids[0])
it returns an undefined offset 0.
Prior to it, the following returns a valid array.
d($kpi_ids);
d(gettype($kpi_ids));
dd(array_keys($kpi_ids));
It all breaks when the query is executed: ->findAll()
or get()->getResult()
答案1
得分: 1
Explanation
这是因为当实际参数 $kpi_ids
是一个空数组时,查询构建器函数:
->whereIn('opcr_success_indicators.kpi_id', $kpi_ids)
会产生 ...WHERE opcr_success_indicators.kpi_id IN ()
,而这在MySQL或MariaDB中是不正确的语法。
Solution
为了保护自己免受此影响,您需要使用条件语句。
Solution Before CodeIgniter Version 4.3.0:
public function getByOPCR($opcr_id, $kpi_ids)
{
$builder = $this->select('opcr_success_indicators.*, kpis.name, kpis.datatype')
->join('kpis', 'opcr_success_indicators.kpi_id = kpis.id', 'left')
->where('opcr_success_indicators.opcr_id', $opcr_id);
if (!empty($kpi_ids)) {
$builder->whereIn('opcr_success_indicators.kpi_id', $kpi_ids);
}
return $builder->findAll();
}
Solution After CodeIgniter Version 4.3.0:
注意:在PHP中,空数组在条件中会被视为假值。php.net: 转换为布尔值
public function getByOPCR($opcr_id, $kpi_ids)
{
return $this->select('opcr_success_indicators.*, kpis.name, kpis.datatype')
->join('kpis', 'opcr_success_indicators.kpi_id = kpis.id', 'left')
->where('opcr_success_indicators.opcr_id', $opcr_id)
->when($kpi_ids, static function ($query, $kpi_ids) {
$query->whereIn('opcr_success_indicators.kpi_id', $kpi_ids);
})
->findAll();
}
这允许根据条件修改查询,而不会打破查询构建器链。第一个参数是条件,它应该评估为布尔值。第二个参数是一个可调用的函数,当条件为
true
时将运行它。由于条件被评估为
true
,所以将调用可调用函数。在条件中设置的值将作为第二个参数传递给可调用函数,以便在查询中使用。
英文:
Explanation
This is so because when the actual argument $kpi_ids
is an empty array, the query builder function:
->whereIn('opcr_success_indicators.kpi_id', $kpi_ids)
produces ...WHERE opcr_success_indicators.kpi_id IN ()
, and this is incorrect syntax in MySQL or MariaDB.
Solution
To protect yourself from this, you need to use conditional statements.
Solution Before CodeIgniter Version 4.3.0:
public function getByOPCR($opcr_id, $kpi_ids)
{
$builder = $this->select('opcr_success_indicators.*, kpis.name, kpis.datatype')
->join('kpis', 'opcr_success_indicators.kpi_id = kpis.id', 'left')
->where('opcr_success_indicators.opcr_id', $opcr_id);
if (!empty($kpi_ids)) {
$builder->whereIn('opcr_success_indicators.kpi_id', $kpi_ids);
}
return $builder->findAll();
}
Solution After CodeIgniter Version 4.3.0:
Note: empty arrays are falsy in PHP. php.net: Converting to boolean
public function getByOPCR($opcr_id, $kpi_ids)
{
return $this->select('opcr_success_indicators.*, kpis.name, kpis.datatype')
->join('kpis', 'opcr_success_indicators.kpi_id = kpis.id', 'left')
->where('opcr_success_indicators.opcr_id', $opcr_id)
->when($kpi_ids, static function ($query, $kpi_ids) {
$query->whereIn('opcr_success_indicators.kpi_id', $kpi_ids);
})
->findAll();
}
> This allows modifying the query based on a condition without breaking
> out of the query builder chain. The first parameter is the condition,
> and it should evaluate to a boolean. The second parameter is a
> callable that will be ran when the condition is true
.
>
> Since the condition is evaluated as true
, the callable will be
> called. The value set in the condition will be passed as the second
> parameter to the callable so it can be used in the query.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论