SQL连接库存计数表到日期表

时间:2014-06-24 06:06:58

标签: mysql sql join

我有一个不同产品的运行库存表,记录每次交易后的库存盘点。交易不会每天都发生,因此表中没有每日运行的计数。

我需要为每种产品列出所有日期,以便我可以对一段时间内的计数求和并计算。

库存

DATE        ID  Qty Count
2014-05-13  123 12  12
2014-05-19  123 -1  11
2014-05-28  123 -1  10
2014-05-29  123 -3  7
2014-05-10  124 5   5
2014-05-15  124 -1  4
2014-05-21  124 -1  3
2014-05-23  124 -3  0

我有一个表格,其中包含加入的日期,但我不确定如何将错过的日期加入多个产品。

我需要查询如下。它需要在选定的时间段内返回计数,但也包括中间的日期。

DATE        ID  Qty Count
2013-05-01  123 0   0
2013-05-02  123 0   0
2013-05-03  123 0   0
2013-05-04  123 0   0
2013-05-05  123 0   0
2013-05-06  123 0   0
2013-05-07  123 0   0
2013-05-08  123 0   0
2013-05-09  123 0   0
2013-05-10  123 0   0
2013-05-11  123 0   0
2013-05-12  123 0   0
2014-05-13  123 12  12
2013-05-14  123 0   12
2013-05-15  123 0   12
2013-05-16  123 0   12
2013-05-17  123 0   12
2013-05-18  123 0   12
2014-05-19  123 -1  11
2013-05-20  123 0   11
2013-05-21  123 0   11
2013-05-22  123 0   11
2013-05-23  123 0   11
2013-05-24  123 0   11
2013-05-25  123 0   11
2013-05-26  123 0   11
2013-05-27  123 0   11
2014-05-28  123 -1  10
2014-05-29  123 -3  7
2013-05-30  123 0   7
2013-05-31  123 0   7
2013-05-01  124 0   0
2013-05-02  124 0   0
2013-05-03  124 0   0
2013-05-04  124 0   0
2013-05-05  124 0   0
2013-05-06  124 0   0
2013-05-07  124 0   0
2013-05-08  124 0   0
2013-05-09  124 0   0
2014-05-10  124 5   5
2014-05-11  124 0   5
2014-05-12  124 0   5
2014-05-13  124 0   5
2014-05-14  124 0   5
2014-05-15  124 -1  4
2014-05-16  124 0   4
2014-05-17  124 0   4
2014-05-18  124 0   4
2014-05-19  124 0   4
2014-05-20  124 0   4
2014-05-21  124 -1  3
2014-05-22  124 0   3
2014-05-23  124 -3  0
2014-05-24  124 0   0
2014-05-25  124 0   0
2014-05-26  124 0   0
2014-05-27  124 0   0
2014-05-28  124 0   0
2014-05-29  124 0   0
2014-05-30  124 0   0
2014-05-31  124 0   0

3 个答案:

答案 0 :(得分:1)

使用inv join inv构建至少31行并构建一个31天的表。然后加入ids,最后加入原始表格。

select a.d, a.id, a.qty,
  if(a.id=@lastid, @count:=@count+a.qty, @count:=a.count) `count`,
  @lastid:=a.id _lastid
from (
  select a.d, b.id, ifnull(c.qty, 0) qty, ifnull(c.count, 0) `count`
  from (
    select adddate('2014-05-01', @row) d, @row:=@row+1 i
    from inv a
    join inv b
    join (select @row := 0) c
    limit 31) a
  join (
    select distinct id
    from inv) b
  left join inv c on a.d = c.date and b.id = c.id
  order by b.id, a.d) a
join (select @count := 0, @lastid := 0) b;

fiddle

答案 1 :(得分:0)

以下是所需的步骤:

  1. 获取两个给定日期之间的所有日期。
  2. 获取每个ID的初始库存。这是:获取该ID的给定开始日期或之后的第一个日期,读取此记录的库存并减去其交易数量。
  3. 每个日期都可以获得以前的库存。如果有该日期的记录,则添加其交易数量并将结果与​​其库存数量进行比较。如果值不匹配则抛出错误。 (这是因为您冗余地存储数据;记录的数量必须等于先前记录的数量加上其自己的交易数量。但数据总是不一致的,所以最好检查一下。)显示新的库存和差异以前的股票。
  4. 所有这些通常都是通过日期的递归CTE,使用KEEP DENSE_RANK函数的所有初始股票的派生表以及用于查看前一记录的LAG函数来实现的。

    • MySQL根本不支持递归CTE - 或CTE。您可以使用足够大的表和变量来模拟它。
    • MySQL不支持KEEP DENSE_RANK功能。您可以使用另一个派生表,而不是先找到每个ID的最小日期。
    • MySQL不支持LAG功能。您可以在MySQL中使用变量。

    话虽如此,我建议使用编程语言(Java,C#,PHP,等等)。您只需使用SQL选择原始数据,使用循环并简单地在每个记录库上执行所有processiong。这比构建满足所有需要的非常复杂的查询更方便(和可读)。您可以在SQL中执行此操作,甚至是MySQL;我只是不推荐它。

答案 2 :(得分:0)

我最终用来解决这个问题的SQL使用了@Fabricators答案的组合(这确实是一个正确的答案)和我的编辑。

我最终使用现有表来创建日期行而不是交叉连接。交叉连接在我使用的产品数量方面表现不佳。

SELECT
POSTDATE,
IF(@PROD_ID = PRODUCT_ID, @NEW := 0, @NEW := 1) AS New_Product,
(@PROD_ID := PRODUCT_ID) AS PRODUCT_ID,
QUANTITY,
IF(@NEW = 1, @INVENTORY := QUANTITY, @INVENTORY := @INVENTORY+QUANTITY) AS 'Count'
FROM (
    (
        SELECT
        POSTDATE,
        PRODUCT_ID,
        QUANTITY
        FROM
        inventory
    )
    UNION ALL
    (
        SELECT
        dateslist_sub.TransDate AS POSTDATE,
        productlist_sub.PRODUCT_ID,
        0 AS QUANTITY,
        FROM
        (
            SELECT
            TransDate
            FROM
            (
                SELECT
                adddate('2013-05-01', @row) AS TransDate,
                @row:=@row+1 i
                FROM
                any_table,
                (SELECT @row := 0) row
            ) datestable
            WHERE
            TransDate <= CURDATE()
        ) dateslist_sub
        cross join (
            SELECT
            PRODUCT_ID
            FROM
            products_table
            ORDER BY
            PRODUCT_ID ASC
        ) productlist_sub
        ORDER BY
        productlist_sub.PRODUCT_ID ASC,
        dateslist_sub.TransDate ASC
    )
    ORDER BY
    PRODUCT_ID ASC,
    POSTDATE ASC
) daily_rows_sub