【问题标题】:Product Quantity Deduction On Condition有条件的产品数量扣除
【发布时间】:2017-12-24 23:11:27
【问题描述】:

我要求在某个条件下扣除产品数量。它似乎有点复杂,不知道如何使用 sql 查询来做到这一点。这是它的概念:产品在这里意味着原材料。出于生产目的,我们必须从库存中扣除原材料。有一些规则可以遵循:

表格 - ProductEntry:

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

游戏从这里开始。在许多情况下,原材料或产品可能会同时分成多个部分或全部,我的意思是假设总共有 100 件。

ii) 现在购买后,它必须进入商店,还有另一个程序。每个购买的产品都应单独收到一个 IP(进口许可证)编号,如下所示:

表格 - 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) 收到产品后,应用于生产目的,即有消费。在消费时,应使用最先进入的产品或原材料。这意味着,如果必须扣除产品 id 1001,则应根据 'EntryDate' 扣除第一个输入的产品,因为它已在最小值处输入。时间 10:00:00 在同一天。因此,对于扣除或消费,应进行以下操作:

表 - 消耗:

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 JOINMIN 函数应该不够准确和简单:

  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

【问题讨论】:

  • 注意:产品的扣款一直持续到数量为零为止。
  • 在您的解释中,库存和使用数量如何相同 - 10 和 10?
  • 因为总量都是20个,使用后(减去10个)变成10个和10个。
  • 所以最后你需要得到 3 条记录,正如你在上一张表中解释的那样 - 列:Id - AnotherProductId - Stock - Quantity Used - Remaining Balance ?在这里,ID 2 应该有 80 个库存,因为您只消耗了 ID 1 和 3?
  • 没有。另一个(参见最终输出部分)。这只是使用DateTime 的简单FIFO。因此,首先进入的产品或原材料应从库存中扣除。在我的例子中,对于 1001,首先输入的库存是 20,它首先被扣除。

标签: sql sql-server-2008 sql-server-2000


【解决方案1】:

这应该会给您预期的结果。请尝试。

    ;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

【讨论】:

  • 我运行您的查询@Rajesh Bhat。它有效,但只有一个问题。数量保持在我给定的样本中,并且当我再次输入以从特定产品的 Consumption 表中扣除数量时,假设AnotherProductId 2 不会被扣除。顺便说一句,我产品消费必须使用MIN(DateTime)
  • 是的,其实就是在Consumption表中再增加一条记录,就是从ProductEntry表的第二条记录中扣除。将重新检查查询。
  • 对我的回答做了一个小的更正。现在看起来不错。请尝试。
  • 它按预期工作。非常感谢。我又打扰你了。假设对于AnotherProductId 2,库存已经为零,并且ProductIdAnotherProductId(1001 或2)有两个不同数量的条目。所以它应该从第二个获得股票意味着另一个股票是 80。
  • 是的,我也在处理那个场景。它应该将第一条记录设为 0,然后从第二条记录中选择,对吗?
【解决方案2】:

这应该涵盖所有场景。

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     

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 2021-12-28
    • 1970-01-01
    • 2020-08-30
    • 2011-04-24
    相关资源
    最近更新 更多