库存数量如何写SQL需要根据之前的订单计算
How to write SQL for stock quantity that requires calculation from previous orders
我有两个 table,一个用于当前产品总库存,一个用于产品订单。
STOCK_TB
PRODUCT_ID STOCK_QTY
A 20
B 15
C 10
ORDER_TB
ORDER_DATE PRODUCT_ID ORDER QTY
2015-03-01 A 5
2015-03-02 A 3
2015-03-02 B 4
2015-03-03 C 1
2015-03-04 C 3
我想要 select 月度库存数量报告的数据,如下所示。假设报表是在 3 月 5 日生成的
Stock Quantity of March:
Daily Stock Qty
Product ID 1 2 3 4 5 6 7 ... 28 29 30 31
A 23 20 20 20 20 0 0 0 0 0 0
B 19 15 15 15 15 0 0 0 0 0 0
C 14 14 13 10 10 0 0 0 0 0 0
往期库存数量以收盘日为准(即:以上3月2日指3月2日23:59:99.999)
超出当前日期的任何日期的数量都将为 0
我们没有 table 来保留每日库存,只有当前库存。所以这意味着要获取以前日期的库存,我必须向后添加产品订单量。
如何编写此类查询?对于日期列,我可以将它们固定在 1 到 31 之间,因为我可以根据应用程序中的月份隐藏未使用的日期。但我不太确定如何在 SQL 中编写逻辑,以便在以前的日期向当前库存添加订单数量。
6天查询示例(其他25天相同:-)
DECLARE @FirstOfMonth AS DATETIME = DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
SELECT
CASE WHEN DAY(GETDATE()) < 1 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 0, @FirstOfMonth)), 0) END _1,
CASE WHEN DAY(GETDATE()) < 2 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 1, @FirstOfMonth)), 0) END _2,
CASE WHEN DAY(GETDATE()) < 3 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 2, @FirstOfMonth)), 0) END _3,
CASE WHEN DAY(GETDATE()) < 4 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 3, @FirstOfMonth)), 0) END _4,
CASE WHEN DAY(GETDATE()) < 5 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 4, @FirstOfMonth)), 0) END _5,
CASE WHEN DAY(GETDATE()) < 6 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 5, @FirstOfMonth)), 0) END _6
FROM STOCK_TB S
请注意,我使用的是 > DATEADD
而不是 >= DATEADD
,但我不太确定...您在本月第一天下的订单是什么时候计算的?
第二种解决方案,但我认为复杂性不会有太大变化:
DECLARE @FirstOfMonth AS DATETIME = DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
DECLARE @Today AS DATETIME = DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0)
;WITH Days(d, dat) AS
(
SELECT 1, @FirstOfMonth
UNION ALL
SELECT d+1, DATEADD(day, 1, dat) FROM Days WHERE d < DATEPART(day, @today)
)
, Work1 AS (
SELECT PRODUCT_ID, STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > dat), 0) STOCK_TB, d FROM STOCK_TB S, Days
)
SELECT PRODUCT_ID,
ISNULL(MAX(CASE WHEN d = 1 THEN STOCK_TB END), 0) _1,
ISNULL(MAX(CASE WHEN d = 2 THEN STOCK_TB END), 0) _2,
ISNULL(MAX(CASE WHEN d = 3 THEN STOCK_TB END), 0) _3,
ISNULL(MAX(CASE WHEN d = 4 THEN STOCK_TB END), 0) _4,
ISNULL(MAX(CASE WHEN d = 5 THEN STOCK_TB END), 0) _5,
ISNULL(MAX(CASE WHEN d = 6 THEN STOCK_TB END), 0) _6,
ISNULL(MAX(CASE WHEN d = 7 THEN STOCK_TB END), 0) _7,
ISNULL(MAX(CASE WHEN d = 8 THEN STOCK_TB END), 0) _8
FROM Work1 GROUP BY PRODUCT_ID
在这里,我使用花哨的递归查询来构建一个 table 天 1...(today)
,然后我构建一个 Work1
中间体,其中包含每天的所有库存数量(所以 x products * y days 行),然后我将它们分组
第三种可能性:双重递归查询(一种计算数字 1...31,另一种计算 运行 总数),加上最后的 GROUP BY
与前面的示例几乎相同。
DECLARE @FirstOfMonth AS DATETIME = DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
DECLARE @Today AS DATETIME = DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0)
;WITH Days(d, dat) AS
(
SELECT DATEPART(day, @Today), @Today dat
UNION ALL
SELECT d-1, DATEADD(day, -1, dat) dat
FROM Days
WHERE d > 1
)
# Product Days x STOCK_TB with a LEFT JOIN on ORDER_TB.
, Work1 AS (
SELECT S.PRODUCT_ID, d, dat, S.STOCK_QTY, ISNULL(O.ORDER_QTY, 0) ORDER_QTY
FROM Days
CROSS JOIN STOCK_TB S # Full cartesian product, JOIN without conditions
LEFT JOIN ORDER_TB O ON dat = O.ORDER_DATE AND S.PRODUCT_ID = O.PRODUCT_ID
)
# Second recursive query to do the running total
, Days2(PRODUCT_ID, d, dat, STOCK_QTY) AS
(
SELECT PRODUCT_ID, d, dat, STOCK_QTY
FROM Work1
WHERE d = DATEPART(day, @Today)
UNION ALL
SELECT d.PRODUCT_ID, d.d - 1, w.dat, d.STOCK_QTY + w.ORDER_QTY
FROM Days2 d
INNER JOIN Work1 w ON d.PRODUCT_ID = w.PRODUCT_ID AND d.d /* - 1 */ = w.d
WHERE d.d > 1
)
SELECT PRODUCT_ID,
ISNULL(MAX(CASE WHEN d = 1 THEN STOCK_QTY END), 0) _1,
ISNULL(MAX(CASE WHEN d = 2 THEN STOCK_QTY END), 0) _2,
ISNULL(MAX(CASE WHEN d = 3 THEN STOCK_QTY END), 0) _3,
ISNULL(MAX(CASE WHEN d = 4 THEN STOCK_QTY END), 0) _4,
ISNULL(MAX(CASE WHEN d = 5 THEN STOCK_QTY END), 0) _5,
ISNULL(MAX(CASE WHEN d = 6 THEN STOCK_QTY END), 0) _6,
ISNULL(MAX(CASE WHEN d = 7 THEN STOCK_QTY END), 0) _7,
ISNULL(MAX(CASE WHEN d = 8 THEN STOCK_QTY END), 0) _8
FROM Days2 GROUP BY PRODUCT_ID
注意 /* - 1 */
注释部分。取消注释,您可以控制每月第一天的值的使用方式。
我有两个 table,一个用于当前产品总库存,一个用于产品订单。
STOCK_TB
PRODUCT_ID STOCK_QTY
A 20
B 15
C 10
ORDER_TB
ORDER_DATE PRODUCT_ID ORDER QTY
2015-03-01 A 5
2015-03-02 A 3
2015-03-02 B 4
2015-03-03 C 1
2015-03-04 C 3
我想要 select 月度库存数量报告的数据,如下所示。假设报表是在 3 月 5 日生成的
Stock Quantity of March:
Daily Stock Qty
Product ID 1 2 3 4 5 6 7 ... 28 29 30 31
A 23 20 20 20 20 0 0 0 0 0 0
B 19 15 15 15 15 0 0 0 0 0 0
C 14 14 13 10 10 0 0 0 0 0 0
往期库存数量以收盘日为准(即:以上3月2日指3月2日23:59:99.999)
超出当前日期的任何日期的数量都将为 0
我们没有 table 来保留每日库存,只有当前库存。所以这意味着要获取以前日期的库存,我必须向后添加产品订单量。
如何编写此类查询?对于日期列,我可以将它们固定在 1 到 31 之间,因为我可以根据应用程序中的月份隐藏未使用的日期。但我不太确定如何在 SQL 中编写逻辑,以便在以前的日期向当前库存添加订单数量。
6天查询示例(其他25天相同:-)
DECLARE @FirstOfMonth AS DATETIME = DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
SELECT
CASE WHEN DAY(GETDATE()) < 1 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 0, @FirstOfMonth)), 0) END _1,
CASE WHEN DAY(GETDATE()) < 2 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 1, @FirstOfMonth)), 0) END _2,
CASE WHEN DAY(GETDATE()) < 3 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 2, @FirstOfMonth)), 0) END _3,
CASE WHEN DAY(GETDATE()) < 4 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 3, @FirstOfMonth)), 0) END _4,
CASE WHEN DAY(GETDATE()) < 5 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 4, @FirstOfMonth)), 0) END _5,
CASE WHEN DAY(GETDATE()) < 6 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 5, @FirstOfMonth)), 0) END _6
FROM STOCK_TB S
请注意,我使用的是 > DATEADD
而不是 >= DATEADD
,但我不太确定...您在本月第一天下的订单是什么时候计算的?
第二种解决方案,但我认为复杂性不会有太大变化:
DECLARE @FirstOfMonth AS DATETIME = DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
DECLARE @Today AS DATETIME = DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0)
;WITH Days(d, dat) AS
(
SELECT 1, @FirstOfMonth
UNION ALL
SELECT d+1, DATEADD(day, 1, dat) FROM Days WHERE d < DATEPART(day, @today)
)
, Work1 AS (
SELECT PRODUCT_ID, STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > dat), 0) STOCK_TB, d FROM STOCK_TB S, Days
)
SELECT PRODUCT_ID,
ISNULL(MAX(CASE WHEN d = 1 THEN STOCK_TB END), 0) _1,
ISNULL(MAX(CASE WHEN d = 2 THEN STOCK_TB END), 0) _2,
ISNULL(MAX(CASE WHEN d = 3 THEN STOCK_TB END), 0) _3,
ISNULL(MAX(CASE WHEN d = 4 THEN STOCK_TB END), 0) _4,
ISNULL(MAX(CASE WHEN d = 5 THEN STOCK_TB END), 0) _5,
ISNULL(MAX(CASE WHEN d = 6 THEN STOCK_TB END), 0) _6,
ISNULL(MAX(CASE WHEN d = 7 THEN STOCK_TB END), 0) _7,
ISNULL(MAX(CASE WHEN d = 8 THEN STOCK_TB END), 0) _8
FROM Work1 GROUP BY PRODUCT_ID
在这里,我使用花哨的递归查询来构建一个 table 天 1...(today)
,然后我构建一个 Work1
中间体,其中包含每天的所有库存数量(所以 x products * y days 行),然后我将它们分组
第三种可能性:双重递归查询(一种计算数字 1...31,另一种计算 运行 总数),加上最后的 GROUP BY
与前面的示例几乎相同。
DECLARE @FirstOfMonth AS DATETIME = DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
DECLARE @Today AS DATETIME = DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0)
;WITH Days(d, dat) AS
(
SELECT DATEPART(day, @Today), @Today dat
UNION ALL
SELECT d-1, DATEADD(day, -1, dat) dat
FROM Days
WHERE d > 1
)
# Product Days x STOCK_TB with a LEFT JOIN on ORDER_TB.
, Work1 AS (
SELECT S.PRODUCT_ID, d, dat, S.STOCK_QTY, ISNULL(O.ORDER_QTY, 0) ORDER_QTY
FROM Days
CROSS JOIN STOCK_TB S # Full cartesian product, JOIN without conditions
LEFT JOIN ORDER_TB O ON dat = O.ORDER_DATE AND S.PRODUCT_ID = O.PRODUCT_ID
)
# Second recursive query to do the running total
, Days2(PRODUCT_ID, d, dat, STOCK_QTY) AS
(
SELECT PRODUCT_ID, d, dat, STOCK_QTY
FROM Work1
WHERE d = DATEPART(day, @Today)
UNION ALL
SELECT d.PRODUCT_ID, d.d - 1, w.dat, d.STOCK_QTY + w.ORDER_QTY
FROM Days2 d
INNER JOIN Work1 w ON d.PRODUCT_ID = w.PRODUCT_ID AND d.d /* - 1 */ = w.d
WHERE d.d > 1
)
SELECT PRODUCT_ID,
ISNULL(MAX(CASE WHEN d = 1 THEN STOCK_QTY END), 0) _1,
ISNULL(MAX(CASE WHEN d = 2 THEN STOCK_QTY END), 0) _2,
ISNULL(MAX(CASE WHEN d = 3 THEN STOCK_QTY END), 0) _3,
ISNULL(MAX(CASE WHEN d = 4 THEN STOCK_QTY END), 0) _4,
ISNULL(MAX(CASE WHEN d = 5 THEN STOCK_QTY END), 0) _5,
ISNULL(MAX(CASE WHEN d = 6 THEN STOCK_QTY END), 0) _6,
ISNULL(MAX(CASE WHEN d = 7 THEN STOCK_QTY END), 0) _7,
ISNULL(MAX(CASE WHEN d = 8 THEN STOCK_QTY END), 0) _8
FROM Days2 GROUP BY PRODUCT_ID
注意 /* - 1 */
注释部分。取消注释,您可以控制每月第一天的值的使用方式。