来自 Bought/Sold 事务日志的每日库存
Daily Inventory from Bought/Sold transaction log
以下 SQL 查询描述了两个 table 及其内容,是大型库存系统的一小部分和简化部分。
第一个是交易日志,其中列出了各种物品的买卖数量。
CREATE TABLE `Inventar_actions` (
`PartID` char(8) NOT NULL,
`DateSeq` smallint(4) unsigned NOT NULL,
`ActionType` enum('Bought','Sold') NOT NULL,
`Units` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`PartID`,`DateSeq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test`.`Inventar_actions` (`PartID`, `DateSeq`, `ActionType`, `Units`) VALUES
('0001', '1020', 'Bought', '100'),('0001', '1025', 'Sold', '20'),('0001', '1028', 'Sold', '30'),
('0001', '1031', 'Bought', '100'),('0001', '1035', 'Sold', '50');
第二个 table 是一个日历,列出了任意纪元的工作日及其序号:
CREATE TABLE `BusinessDates` (
`DateSeq` int(10) unsigned NOT NULL,
`BusinessDate` date NOT NULL,
PRIMARY KEY (`DateSeq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test`.`BusinessDates` (`DateSeq`, `BusinessDate`) VALUES
('1015', '2020-02-03'),('1016', '2020-02-04'),('1017', '2020-02-05'),('1018', '2020-02-06'),('1019', '2020-02-07'),
('1020', '2020-02-10'),('1021', '2020-02-11'),('1022', '2020-02-12'),('1023', '2020-02-13'),('1024', '2020-02-14'),
('1025', '2020-02-17'),('1026', '2020-02-18'),('1027', '2020-02-19'),('1028', '2020-02-20'),('1029', '2020-02-21'),
('1030', '2020-02-24'),('1031', '2020-02-25'),('1032', '2020-02-26'),('1033', '2020-02-27'),('1034', '2020-02-28'),
('1035', '2020-03-02'),('1036', '2020-03-03'),('1037', '2020-03-04'),('1038', '2020-03-05'),('1039', '2020-03-06')
;
我需要的是每日库存,看起来像这样:
| 1020 | 2020-02-10 | 100 | Bought | 100 |
| 1021 | 2020-02-11 | | | 100 |
| 1022 | 2020-02-12 | | | 100 |
| 1023 | 2020-02-13 | | | 100 |
| 1024 | 2020-02-14 | | | 100 |
| 1025 | 2020-02-17 | 20 | Sold | 80 |
| 1026 | 2020-02-18 | | | 80 |
| 1027 | 2020-02-19 | | | 80 |
| 1028 | 2020-02-20 | 30 | Sold | 50 |
| 1029 | 2020-02-21 | | | 50 |
| 1030 | 2020-02-24 | | | 50 |
| 1031 | 2020-02-25 | 100 | Bought | 150 |
| 1032 | 2020-02-26 | | | 150 |
| 1033 | 2020-02-27 | | | 150 |
| 1034 | 2020-02-28 | | | 150 |
| 1035 | 2020-03-02 | 50 | Sold | 100 |
| 1036 | 2020-03-03 | | | 100 |
| 1037 | 2020-03-04 | | | 100 |
| 1038 | 2020-03-05 | | | 100 |
| 1039 | 2020-03-06 | | | 100 |
也就是说,对于每个业务日期,每个 PartID 的余额是多少,给定零件买卖。
我使用以下查询来排列日期、日期序列和交易:
SELECT d.DateSeq, d.BusinessDate, a.`Units`, a.`ActionType`
FROM `BusinessDates` AS d LEFT JOIN
(SELECT DateSeq, ActionType, Units FROM `Inventar_actions` WHERE PartID = '0001') AS a USING (DateSeq)
WHERE d.DateSeq BETWEEN 1020 AND 1039
ORDER BY d.DateSeq;
这将生成所需输出的前四列。
遗憾的是,我找不到同时生成最后一列(零件余额库存)的查询。
请注意,有 很多 个 PartID 和数千个工作日。
请帮忙...
这适用于 mysql 5.x 和 8.0
CREATE TABLE `Inventar_actions` (
`PartID` char(8) NOT NULL,
`DateSeq` smallint(4) unsigned NOT NULL,
`ActionType` enum('Bought','Sold') NOT NULL,
`Units` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`PartID`,`DateSeq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `Inventar_actions` (`PartID`, `DateSeq`, `ActionType`, `Units`) VALUES
('0001', '1020', 'Bought', '100'),('0001', '1025', 'Sold', '20'),('0001', '1028', 'Sold', '30'),
('0001', '1031', 'Bought', '100'),('0001', '1035', 'Sold', '50');
✓
✓
CREATE TABLE `BusinessDates` (
`DateSeq` int(10) unsigned NOT NULL,
`BusinessDate` date NOT NULL,
PRIMARY KEY (`DateSeq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `BusinessDates` (`DateSeq`, `BusinessDate`) VALUES
('1015', '2020-02-03'),('1016', '2020-02-04'),('1017', '2020-02-05'),('1018', '2020-02-06'),('1019', '2020-02-07'),
('1020', '2020-02-10'),('1021', '2020-02-11'),('1022', '2020-02-12'),('1023', '2020-02-13'),('1024', '2020-02-14'),
('1025', '2020-02-17'),('1026', '2020-02-18'),('1027', '2020-02-19'),('1028', '2020-02-20'),('1029', '2020-02-21'),
('1030', '2020-02-24'),('1031', '2020-02-25'),('1032', '2020-02-26'),('1033', '2020-02-27'),('1034', '2020-02-28'),
('1035', '2020-03-02'),('1036', '2020-03-03'),('1037', '2020-03-04'),('1038', '2020-03-05'),('1039', '2020-03-06')
;
✓
✓
SELECT
d.DateSeq
, d.BusinessDate
, a.`Units`
, a.`ActionType`
,
CASE
WHEN a.`ActionType` = 'Bought' THEN @inventory := @inventory + a.`Units`
WHEN a.`ActionType` = 'Sold' THEN @inventory := @inventory - a.`Units`
ELSE
@inventory := @inventory
END inventory
FROM (SELECT * FROM `BusinessDates` ORDER BY BusinessDate ASC) AS d LEFT JOIN
(SELECT DateSeq, ActionType, Units FROM `Inventar_actions` WHERE PartID = '0001') AS a USING (DateSeq)
,(SELECT @inventory := 0) b
WHERE d.DateSeq BETWEEN 1020 AND 1039
ORDER BY d.DateSeq;
DateSeq | BusinessDate | Units | ActionType | inventory
------: | :----------- | ----: | :--------- | :--------
1020 | 2020-02-10 | 100 | Bought | 100
1021 | 2020-02-11 | null | null | 100
1022 | 2020-02-12 | null | null | 100
1023 | 2020-02-13 | null | null | 100
1024 | 2020-02-14 | null | null | 100
1025 | 2020-02-17 | 20 | Sold | 80
1026 | 2020-02-18 | null | null | 80
1027 | 2020-02-19 | null | null | 80
1028 | 2020-02-20 | 30 | Sold | 50
1029 | 2020-02-21 | null | null | 50
1030 | 2020-02-24 | null | null | 50
1031 | 2020-02-25 | 100 | Bought | 150
1032 | 2020-02-26 | null | null | 150
1033 | 2020-02-27 | null | null | 150
1034 | 2020-02-28 | null | null | 150
1035 | 2020-03-02 | 50 | Sold | 100
1036 | 2020-03-03 | null | null | 100
1037 | 2020-03-04 | null | null | 100
1038 | 2020-03-05 | null | null | 100
1039 | 2020-03-06 | null | null | 100
db<>fiddle here
以下 SQL 查询描述了两个 table 及其内容,是大型库存系统的一小部分和简化部分。
第一个是交易日志,其中列出了各种物品的买卖数量。
CREATE TABLE `Inventar_actions` (
`PartID` char(8) NOT NULL,
`DateSeq` smallint(4) unsigned NOT NULL,
`ActionType` enum('Bought','Sold') NOT NULL,
`Units` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`PartID`,`DateSeq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test`.`Inventar_actions` (`PartID`, `DateSeq`, `ActionType`, `Units`) VALUES
('0001', '1020', 'Bought', '100'),('0001', '1025', 'Sold', '20'),('0001', '1028', 'Sold', '30'),
('0001', '1031', 'Bought', '100'),('0001', '1035', 'Sold', '50');
第二个 table 是一个日历,列出了任意纪元的工作日及其序号:
CREATE TABLE `BusinessDates` (
`DateSeq` int(10) unsigned NOT NULL,
`BusinessDate` date NOT NULL,
PRIMARY KEY (`DateSeq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test`.`BusinessDates` (`DateSeq`, `BusinessDate`) VALUES
('1015', '2020-02-03'),('1016', '2020-02-04'),('1017', '2020-02-05'),('1018', '2020-02-06'),('1019', '2020-02-07'),
('1020', '2020-02-10'),('1021', '2020-02-11'),('1022', '2020-02-12'),('1023', '2020-02-13'),('1024', '2020-02-14'),
('1025', '2020-02-17'),('1026', '2020-02-18'),('1027', '2020-02-19'),('1028', '2020-02-20'),('1029', '2020-02-21'),
('1030', '2020-02-24'),('1031', '2020-02-25'),('1032', '2020-02-26'),('1033', '2020-02-27'),('1034', '2020-02-28'),
('1035', '2020-03-02'),('1036', '2020-03-03'),('1037', '2020-03-04'),('1038', '2020-03-05'),('1039', '2020-03-06')
;
我需要的是每日库存,看起来像这样:
| 1020 | 2020-02-10 | 100 | Bought | 100 |
| 1021 | 2020-02-11 | | | 100 |
| 1022 | 2020-02-12 | | | 100 |
| 1023 | 2020-02-13 | | | 100 |
| 1024 | 2020-02-14 | | | 100 |
| 1025 | 2020-02-17 | 20 | Sold | 80 |
| 1026 | 2020-02-18 | | | 80 |
| 1027 | 2020-02-19 | | | 80 |
| 1028 | 2020-02-20 | 30 | Sold | 50 |
| 1029 | 2020-02-21 | | | 50 |
| 1030 | 2020-02-24 | | | 50 |
| 1031 | 2020-02-25 | 100 | Bought | 150 |
| 1032 | 2020-02-26 | | | 150 |
| 1033 | 2020-02-27 | | | 150 |
| 1034 | 2020-02-28 | | | 150 |
| 1035 | 2020-03-02 | 50 | Sold | 100 |
| 1036 | 2020-03-03 | | | 100 |
| 1037 | 2020-03-04 | | | 100 |
| 1038 | 2020-03-05 | | | 100 |
| 1039 | 2020-03-06 | | | 100 |
也就是说,对于每个业务日期,每个 PartID 的余额是多少,给定零件买卖。
我使用以下查询来排列日期、日期序列和交易:
SELECT d.DateSeq, d.BusinessDate, a.`Units`, a.`ActionType`
FROM `BusinessDates` AS d LEFT JOIN
(SELECT DateSeq, ActionType, Units FROM `Inventar_actions` WHERE PartID = '0001') AS a USING (DateSeq)
WHERE d.DateSeq BETWEEN 1020 AND 1039
ORDER BY d.DateSeq;
这将生成所需输出的前四列。
遗憾的是,我找不到同时生成最后一列(零件余额库存)的查询。
请注意,有 很多 个 PartID 和数千个工作日。
请帮忙...
这适用于 mysql 5.x 和 8.0
CREATE TABLE `Inventar_actions` ( `PartID` char(8) NOT NULL, `DateSeq` smallint(4) unsigned NOT NULL, `ActionType` enum('Bought','Sold') NOT NULL, `Units` bigint(20) unsigned NOT NULL, PRIMARY KEY (`PartID`,`DateSeq`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `Inventar_actions` (`PartID`, `DateSeq`, `ActionType`, `Units`) VALUES ('0001', '1020', 'Bought', '100'),('0001', '1025', 'Sold', '20'),('0001', '1028', 'Sold', '30'), ('0001', '1031', 'Bought', '100'),('0001', '1035', 'Sold', '50');
✓ ✓
CREATE TABLE `BusinessDates` ( `DateSeq` int(10) unsigned NOT NULL, `BusinessDate` date NOT NULL, PRIMARY KEY (`DateSeq`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `BusinessDates` (`DateSeq`, `BusinessDate`) VALUES ('1015', '2020-02-03'),('1016', '2020-02-04'),('1017', '2020-02-05'),('1018', '2020-02-06'),('1019', '2020-02-07'), ('1020', '2020-02-10'),('1021', '2020-02-11'),('1022', '2020-02-12'),('1023', '2020-02-13'),('1024', '2020-02-14'), ('1025', '2020-02-17'),('1026', '2020-02-18'),('1027', '2020-02-19'),('1028', '2020-02-20'),('1029', '2020-02-21'), ('1030', '2020-02-24'),('1031', '2020-02-25'),('1032', '2020-02-26'),('1033', '2020-02-27'),('1034', '2020-02-28'), ('1035', '2020-03-02'),('1036', '2020-03-03'),('1037', '2020-03-04'),('1038', '2020-03-05'),('1039', '2020-03-06') ;
✓ ✓
SELECT d.DateSeq , d.BusinessDate , a.`Units` , a.`ActionType` , CASE WHEN a.`ActionType` = 'Bought' THEN @inventory := @inventory + a.`Units` WHEN a.`ActionType` = 'Sold' THEN @inventory := @inventory - a.`Units` ELSE @inventory := @inventory END inventory FROM (SELECT * FROM `BusinessDates` ORDER BY BusinessDate ASC) AS d LEFT JOIN (SELECT DateSeq, ActionType, Units FROM `Inventar_actions` WHERE PartID = '0001') AS a USING (DateSeq) ,(SELECT @inventory := 0) b WHERE d.DateSeq BETWEEN 1020 AND 1039 ORDER BY d.DateSeq;
DateSeq | BusinessDate | Units | ActionType | inventory ------: | :----------- | ----: | :--------- | :-------- 1020 | 2020-02-10 | 100 | Bought | 100 1021 | 2020-02-11 | null | null | 100 1022 | 2020-02-12 | null | null | 100 1023 | 2020-02-13 | null | null | 100 1024 | 2020-02-14 | null | null | 100 1025 | 2020-02-17 | 20 | Sold | 80 1026 | 2020-02-18 | null | null | 80 1027 | 2020-02-19 | null | null | 80 1028 | 2020-02-20 | 30 | Sold | 50 1029 | 2020-02-21 | null | null | 50 1030 | 2020-02-24 | null | null | 50 1031 | 2020-02-25 | 100 | Bought | 150 1032 | 2020-02-26 | null | null | 150 1033 | 2020-02-27 | null | null | 150 1034 | 2020-02-28 | null | null | 150 1035 | 2020-03-02 | 50 | Sold | 100 1036 | 2020-03-03 | null | null | 100 1037 | 2020-03-04 | null | null | 100 1038 | 2020-03-05 | null | null | 100 1039 | 2020-03-06 | null | null | 100
db<>fiddle here