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

I am using Case for SQL select query and want to calculate price dynamically

我的控制器代码

$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 Error: [PDOException] SQLSTATE[42S22]: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Invalid column name '2'.

如果我静态使用这些值则没有错误

$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*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')
// ...

另见