根据数量将行拆分为多行

时间:2015-08-08 05:39:15

标签: sql postgresql postgresql-9.2

我的表格中有一行:

 id  m_id quantity
 1   1  1500
 2   1  -1000
 3   2  -3000
 4   2   2000
 5   3  400
 6   3  -1000
 7   4   500
 8   4   -500
 9   5   1500

我想创建一个返回此视图的视图:

 id   m_id   quantity
  1  1    500
  2  1    1000
  3   1    -1000
  4   2   -1000
  5   2   -2000
  6   2   2000
  7   3   400
  8   3   -400
  9   3   -600
  10  4   500
  11  4   -500
  12  5   1500

View将返回正/负的相等值,并将其余部分拆分为单独的行。因此,如果给定m_id的正数和负数不同,则将两行分成三行。

1 个答案:

答案 0 :(得分:0)

我认为你可以使用这样的查询:

WITH t1 AS (
    SELECT *, 
        LAG(quantity) OVER (PARTITION BY m_id ORDER BY id) as pq, -- Previous quantity based on id
        LEAD(quantity) OVER (PARTITION BY m_id ORDER BY id) as nq -- Next quantity based on id
    FROM yourTable    
), t2 AS (
SELECT id, m_id, 1 as ord,
    CASE 
        -- If sign is changed and quantity is bigger than that use next quantity
        WHEN (SIGN(nq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(nq)) THEN -nq
        -- If sign is changed and quantity is bigger than that use previous quantity
        WHEN (SIGN(pq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(pq)) THEN -pq
        -- Else use original quantity
        ELSE quantity
    END As quantity
FROM t1
UNION ALL  -- Add extra rows
SELECT id , m_id,
    CASE 
        -- Set order to be higher than original quantity
        WHEN (SIGN(nq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(nq)) THEN 0
        -- Set order to be lower than original quantity
        WHEN (SIGN(pq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(pq)) THEN 2
    END As ord,
    -- quantity is difference
    CASE 
        WHEN (SIGN(nq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(nq)) THEN nq + quantity
        WHEN (SIGN(pq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(pq)) THEN pq + quantity
    END As quantity
FROM t1
WHERE   
    -- Find differences more
    1 = CASE 
            WHEN (SIGN(nq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(nq)) THEN 1
            WHEN (SIGN(pq) <> SIGN(quantity)) AND (ABS(quantity) > ABS(pq)) THEN 1
            ELSE 0
        END)
SELECT 
    -- Use new values for id
    ROW_NUMBER() OVER (ORDER BY id, ord) As id, 
    m_id, quantity
FROM t2;