我正在使用Case for SQL select查询,并希望动态计算价格

问题描述

我的控制器代码

$nicepay_commission = Configure::read('nicepay_commission');
$paypal_commission = Configure::read('paypal_commission');
 
$getQuery = $this->OrderProduct
    ->find('all',[
        'contain' => [
            'Orders' => ['PaymentMethods'],'Products' => ['ProductType']
        ]
    ])
   ->distinct('Products.id')
   ->select([
        'product_name' => 'MAX(Products.product_name)','count' => 'SUM(OrderProduct.qty)','actual_rate' => 'SUM(OrderProduct.actual_rate)','revenue_based_actual_rate' => '(
            SUM(
                CASE
                WHEN PaymentMethods.payment_gateway = \'nicepay\'
                THEN (OrderProduct.actual_rate-((OrderProduct.actual_rate*"'.$nicepay_commission.'")/100))
                WHEN PaymentMethods.payment_gateway = \'paypal\'
                THEN (OrderProduct.actual_rate-((OrderProduct.actual_rate*"'.$paypal_commission.'")/100))
                ELSE (OrderProduct.actual_rate)
                END
            )
        )'
   ])
   ->where($conditions);

但是发生了一些错误,我找不到解决方法

我的错误日志如下

2020-08-20 07:56:56错误:[PDOException] sqlSTATE [42S22]:[Microsoft] [用于sql Server的ODBC驱动程序17] [sql Server]无效的列名'2'。

如果我静态使用这些值,那么就没有错误

$getQuery = $this->OrderProduct
    ->find('all','Products' => ['ProductType']
        ]
    ])
    ->distinct('Products.id')
    ->select([
        'product_name' => 'MAX(Products.product_name)','revenue_based_actual_rate' => '(
            SUM(
                CASE
                WHEN PaymentMethods.payment_gateway = \'nicepay\'
                THEN (OrderProduct.actual_rate-((OrderProduct.actual_rate*2)/100))
                WHEN PaymentMethods.payment_gateway = \'paypal\'
                THEN (OrderProduct.actual_rate-((OrderProduct.actual_rate*1)/100))
                ELSE (OrderProduct.actual_rate)
                END
            )
        )'
    ])
    ->where($conditions);

解决方法

首先,切勿将日期直接插入SQL代码段中,如果可以避免的话,即使您认为日期可能来自安全来源!

话虽如此,请查看生成的SQL查询(如果尚未使用Debug Kit,则应安装它),然后将值括在双引号中,即生成的SQL将如下所示:

OrderProduct.actual_rate * "2"

在ISO SQL中表示2将用作标识符。

删除引号可以解决此问题,但是您仍在将动态数据注入SQL字符串中,如果可能的话,应避免这样做,因此应更进一步并绑定值,以减少机会SQL注入漏洞的说明:

// ...
->select([
    'product_name' => 'MAX(Products.product_name)','count' => 'SUM(OrderProduct.qty)','actual_rate' => 'SUM(OrderProduct.actual_rate)','revenue_based_actual_rate' => '(
        SUM(
            CASE
            WHEN PaymentMethods.payment_gateway = \'nicepay\'
            THEN (OrderProduct.actual_rate-((OrderProduct.actual_rate * :nicepayCommission)/100))
            WHEN PaymentMethods.payment_gateway = \'paypal\'
            THEN (OrderProduct.actual_rate-((OrderProduct.actual_rate * :paypalCommission)/100))
            ELSE (OrderProduct.actual_rate)
            END
        )
    )'
])
->bind(':nicepayCommission',$nicepay_commission,'integer')
->bind(':paypalCommission',$paypal_commission,'integer')
// ...

另请参见