Python DataError来自存储过程,但手动运行时没有错误

时间:2010-06-28 13:48:02

标签: python postgresql stored-procedures plpgsql

我收到此错误:

DataError: (DataError) invalid input syntax for integer:
"1.50" CONTEXT: PL/pgSQL function "sp_aggregate_cart" line 82
at FOR over EXECUTE statement
'SELECT total_items, subtotal, is_shipping_required, discount_other,
is_shipping_discount FROM sp_aggregate_cart(8135)' {}

运行我的应用程序代码时。当我手动运行该查询时,一切都很好。我碰巧知道这个实例中的1.50是一个值,它通过声明为numeric(10,2)的函数中的变量传递。它不是由函数返回的,只是处理完毕。

此查询如何在应用程序代码中抛出此错误,但在pgadmin中运行正常?

好的,这是存储过程。 discount_amount是您看到错误的1.50。

CREATE TYPE buy_object_info as (object_id integer, promo_id integer, buy_quantity integer, get_quantity integer, quantity integer, discount_amount numeric(10,2));

-- Function: sp_aggregate_cart(integer)

DROP FUNCTION sp_aggregate_cart(integer);

CREATE OR REPLACE FUNCTION sp_aggregate_cart(p_cart_id integer)
  RETURNS SETOF cart AS
$BODY$
DECLARE
    v_total_items int;
    v_subtotal numeric;
    v_discount_other record;
    v_items_shipping integer;
    v_shipping_required boolean;
    buy_object_info buy_object_info%rowtype;
    buy_object_price numeric;
    buy_object_orginal_subtotal numeric;
    other_promo_id integer;
    buy_object_query text;
    other_promo_buy_quantity integer;
    BEGIN
    -- Get the total number of items
    SELECT sum(quantity) INTO v_total_items FROM cart_object WHERE cart_id = p_cart_id;

    -- Get the subtotal
    SELECT sum(unit_price) INTO v_subtotal FROM (
        SELECT co.cart_id, co.object_id, co.quantity, 
            CASE 
                --When buy only cart quantity = buy quantity
                WHEN (p.get_quantity = 0 or p.get_quantity IS NULL) AND (p.buy_quantity > 0 OR p.buy_quantity IS NOT NULL) AND pbo.object_id = co.object_id AND p.buy_quantity = co.quantity
                    THEN ((cast(oa.value AS numeric(10,2)) - COALESCE(pco.discount_amount, 0)) * p.buy_quantity)
                --When buy only more than the buy quantity in cart
                WHEN (p.get_quantity = 0 or p.get_quantity IS NULL) AND (p.buy_quantity > 0 OR p.buy_quantity IS NOT NULL) AND pbo.object_id = co.object_id AND p.buy_quantity < co.quantity
                    THEN (((cast(oa.value AS numeric(10,2)) - COALESCE(pco.discount_amount, 0))) * p.buy_quantity) + ((co.quantity - p.buy_quantity) * (cast(oa.value AS numeric(10,2))))
                --When buy/get
                WHEN (p.get_quantity > 0 or p.get_quantity IS NOT NULL) AND (p.buy_quantity > 0 OR p.buy_quantity IS NOT NULL) AND pgo.object_id = co.object_id                   
                    THEN ((cast(oa.value AS numeric(10,2)) - COALESCE(pco.discount_amount, 0)) + ((co.quantity - 1) * cast(oa.value AS numeric(10,2))))
                WHEN (p.get_quantity = 0 or p.get_quantity IS NULL) AND (p.buy_quantity = 0 OR p.buy_quantity IS NULL)
                    THEN ((cast(oa.value AS numeric(10,2)) - COALESCE(pco.discount_amount, 0)) * co.quantity)
                ELSE
                    (cast(oa.value AS numeric(10,2)) * co.quantity)
            END AS "unit_price"     
            FROM cart_object co
            JOIN object_attr oa ON oa.object_id=co.object_id AND oa.attr_id=50
            LEFT JOIN promo_cart_objects pco ON pco.cart_id=co.cart_id AND pco.object_id=co.object_id
            LEFT JOIN promos p ON p.promo_id=pco.promotion_id
            LEFT JOIN promo_get_objects pgo ON pgo.object_id = co.object_id AND pgo.promo_id = pco.promotion_id
            LEFT JOIN promo_buy_objects pbo ON pbo.object_id = co.object_id AND pbo.promo_id = pco.promotion_id
        WHERE co.cart_id=p_cart_id
        GROUP BY co.cart_id, co.object_id, oa.value, co.quantity, p.get_quantity, p.buy_quantity, pbo.object_id, pgo.object_id, pco.discount_amount, p.promo_id
    ) AS a;
    --Get the buyobjects that are in the cart and need to have their line item subtotal recalculated
    -- :)
    buy_object_query := 
        'SELECT DISTINCT ON(pbo.object_id) 
            pbo.object_id, p.promo_id, p.buy_quantity, p.get_quantity, pco.discount_amount, co.quantity
        FROM 
            promo_buy_objects pbo 
        JOIN 
            promos p on p.promo_id = pbo.promo_id AND p.active = TRUE AND now() BETWEEN p.start_date AND p.end_date 
        JOIN 
            promo_cart_objects pco ON pco.object_id = pbo.object_id 
        JOIN 
            cart_object co ON co.cart_id = pco.cart_id AND co.object_id = pbo.object_id
        WHERE 
            pco.cart_id = ' || p_cart_id || '
            AND 
            pbo.object_id IN(SELECT 
                        po.object_id 
                    FROM 
                        promo_objects po 
                    JOIN 
                        promos p on p.promo_id = po.promotion_id AND p.active = TRUE AND now() BETWEEN p.start_date AND p.end_date 
                    JOIN 
                        promo_cart_objects pco ON pco.object_id = po.object_id 
                    WHERE 
                        pco.cart_id = ' || p_cart_id || '
                    UNION 
                    SELECT 
                        pgo.object_id 
                    FROM 
                        promo_get_objects pgo 
                    JOIN 
                        promos p on p.promo_id = pgo.promo_id AND p.active = TRUE AND now() BETWEEN p.start_date AND p.end_date 
                    JOIN 
                        promo_cart_objects pco ON pco.object_id = pgo.object_id JOIN cart_object co ON co.cart_id = pco.cart_id 
                    WHERE pco.cart_id = ' || p_cart_id || ')
            AND
            co.quantity > p.buy_quantity';
        FOR buy_object_info IN EXECUTE buy_object_query LOOP
            --Get the price
            SELECT cast("value" as numeric(10,2)) INTO buy_object_price FROM object_attr WHERE object_id = buy_object_info.object_id AND attr_id = 50;
            --What was that original price? Redundant I know ...I might get around to optimizing this function
            IF (buy_object_info.get_quantity = 0 or buy_object_info.get_quantity IS NULL) AND (buy_object_info.buy_quantity > 0 OR buy_object_info.buy_quantity IS NOT NULL) AND buy_object_info.buy_quantity = buy_object_info.quantity
                THEN buy_object_orginal_subtotal := ((buy_object_price - COALESCE(buy_object_info.discount_amount, 0)) * buy_object_info.buy_quantity);
            --When buy only more than the buy quantity in cart
            ELSIF (buy_object_info.get_quantity = 0 or buy_object_info.get_quantity IS NULL) AND (buy_object_info.buy_quantity > 0 OR buy_object_info.buy_quantity IS NOT NULL) AND buy_object_info.buy_quantity < buy_object_info.quantity
                THEN buy_object_orginal_subtotal := (((buy_object_price - COALESCE(buy_object_info.discount_amount, 0))) * buy_object_info.buy_quantity) + ((buy_object_info.quantity - buy_object_info.buy_quantity) * (buy_object_price));
            --When buy/get
            ELSIF (buy_object_info.get_quantity > 0 or buy_object_info.get_quantity IS NOT NULL) AND (buy_object_info.buy_quantity > 0 OR buy_object_info.buy_quantity IS NOT NULL)               
                THEN buy_object_orginal_subtotal := ((buy_object_price - COALESCE(buy_object_info.discount_amount, 0)) + ((buy_object_info.quantity - 1) * buy_object_price));
            ELSIF (buy_object_info.get_quantity = 0 or buy_object_info.get_quantity IS NULL) AND (buy_object_info.buy_quantity = 0 OR buy_object_info.buy_quantity IS NULL)
                THEN buy_object_orginal_subtotal := ((buy_object_price - COALESCE(buy_object_info.discount_amount, 0)) * buy_object_info.quantity);
            ELSE
                buy_object_orginal_subtotal := (cast(oa.value AS numeric(10,2)) * buy_object_info.quantity);
            END IF;
            --Well now we need that other promotion...this is so lame
             SELECT INTO other_promo_id, other_promo_buy_quantity promo_id, buy_quantity FROM(
                    SELECT 
                        p.promo_id AS promo_id, p.buy_quantity AS buy_quantity
                    FROM 
                        promo_objects po 
                    JOIN 
                        promos p on p.promo_id = po.promotion_id AND p.active = TRUE AND now() BETWEEN p.start_date AND p.end_date 
                    JOIN 
                        promo_cart_objects pco ON pco.object_id = po.object_id 
                    WHERE 
                        pco.cart_id = p_cart_id
                    UNION 
                    SELECT 
                        p.promo_id AS promo_id, p.buy_quantity AS buy_quantity
                    FROM 
                        promo_get_objects pgo 
                    JOIN 
                        promos p on p.promo_id = pgo.promo_id AND p.active = TRUE AND now() BETWEEN p.start_date AND p.end_date 
                    JOIN 
                        promo_cart_objects pco ON pco.object_id = pgo.object_id JOIN cart_object co ON co.cart_id = pco.cart_id 
                    WHERE pco.cart_id = p_cart_id AND pco.object_id = buy_object_info.object_id) AS foo;
            --Alrighty now that we have everything we need, let's perform this funky ass math
            v_subtotal := v_subtotal - buy_object_orginal_subtotal;
            v_subtotal := v_subtotal + (other_promo_buy_quantity * buy_object_price) + ((buy_object_info.quantity - other_promo_buy_quantity) * (buy_object_price - COALESCE(buy_object_info.discount_amount, 0)));
        END LOOP;
    --Get Discount Other
    --SELECT COALESCE(max(discount_amount), 0), is_shipping_discount INTO v_discount_other FROM cart_promotion WHERE cart_id=p_cart_id;
    SELECT COALESCE(discount_amount, 0) as discount, COALESCE(is_shipping_discount, false) as is_shipping_discount INTO v_discount_other
    FROM promo_carts WHERE cart_id=p_cart_id order by discount_amount desc limit 1;

    -- Determine if shipping is required
    SELECT count(*) INTO v_items_shipping
    FROM object o, object_attr oa, cart_object co
    WHERE oa.object_id = o.object_id AND co.object_id = o.object_id 
    AND attr_id = 74 and cart_id = p_cart_id AND oa.value = 'true';

    IF v_items_shipping > 0 THEN
        v_shipping_required := True;
    ELSE 
        v_shipping_required := False;
    END IF;

    -- Update the cart
    UPDATE cart SET 
        total_items = COALESCE(v_total_items, 0), 
        subtotal = COALESCE(v_subtotal, 0),
        is_shipping_required = v_shipping_required,
        discount_other = COALESCE(v_discount_other.discount, 0),
        is_shipping_discount = COALESCE(v_discount_other.is_shipping_discount, false)
    WHERE id = p_cart_id;

    RETURN QUERY SELECT * from cart WHERE id = p_cart_id;
    END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE
  COST 100
  ROWS 1000;
ALTER FUNCTION sp_aggregate_cart(integer) OWNER TO postgres;

1 个答案:

答案 0 :(得分:1)

buy_object_query正在以错误的顺序选择东西。它选择我在代码buy_object_info开头创建的类型。我正在选择小数到整数