SQL - 先进先出

时间:2017-12-14 09:22:23

标签: sql fifo

我想在我的股票表中实现FIFO

表格如下:

---+------------+-----------+--------+--------------+-----------
id | shift_type | item_type | amount | name         | date
---+------------+-----------+--------+--------------+-----------
1  | in         | apple     | 50     | apple type 1 | 2017-12-01
2  | out        | apple     | 30     | apple type 1 | 2017-12-02
3  | in         | apple     | 40     | apple type 2 | 2017-12-04
4  | in         | apple     | 60     | apple type 3 | 2017-12-05
5  | out        | apple     | 20     | apple type 1 | 2017-12-07
6  | out        | apple     | 10     | apple type 1 | 2017-12-07
7  | in         | apple     | 20     | apple type 3 | 2017-12-09

并保留有关库存变化的信息。 如果我想只拿最早的收入 - 我可以记录身份最低或最早的日期。

但......也有“出局”的转变。 所以,如果我想以50个苹果为例,查询应该返回2条记录:

---+------------+-----------+--------+--------------+------------+-----
id | shift_type | item_type | amount | name         | date       | take
---+------------+-----------+--------+--------------+------------+-----
1  | in         | apple     | 50     | apple type 1 | 2017-12-01 | 20
3  | in         | apple     | 40     | apple type 2 | 2017-12-04 | 30

因为 - 先出(id 2)需要30个苹果,所以从收入id 1中剩余20个,其余部分应从收入ID 3中取出

如何使用SQL实现它?

1 个答案:

答案 0 :(得分:0)

我在这里做了一些事。但需要用不同的输入进行测试。

如果没有,在外部选择查询中说50,它将为您提供需要从中获取苹果的堆栈列表。

WITH view_t
AS (
SELECT 1 id
    ,'in' shift_type
    ,'apple' item_type
    ,50 amount
    ,'apple type 1' NAME
    ,TO_DATE('2017-12-01', 'yyyy-mm-dd') date1
FROM dual

UNION ALL

SELECT 2
    ,'out'
    ,'apple'
    ,30
    ,'apple type 1'
    ,TO_DATE('2017-12-02', 'yyyy-mm-dd')
FROM dual

UNION ALL

SELECT 3
    ,'in'
    ,'apple'
    ,40
    ,'apple type 2'
    ,TO_DATE('2017-12-04', 'yyyy-mm-dd')
FROM dual

UNION ALL

SELECT 4
    ,'in'
    ,'apple'
    ,60
    ,'apple type 3'
    ,TO_DATE('2017-12-05', 'yyyy-mm-dd')
FROM dual

UNION ALL

SELECT 5
    ,'out'
    ,'apple'
    ,30
    ,'apple type 2'
    ,TO_DATE('2017-12-07', 'yyyy-mm-dd')
FROM dual
)
SELECT id
,date1
,shift_type
,NAME
,itemrem
,nvl((
        50 - LAG(itemrem) OVER (
            ORDER BY id
            )
        ), itemrem) take
 FROM (
SELECT id
    ,date1
    ,shift_type
    ,NAME
    ,SUM(amtretain) OVER (
        ORDER BY id
        ) itemrem
FROM (
    SELECT id
        ,date1
        ,shift_type
        ,amount
        ,signamt
        ,NAME
        ,CASE 
            WHEN LEAD(shift_type) OVER (
                    ORDER BY id
                    ) = 'out'
                THEN LEAD(signamt) OVER (
                        ORDER BY id
                        ) + signamt
            ELSE signamt
            END amtretain
    --date1,shift_type,sum(signamt) over(order by id)
    FROM (
        SELECT id
            ,shift_type
            ,NAME
            ,item_type
            ,date1
            ,DECODE(shift_type, 'in', amount, 'out', amount * - 1) signamt
            ,amount
        FROM view_t
        )
    )
WHERE shift_type = 'in'
);

这种方法背后的想法是,

  1. 根据shift_type
  2. 转换金额的符号
  3. 使用线索根据其班次类型减去信号
  4. 使用运行总计来识别每个日期的剩余苹果
  5. 最后使用带有苹果输入数量的LAG来计算需要花费多少