CodeIgniter 4: 如何使用查询构建器链编写条件语句。即,如果…然后

huangapple go评论69阅读模式
英文:

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();
}

条件语句

$builder->when()

这允许根据条件修改查询,而不会打破查询构建器链。第一个参数是条件,它应该评估为布尔值。第二个参数是一个可调用的函数,当条件为 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();
}

Conditional Statements

$builder->when()

> 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.

huangapple
  • 本文由 发表于 2023年6月15日 15:26:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76480082.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定