产品数量按条件扣款
Product Quantity Deduction On Condition
我需要根据条件扣除产品数量。看起来有点复杂,不确定如何使用 sql 查询来完成。这是它的概念:这里的 Product 是指原始 material。出于生产目的,我们必须从库存中扣除原始 materials。遵循的规则很少:
Table - 产品条目:
i) 产品是使用 PO(采购订单)和发票编号从供应商处购买的。在这种情况下有一个条件。假设购买了100件商品id为1001的商品,分为以下两部分:
Id - ProductId - PO - Invoice no - Quantity - Price - EntryDate
1st section: 1 - 1001 - PO-102 - Inv-122 - 20 - 200 - 2017-07-10 10:00:00
2nd section: 2 - 1001 - PO-102 - Inv-122 - 80 - 800 - 2017-07-10 11:00:00
3 - 1002 - PO-102 - Inv-122 - 20 - 400 - 2017-07-10 10:00:00
游戏从这里开始。在许多情况下,原始 material 或产品可能一次分成多个部分或全部,我的意思是假设总共有 100 件。
ii) 现在购买了,还要进店,还有一个流程。每个购买的产品都应收到一个单独的 IP(进口许可证)号码,如下所示:
Table - IpEntry:
Id - ProductId - Invoice no - IP - AnotherProductId
1 - 1001 - Inv-122 - IP2244 - 2
2 - 1001 - Inv-122 - IP2244 - 2
3 - 1002 - Inv-122 - IP2244 - 4
iii) 收到产品后,应用于生产目的,即会有消费。在消费中,应使用第一个输入的产品或原始material。这意味着,如果必须扣除产品 ID 1001,则应根据“EntryDate”扣除第一个输入的产品,因为它已在最小时间输入。时间 10:00:00 在同一天。所以对于扣除或消耗,应该发生以下情况:
Table - 消费:
Id - 消费编号 - AnotherProductId - 数量
1 - Con-122 - 2 - 10
3 - Con-122 - 4 - 10
因此最终输出将如下所示:
Id - AnotherProductId - Stock - Quantity Used - Remaining Balance
1 - 2 - 10 - 10 - 100
2 - 4 - 10 - 10 - 200
我不会在这里分享 sql 查询,因为它使用 INNER JOIN
和 MIN
函数应该不够准确和简单,returns 以下内容:
Id - AnotherProductId - Stock - Quantity Used - Remaining Balance
1 - 2 - 10 - 10 - 100
2 - 2 - 10 - 10 - 100 //It returns **AnotherProductId or ProductId - 1001 or 2** twice as it should only return once
3 - 4 - 10 - 10 - 200
我不确定如何处理上述情况,特别是相同产品但数量不同并且有点混乱。
为了更好地理解,这里是脚本:
USE [Demo]
GO
/****** Object: Table [dbo].[ProductEntry] Script Date: 07/19/2017 20:37:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ProductEntry](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ProductId] [int] NULL,
[PO] [nvarchar](60) NULL,
[Invoice No] [nvarchar](60) NULL,
[Quantity] [float] NULL,
[Price] [float] NULL,
[EntryDate] [datetime] NULL,
CONSTRAINT [PK_ProductEntry] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[ProductEntry] ON
INSERT [dbo].[ProductEntry] ([Id], [ProductId], [PO], [Invoice No], [Quantity], [Price], [EntryDate]) VALUES (1, 1001, N'PO-102', N'Inv-122', 20, 200, CAST(0x0000A7AC00A4CB80 AS DateTime))
INSERT [dbo].[ProductEntry] ([Id], [ProductId], [PO], [Invoice No], [Quantity], [Price], [EntryDate]) VALUES (2, 1001, N'PO-102', N'Inv-122', 80, 800, CAST(0x0000A7AC00B54640 AS DateTime))
INSERT [dbo].[ProductEntry] ([Id], [ProductId], [PO], [Invoice No], [Quantity], [Price], [EntryDate]) VALUES (3, 1002, N'PO-102', N'Inv-122', 20, 400, CAST(0x0000A7AC00A4CB80 AS DateTime))
SET IDENTITY_INSERT [dbo].[ProductEntry] OFF
/****** Object: Table [dbo].[IpEntry] Script Date: 07/19/2017 20:37:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[IpEntry](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ProductId] [int] NULL,
[Invoice No] [nvarchar](60) NULL,
[IP] [nvarchar](60) NULL,
[AnotherProductId] [int] NULL,
CONSTRAINT [PK_IpEntry] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[IpEntry] ON
INSERT [dbo].[IpEntry] ([Id], [ProductId], [Invoice No], [IP], [AnotherProductId]) VALUES (1, 1001, N'Inv-122', N'IP2244', 2)
INSERT [dbo].[IpEntry] ([Id], [ProductId], [Invoice No], [IP], [AnotherProductId]) VALUES (2, 1001, N'Inv-122', N'IP2244', 2)
INSERT [dbo].[IpEntry] ([Id], [ProductId], [Invoice No], [IP], [AnotherProductId]) VALUES (3, 1002, N'Inv-122', N'IP2244', 4)
SET IDENTITY_INSERT [dbo].[IpEntry] OFF
/****** Object: Table [dbo].[Consumption] Script Date: 07/19/2017 20:37:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Consumption](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Consumption no] [nvarchar](40) NULL,
[AnotherProductId] [int] NULL,
[Quantity] [float] NULL,
CONSTRAINT [PK_Consumption] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Consumption] ON
INSERT [dbo].[Consumption] ([Id], [Consumption no], [AnotherProductId], [Quantity]) VALUES (1, N'Con-122 ', 2, 10)
INSERT [dbo].[Consumption] ([Id], [Consumption no], [AnotherProductId], [Quantity]) VALUES (2, N'Con-122 ', 4, 10)
SET IDENTITY_INSERT [dbo].[Consumption] OFF
这应该会给您预期的结果。请尝试。
;WITH CTE AS (
select DISTINCT ProductID,AnotherProductId,Balance,
CASE WHEN Balance>=0 THEN 'P' ELSE 'N' END Flag, row_number() over(partition by AnotherProductId order by Balance) RID
FROM (SELECT DISTINCT P.ProductID,I.AnotherProductId,(P.Quantity-C.Quantity) 'Balance'
FROM [ProductEntry] P INNER JOIN [IpEntry] I ON I.ProductID=P.ProductId
INNER JOIN (SELECT [AnotherProductId],SUM([Quantity]) [Quantity] FROM [Consumption] GROUP BY [AnotherProductId]) C ON C.AnotherProductId=I.AnotherProductId
)A
)
select T.AnotherProductId,Balance as Stock, C.Quantity as 'Quantity Used',MIN((P.Price *(P.Quantity-C.Quantity)/P.Quantity)) 'Remaining Balance'
FROM [ProductEntry] P INNER JOIN CTE T ON T.ProductID=P.ProductId AND (RID=1 OR Flag='N')
INNER JOIN (SELECT DISTINCT ProductId,AnotherProductId FROM [IpEntry]) I ON I.ProductID=P.ProductId
INNER JOIN (SELECT [AnotherProductId],SUM([Quantity]) [Quantity] FROM [Consumption] GROUP BY [AnotherProductId]) C ON C.AnotherProductId=I.AnotherProductId
GROUP BY T.AnotherProductId,Balance, C.Quantity
预计涵盖所有场景。
SELECT DISTINCT P.ProductID,P.Quantity,-1 Flag,C.[Quantity] Balance
INTO #TMP
FROM [ProductEntry] P
INNER JOIN [IpEntry] I ON I.ProductID=P.ProductId
INNER JOIN (SELECT [AnotherProductId],SUM([Quantity]) [Quantity] FROM [Consumption] GROUP BY [AnotherProductId])C ON C.AnotherProductId=I.AnotherProductId
DECLARE @Counter INT=1
WHILE((SELECT TOP 1 1 FROM #TMP WHERE Flag=-1 )=1)
BEGIN
UPDATE T SET T.Balance = T.Balance-T.Quantity,
T.Quantity = CASE WHEN T.Quantity-T.Balance>=0 THEN T.Quantity-T.Balance ELSE 0 END,
T.Flag = CASE WHEN T.Quantity-T.Balance>=0 THEN 0 ELSE 1 END
FROM (SELECT ProductId,Quantity,row_number() over (partition by ProductId order by Quantity)RID FROM [ProductEntry])P
INNER JOIN [IpEntry] I ON I.ProductID=P.ProductId and P.RID=@Counter
INNER JOIN (SELECT ProductId,Quantity,Flag,Balance,row_number() over (partition by ProductId order by Quantity)RID FROM #TMP ) T ON T.ProductID=P.ProductID and T.RID=@Counter
INNER JOIN (SELECT [AnotherProductId],SUM([Quantity]) [Quantity] FROM [Consumption] GROUP BY [AnotherProductId])C ON C.AnotherProductId=I.AnotherProductId
UPDATE T1 SET Balance=T2.Balance
FROM #TMP T1 INNER JOIN #TMP T2 ON T1.ProductId=T2.ProductId
WHERE T2.Flag IN (0,1)
UPDATE T1 SET Flag= (SELECT T2.Flag FROM #TMP T2 WHERE T1.ProductId=T2.ProductId AND T2.Flag=0)
FROM #TMP T1
WHERE Flag=0
SET @Counter=@Counter+1
SELECT * FROM #TMP
END
SELECT ProductId,Quantity FROM #TMP --You can add more details by joining with other tables as per your requirement
drop table #TMP
我需要根据条件扣除产品数量。看起来有点复杂,不确定如何使用 sql 查询来完成。这是它的概念:这里的 Product 是指原始 material。出于生产目的,我们必须从库存中扣除原始 materials。遵循的规则很少:
Table - 产品条目:
i) 产品是使用 PO(采购订单)和发票编号从供应商处购买的。在这种情况下有一个条件。假设购买了100件商品id为1001的商品,分为以下两部分:
Id - ProductId - PO - Invoice no - Quantity - Price - EntryDate
1st section: 1 - 1001 - PO-102 - Inv-122 - 20 - 200 - 2017-07-10 10:00:00
2nd section: 2 - 1001 - PO-102 - Inv-122 - 80 - 800 - 2017-07-10 11:00:00
3 - 1002 - PO-102 - Inv-122 - 20 - 400 - 2017-07-10 10:00:00
游戏从这里开始。在许多情况下,原始 material 或产品可能一次分成多个部分或全部,我的意思是假设总共有 100 件。
ii) 现在购买了,还要进店,还有一个流程。每个购买的产品都应收到一个单独的 IP(进口许可证)号码,如下所示:
Table - IpEntry:
Id - ProductId - Invoice no - IP - AnotherProductId
1 - 1001 - Inv-122 - IP2244 - 2
2 - 1001 - Inv-122 - IP2244 - 2
3 - 1002 - Inv-122 - IP2244 - 4
iii) 收到产品后,应用于生产目的,即会有消费。在消费中,应使用第一个输入的产品或原始material。这意味着,如果必须扣除产品 ID 1001,则应根据“EntryDate”扣除第一个输入的产品,因为它已在最小时间输入。时间 10:00:00 在同一天。所以对于扣除或消耗,应该发生以下情况:
Table - 消费:
Id - 消费编号 - AnotherProductId - 数量
1 - Con-122 - 2 - 10
3 - Con-122 - 4 - 10
因此最终输出将如下所示:
Id - AnotherProductId - Stock - Quantity Used - Remaining Balance
1 - 2 - 10 - 10 - 100
2 - 4 - 10 - 10 - 200
我不会在这里分享 sql 查询,因为它使用 INNER JOIN
和 MIN
函数应该不够准确和简单,returns 以下内容:
Id - AnotherProductId - Stock - Quantity Used - Remaining Balance
1 - 2 - 10 - 10 - 100
2 - 2 - 10 - 10 - 100 //It returns **AnotherProductId or ProductId - 1001 or 2** twice as it should only return once
3 - 4 - 10 - 10 - 200
我不确定如何处理上述情况,特别是相同产品但数量不同并且有点混乱。
为了更好地理解,这里是脚本:
USE [Demo]
GO
/****** Object: Table [dbo].[ProductEntry] Script Date: 07/19/2017 20:37:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ProductEntry](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ProductId] [int] NULL,
[PO] [nvarchar](60) NULL,
[Invoice No] [nvarchar](60) NULL,
[Quantity] [float] NULL,
[Price] [float] NULL,
[EntryDate] [datetime] NULL,
CONSTRAINT [PK_ProductEntry] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[ProductEntry] ON
INSERT [dbo].[ProductEntry] ([Id], [ProductId], [PO], [Invoice No], [Quantity], [Price], [EntryDate]) VALUES (1, 1001, N'PO-102', N'Inv-122', 20, 200, CAST(0x0000A7AC00A4CB80 AS DateTime))
INSERT [dbo].[ProductEntry] ([Id], [ProductId], [PO], [Invoice No], [Quantity], [Price], [EntryDate]) VALUES (2, 1001, N'PO-102', N'Inv-122', 80, 800, CAST(0x0000A7AC00B54640 AS DateTime))
INSERT [dbo].[ProductEntry] ([Id], [ProductId], [PO], [Invoice No], [Quantity], [Price], [EntryDate]) VALUES (3, 1002, N'PO-102', N'Inv-122', 20, 400, CAST(0x0000A7AC00A4CB80 AS DateTime))
SET IDENTITY_INSERT [dbo].[ProductEntry] OFF
/****** Object: Table [dbo].[IpEntry] Script Date: 07/19/2017 20:37:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[IpEntry](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ProductId] [int] NULL,
[Invoice No] [nvarchar](60) NULL,
[IP] [nvarchar](60) NULL,
[AnotherProductId] [int] NULL,
CONSTRAINT [PK_IpEntry] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[IpEntry] ON
INSERT [dbo].[IpEntry] ([Id], [ProductId], [Invoice No], [IP], [AnotherProductId]) VALUES (1, 1001, N'Inv-122', N'IP2244', 2)
INSERT [dbo].[IpEntry] ([Id], [ProductId], [Invoice No], [IP], [AnotherProductId]) VALUES (2, 1001, N'Inv-122', N'IP2244', 2)
INSERT [dbo].[IpEntry] ([Id], [ProductId], [Invoice No], [IP], [AnotherProductId]) VALUES (3, 1002, N'Inv-122', N'IP2244', 4)
SET IDENTITY_INSERT [dbo].[IpEntry] OFF
/****** Object: Table [dbo].[Consumption] Script Date: 07/19/2017 20:37:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Consumption](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Consumption no] [nvarchar](40) NULL,
[AnotherProductId] [int] NULL,
[Quantity] [float] NULL,
CONSTRAINT [PK_Consumption] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Consumption] ON
INSERT [dbo].[Consumption] ([Id], [Consumption no], [AnotherProductId], [Quantity]) VALUES (1, N'Con-122 ', 2, 10)
INSERT [dbo].[Consumption] ([Id], [Consumption no], [AnotherProductId], [Quantity]) VALUES (2, N'Con-122 ', 4, 10)
SET IDENTITY_INSERT [dbo].[Consumption] OFF
这应该会给您预期的结果。请尝试。
;WITH CTE AS (
select DISTINCT ProductID,AnotherProductId,Balance,
CASE WHEN Balance>=0 THEN 'P' ELSE 'N' END Flag, row_number() over(partition by AnotherProductId order by Balance) RID
FROM (SELECT DISTINCT P.ProductID,I.AnotherProductId,(P.Quantity-C.Quantity) 'Balance'
FROM [ProductEntry] P INNER JOIN [IpEntry] I ON I.ProductID=P.ProductId
INNER JOIN (SELECT [AnotherProductId],SUM([Quantity]) [Quantity] FROM [Consumption] GROUP BY [AnotherProductId]) C ON C.AnotherProductId=I.AnotherProductId
)A
)
select T.AnotherProductId,Balance as Stock, C.Quantity as 'Quantity Used',MIN((P.Price *(P.Quantity-C.Quantity)/P.Quantity)) 'Remaining Balance'
FROM [ProductEntry] P INNER JOIN CTE T ON T.ProductID=P.ProductId AND (RID=1 OR Flag='N')
INNER JOIN (SELECT DISTINCT ProductId,AnotherProductId FROM [IpEntry]) I ON I.ProductID=P.ProductId
INNER JOIN (SELECT [AnotherProductId],SUM([Quantity]) [Quantity] FROM [Consumption] GROUP BY [AnotherProductId]) C ON C.AnotherProductId=I.AnotherProductId
GROUP BY T.AnotherProductId,Balance, C.Quantity
预计涵盖所有场景。
SELECT DISTINCT P.ProductID,P.Quantity,-1 Flag,C.[Quantity] Balance
INTO #TMP
FROM [ProductEntry] P
INNER JOIN [IpEntry] I ON I.ProductID=P.ProductId
INNER JOIN (SELECT [AnotherProductId],SUM([Quantity]) [Quantity] FROM [Consumption] GROUP BY [AnotherProductId])C ON C.AnotherProductId=I.AnotherProductId
DECLARE @Counter INT=1
WHILE((SELECT TOP 1 1 FROM #TMP WHERE Flag=-1 )=1)
BEGIN
UPDATE T SET T.Balance = T.Balance-T.Quantity,
T.Quantity = CASE WHEN T.Quantity-T.Balance>=0 THEN T.Quantity-T.Balance ELSE 0 END,
T.Flag = CASE WHEN T.Quantity-T.Balance>=0 THEN 0 ELSE 1 END
FROM (SELECT ProductId,Quantity,row_number() over (partition by ProductId order by Quantity)RID FROM [ProductEntry])P
INNER JOIN [IpEntry] I ON I.ProductID=P.ProductId and P.RID=@Counter
INNER JOIN (SELECT ProductId,Quantity,Flag,Balance,row_number() over (partition by ProductId order by Quantity)RID FROM #TMP ) T ON T.ProductID=P.ProductID and T.RID=@Counter
INNER JOIN (SELECT [AnotherProductId],SUM([Quantity]) [Quantity] FROM [Consumption] GROUP BY [AnotherProductId])C ON C.AnotherProductId=I.AnotherProductId
UPDATE T1 SET Balance=T2.Balance
FROM #TMP T1 INNER JOIN #TMP T2 ON T1.ProductId=T2.ProductId
WHERE T2.Flag IN (0,1)
UPDATE T1 SET Flag= (SELECT T2.Flag FROM #TMP T2 WHERE T1.ProductId=T2.ProductId AND T2.Flag=0)
FROM #TMP T1
WHERE Flag=0
SET @Counter=@Counter+1
SELECT * FROM #TMP
END
SELECT ProductId,Quantity FROM #TMP --You can add more details by joining with other tables as per your requirement
drop table #TMP