[SOLVED] IFNULL doesn't works my_sql

Issue

I’m trying to get a sql select inside an update, but always return null.

UPDATE ps_stock_available sa
SET sa.reserved_quantity = (
    SELECT IFNULL(SUM(od.product_quantity - od.product_quantity_refunded),0) 
    FROM ps_orders o
    INNER JOIN ps_order_detail od ON od.id_order = o.id_order
    INNER JOIN ps_order_state os ON os.id_order_state = o.current_state
    WHERE o.id_shop = 1 AND
    os.shipped != 1 AND (
        o.valid = 1 OR (
            os.id_order_state NOT IN ('6,28,59') AND
            os.id_order_state NOT IN ('8')
        )
    ) AND sa.id_product = od.product_id AND
    sa.id_product_attribute = od.product_attribute_id
    GROUP BY od.product_id, od.product_attribute_id
)
WHERE sa.id_shop = 1 AND sa.id_product = 3374;

If the sum is null, the subquery has to return 0.
I get this query update from prestashop class (StockManager.php, method: updateReservedProductQuantity).

This is the original code:

$updateReservedQuantityQuery = '
            UPDATE {table_prefix}stock_available sa
            SET sa.reserved_quantity = (
                SELECT SUM(od.product_quantity - od.product_quantity_refunded)
                FROM {table_prefix}orders o
                INNER JOIN {table_prefix}order_detail od ON od.id_order = o.id_order
                INNER JOIN {table_prefix}order_state os ON os.id_order_state = o.current_state
                WHERE o.id_shop = :shop_id AND
                os.shipped != 1 AND (
                    o.valid = 1 OR (
                        os.id_order_state != :error_state AND
                        os.id_order_state != :cancellation_state
                    )
                ) AND sa.id_product = od.product_id AND
                sa.id_product_attribute = od.product_attribute_id
                GROUP BY od.product_id, od.product_attribute_id
            )
            WHERE sa.id_shop = :shop_id
        ';

        $strParams = array(
            '{table_prefix}' => _DB_PREFIX_,
            ':shop_id' => (int) $shopId,
            ':error_state' => (int) $errorState,
            ':cancellation_state' => (int) $cancellationState,
        );

        if ($idProduct) {
            $updateReservedQuantityQuery .= ' AND sa.id_product = :product_id';
            $strParams[':product_id'] = (int) $idProduct;
        }

        if ($idOrder) {
            $updateReservedQuantityQuery .= ' AND sa.id_product IN (SELECT product_id FROM {table_prefix}order_detail WHERE id_order = :order_id)';
            $strParams[':order_id'] = (int) $idOrder;
        }

        $updateReservedQuantityQuery = strtr($updateReservedQuantityQuery, $strParams); 

Why always return null ?

Solution

You need to put the ifnull check on the outer query, not the inner, which can return no rows.

You can use coalesce here, such as:

UPDATE ps_stock_available sa
SET sa.reserved_quantity = coalesce((
    SELECT SUM(od.product_quantity - od.product_quantity_refunded)
    FROM ps_orders o
    INNER JOIN ps_order_detail od ON od.id_order = o.id_order
    INNER JOIN ps_order_state os ON os.id_order_state = o.current_state
    WHERE o.id_shop = 1 AND
    os.shipped != 1 AND (
        o.valid = 1 OR (
            os.id_order_state NOT IN ('6,28,59') AND
            os.id_order_state NOT IN ('8')
        )
    ) AND sa.id_product = od.product_id AND
    sa.id_product_attribute = od.product_attribute_id
    GROUP BY od.product_id, od.product_attribute_id
), 0)
WHERE sa.id_shop = 1 AND sa.id_product = 3374;

Answered By – Stu

Answer Checked By – Marilyn (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.