填写表格中的值之间的差距 - MySQL

时间:2017-04-20 16:44:49

标签: mysql lag window-functions lead

我有一张桌子(MySQL)

UserID | CreationTS | Type         | Value    | Bonus Value    
259275 | 2012-08-01 | Deposit      | -------- | NULL
259275 | 2012-08-02 | BonusApplied |      175 | 175
259275 | 2012-08-03 | TradeOrder   | -------- | 175
259275 | 2012-08-06 | TradeOrder   | -------- | 175
259275 | 2012-08-10 | BonusApplied |      180 | 180
259275 | 2012-08-11 | TradeOrder   | -------- | 180
259275 | 2012-08-12 | TradeOrder   | -------- | 180
259275 | 2012-08-15 | TradeOrder   | -------- | 180
259275 | 2012-08-17 | BonusApplied |      200 | 200
259275 | 2012-08-18 | TradeOrder   | -------- | 200
259681 | 2012-08-01 | Deposit      | -------- | NULL
259681 | 2012-08-02 | BonusApplied |      175 | 175
259681 | 2012-08-03 | TradeOrder   | -------- | 175
259681 | 2012-08-06 | TradeOrder   | -------- | 175
259681 | 2012-08-10 | BonusApplied |      180 | 180
259681 | 2012-08-11 | TradeOrder   | -------- | 180
259681 | 2012-08-12 | TradeOrder   | -------- | 180
259681 | 2012-08-15 | TradeOrder   | -------- | 180
259681 | 2012-08-17 | BonusApplied |      200 | 200
259681 | 2012-08-18 | TradeOrder   | -------- | 200

我需要根据每个用户的第一个值和BonusApplied填写在每个UserID的BonusApplied类型之间填充的VALUE中的空白。 最终值位于“奖励值”列中。这就是我需要的。 如果有一个基于@variables的解决方案而不是JOIN,那就太好了。

3 个答案:

答案 0 :(得分:1)

试试这个:

CREATE TABLE bonusTable (userID INT UNSIGNED, CreationTs DATE, `Type` CHAR(32), `Value` INT UNSIGNED, BonusValue INT);

INSERT INTO bonusTable VALUES
(259275, '2012-08-01', 'Deposit', NULL, NULL),
(259275, '2012-08-02', 'BonusApplied', 175, 175),
(259275, '2012-08-03', 'TradeOrder', NULL, 175),
(259275, '2012-08-06', 'TradeOrder', NULL, 175),
(259275, '2012-08-10', 'BonusApplied', 180, 180),
(259275, '2012-08-11', 'TradeOrder', NULL, 180),
(259275, '2012-08-12', 'TradeOrder', NULL, 180),
(259275, '2012-08-15', 'TradeOrder', NULL, 180),
(259275, '2012-08-17', 'BonusApplied', 200, 200),
(259275, '2012-08-18', 'TradeOrder', NULL, 200),
(259681, '2012-08-01', 'Deposit', NULL, NULL),
(259681, '2012-08-02', 'BonusApplied', 175, 175),
(259681, '2012-08-03', 'TradeOrder', NULL, 175),
(259681, '2012-08-06', 'TradeOrder', NULL, 175),
(259681, '2012-08-10', 'BonusApplied', 180, 180),
(259681, '2012-08-11', 'TradeOrder', NULL, 180),
(259681, '2012-08-12', 'TradeOrder', NULL, 180),
(259681, '2012-08-15', 'TradeOrder', NULL, 180),
(259681, '2012-08-17', 'BonusApplied', 200, 200),
(259681, '2012-08-18', 'TradeOrder', NULL, 200);


SET @VUserID := NULL;
SET @VValue := NULL;

SELECT CreationTs, `Type`, IF(@VUserID = userID, IF(`Value` IS NULL, @VValue, @VValue := `Value`), @VValue := `Value`) BonusValue, @VUserID := userID userID FROM bonusTable ORDER BY userID, CreationTs;

#Cols in original order:
SELECT userID, CreationTs, `Type`, BonusValue FROM (
SELECT CreationTs, `Type`, IF(@VUserID = userID, IF(`Value` IS NULL, @VValue, @VValue := `Value`), @VValue := `Value`) BonusValue, @VUserID := userID userID FROM bonusTable ORDER BY userID, CreationTs
) A;

答案 1 :(得分:0)

这是一个JOIN类型解决方案:

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(id INT NOT NULL
,seq INT NOT NULL
,value INT NULL
,PRIMARY KEY(id,seq)
);

INSERT INTO my_table VALUES
(101, 1,NULL),
(101, 2,175),
(101, 4,NULL),
(101, 7,NULL),
(101, 9,180),
(101,11,NULL),
(102, 2,NULL),
(102, 3,175),
(102, 4,NULL),
(102, 7,NULL),
(102, 9,200),
(102,12,NULL);

SELECT x.*
     , MAX(y.value) i 
  FROM my_table x 
  JOIN my_table y 
    ON y.id = x.id 
   AND y.seq <= x.seq 
 GROUP 
    BY x.id,x.seq;
+-----+-----+-------+------+
| id  | seq | value | i    |
+-----+-----+-------+------+
| 101 |   1 |  NULL | NULL |
| 101 |   2 |   175 |  175 |
| 101 |   4 |  NULL |  175 |
| 101 |   7 |  NULL |  175 |
| 101 |   9 |   180 |  180 |
| 101 |  11 |  NULL |  180 |
| 102 |   2 |  NULL | NULL |
| 102 |   3 |   175 |  175 |
| 102 |   4 |  NULL |  175 |
| 102 |   7 |  NULL |  175 |
| 102 |   9 |   200 |  200 |
| 102 |  12 |  NULL |  200 |
+-----+-----+-------+------+

答案 2 :(得分:0)

这与Strawberry的答案类似,但适用于奖金值的上升和下降:

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(id INT NOT NULL
,seq INT NOT NULL
,value INT NULL
,PRIMARY KEY(id,seq)
);

INSERT INTO my_table VALUES
(101, 1,NULL),
(101, 2,175),
(101, 4,NULL),
(101, 7,NULL),
(101, 9,180),
(101,11,NULL),
(102, 2,NULL),
(102, 3,175),
(102, 4,NULL),
(102, 7,NULL),
(102, 9,150),
(102,12,NULL);

SELECT
    x.*,
    (SELECT value FROM my_table
        WHERE id = x.id
        AND seq = MAX(y.seq)) filled
FROM my_table x
LEFT JOIN my_table y
    ON y.id = x.id
    AND y.seq <= x.seq
    AND y.value IS NOT NULL
GROUP BY
    x.id, x.seq

结果:

+-----+-----+-------+------+
| id  | seq | value | i    |
+-----+-----+-------+------+
| 101 |   1 |  NULL | NULL |
| 101 |   2 |   175 |  175 |
| 101 |   4 |  NULL |  175 |
| 101 |   7 |  NULL |  175 |
| 101 |   9 |   180 |  180 |
| 101 |  11 |  NULL |  180 |
| 102 |   2 |  NULL | NULL |
| 102 |   3 |   175 |  175 |
| 102 |   4 |  NULL |  175 |
| 102 |   7 |  NULL |  175 |
| 102 |   9 |   150 |  150 |
| 102 |  12 |  NULL |  150 |
+-----+-----+-------+------+

工作原理:

  1. 自我联接通过y.seq <= x.seqy.value IS NOT NULL表达式将具有相同ID的所有非空前行添加到每个原始行
  2. GROUP BY x.id, x.seq子句允许我们通过MAX(y.seq)选择最高的前序号
  3. 选择列表子查询查找同一id组中最直接的非空前一行的值