第N行的MySQL汇总函数

时间:2016-06-22 10:32:56

标签: mysql

我尝试创建一个函数,它返回第n行的摘要,其中n由查询结果的顺序定义。 这就是我所拥有的:

CREATE DEFINER=`root`@`localhost` FUNCTION `fn_inventory_stock_on_note`( fIngredient int, fInventory int, fNote int ) RETURNS float
    DETERMINISTIC
BEGIN
    DECLARE tStock float;  
    DECLARE tNoteRow int;
    DECLARE tDummy int;

    DECLARE rStock float;  
    DECLARE rRow int;

    SET tNoteRow = 0;
    SET @rRow := 0;

    SELECT @rRow := @rRow + 1, b.ID
        INTO tNoteRow, tDummy
    FROM fn_inventory_book b
        LEFT JOIN fn_inventory_book_in bi ON b.id = bi.bookid
        LEFT JOIN fn_inventory_book_out bo ON b.id = bo.bookid
            LEFT JOIN fn_dict_transactions t ON b.transactionid = t.id
    WHERE b.inventoryid = fInventory
        AND ( bi.ingredientid = fIngredient OR bo.ingredientid = fIngredient )
    HAVING b.ID = fNote
    ORDER BY b.date ASC, t.direction ASC;

    SET @rRow := 0;
    SET @rStock := 0;

    SELECT rStock INTO tStock
    FROM ( SELECT @rRow := @rRow + 1 as rRow, @rStock := @rStock + ifnull( if( bi.id is not null, bi.quantity, bo.quantity ), 0 ) * t.direction as rStock
            FROM fn_inventory_book b
                LEFT JOIN fn_inventory_book_in bi ON b.id = bi.bookid
                LEFT JOIN fn_inventory_book_out bo ON b.id = bo.bookid
                    LEFT JOIN fn_dict_transactions t ON b.transactionid = t.id
            WHERE b.inventoryid = fInventory
                AND ( bi.ingredientid = fIngredient OR bo.ingredientid = fIngredient )
            ORDER BY b.date ASC, t.direction ASC ) as q
    WHERE rRow = tNoteRow;

    RETURN tStock;

END

其中fIngredientfInventory是查询过滤器的ID,而fNote是来自fn_inventory_book表的PK。 第一个选择在订单中获得所需的行号,工作正常。 我的问题是在第二个查询中,在子查询中创建一个具有相同过滤器和顺序的表,如第一个选择,具有相同的行号和每行的累积数量。在主查询中,我使用第一个选择中的行号过滤掉。

至少应该发生这种情况。但不是那样,当我运行这样的函数时: select fn_inventory_stock_on_note( 1545, 18, 124167 ) as stock from dual; 它返回NULL,但如果我使用相同的参数单独运行第二个查询,我会收到一笔金额。

但不是正确的数字,因为如果我只运行第二个查询的子查询,则行号不是按顺序排列的(1,2,3,6,7,4,5,8,9) ,10而不是1,2,3,..,10)。

我做错了什么?任何帮助将不胜感激。 请随意询问我的描述是否不清楚。

1 个答案:

答案 0 :(得分:0)

我为我的问题找到了一个解决方案,但是如果有人有更好的解决方案,请分享,因为我不认为我的是正确的,尽管它有效。

DROP function IF EXISTS `fn_inventory_stock_on_note`;

DELIMITER $$
CREATE DEFINER=`root`@`localhost` FUNCTION `fn_inventory_stock_on_note`( fIngredient int, fInventory int, fNote int, fItem int ) RETURNS float
    DETERMINISTIC
BEGIN
    DECLARE tStock float;  
    DECLARE tNoteRow int;

    DECLARE rStock float;  
    DECLARE rRow int;

    SET @rRow := 0;

    DROP TEMPORARY TABLE IF EXISTS stock_temp;
    CREATE TEMPORARY TABLE stock_temp ( num int, BookID int, ItemID int, qty float );
    INSERT INTO stock_temp ( SELECT @rRow := @rRow + 1 as num, q.*
                                FROM ( SELECT b.id as BookID, if( bi.id is not null, bi.id, bo.id ) as ItemID, 
                                            ifnull( if( bi.id is not null, bi.quantity, bo.quantity ), 0 ) * t.direction as qty
                                        FROM fn_inventory_book b
                                            LEFT JOIN fn_inventory_book_in bi ON b.id = bi.bookid
                                            LEFT JOIN fn_inventory_book_out bo ON b.id = bo.bookid
                                                LEFT JOIN fn_dict_transactions t ON b.transactionid = t.id
                                        WHERE b.inventoryid = fInventory
                                            AND ( bi.ingredientid = fIngredient OR bo.ingredientid = fIngredient )
                                        ORDER BY b.date ASC, t.direction ASC ) as q );


    SELECT num INTO tNoteRow
    FROM stock_temp st
    WHERE st.BookID = fNote
        AND st.ItemID = fItem;


    SELECT sum( st.qty ) INTO tStock
    FROM stock_temp st
    WHERE st.num <= tNoteRow;

    RETURN tStock;

END$$

DELIMITER ;