Sql server 每行或每行的Sql server

Sql server 每行或每行的Sql server,sql-server,loops,tsql,Sql Server,Loops,Tsql,首先,我使用了AdvantureWork2019 DB,您可以使用它查看与我相同的结果,如果您想测试它,我将添加一个脚本,在末尾创建折扣表,并创建我用于创建##诱惑的视图,我的问题是: 我有两个临时表,第一个是: DiscID Desc DiscLimitID Limit DiscPercID Perc Qty DiscQtyID Allowed Allocated 1 NA 1 0.0000000

首先,我使用了AdvantureWork2019 DB,您可以使用它查看与我相同的结果,如果您想测试它,我将添加一个脚本,在末尾创建折扣表,并创建我用于创建##诱惑的视图,我的问题是:

我有两个临时表,第一个是:

DiscID  Desc    DiscLimitID Limit         DiscPercID    Perc    Qty      DiscQtyID  Allowed Allocated
1        NA         1       0.0000000         1      0.0200000  1.0000000   1      0.0000000    0.0000000
2        Cheap      2       50.0000000        2      0.0100000  4.0000000   2   1000.0000000    0.0000000
3        Moderate   3       200.0000000       3      0.0250000  3.0000000   3   5000.0000000    0.0000000
4        Expensive  4       1000.0000000      4      0.0500000  2.0000000   4   20000.0000000   5000.0000000
第二条:

SalesOrderID    SalesOrderDetailID  LineTotal   OrderQty    ODiscID
43659                   1          2024.994000      1         0
43659                   2          6074.982000      3         4
43659                   3          2024.994000      1         0
43659                   4          2039.994000      1         0
43659                   5          2039.994000      1         0
43659                   6          4079.988000      2         4
43659                   7          2039.994000      1         0
43659                   8          86.521200        3         0
43659                   9          28.840400        1         1
43659                  10          34.200000        6         1
我提出了一个查询以给出此结果(示例):

我现在要做的是创建一个游标或While循环,以阻止查询进行
折扣
,并将其添加到
最终分配
,并将其替换为0

例如,如果
DiscID
=3达到5000(
finalaallocated
),则停止对
DiscID
3的继续查询,并向包含
DiscID=3
的其余行添加0
DiscID
,然后转到下一个
DiscID
,即4,然后重新开始

例:

折扣表的脚本:

USE [AdventureWorks2019]
GO
/****** Object:  Table [dbo].[DiscountClass]    Script Date: 6/29/2020 12:29:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[DiscountClass](
    [DiscountClassID] [int] IDENTITY(1,1) NOT NULL,
    [Description] [nvarchar](50) NULL,
 CONSTRAINT [PK_DiscountClass] PRIMARY KEY CLUSTERED 
(
    [DiscountClassID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object:  Table [dbo].[DiscountLimit]    Script Date: 6/29/2020 12:29:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[DiscountLimit](
    [DiscountLimitID] [int] IDENTITY(1,1) NOT NULL,
    [DiscountClassID] [int] NULL,
    [Limit] [numeric](24, 7) NULL,
 CONSTRAINT [PK_DiscountLimit] PRIMARY KEY CLUSTERED 
(
    [DiscountLimitID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object:  Table [dbo].[DiscountPercentage]    Script Date: 6/29/2020 12:29:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[DiscountPercentage](
    [DiscountPercentageID] [int] IDENTITY(1,1) NOT NULL,
    [DiscountLimitID] [int] NULL,
    [Quantity] [numeric](24, 7) NULL,
    [Percentage] [numeric](24, 7) NULL,
 CONSTRAINT [PK_DiscountPercentage] PRIMARY KEY CLUSTERED 
(
    [DiscountPercentageID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object:  Table [dbo].[DiscountQuota]    Script Date: 6/29/2020 12:29:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[DiscountQuota](
    [DiscountQuotaId] [int] IDENTITY(1,1) NOT NULL,
    [DiscountClassId] [int] NULL,
    [Allowed] [numeric](24, 7) NULL,
    [Allocated] [numeric](24, 7) NULL,
 CONSTRAINT [PK_DiscountQuota] PRIMARY KEY CLUSTERED 
(
    [DiscountQuotaId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[DiscountClass] ON 

INSERT [dbo].[DiscountClass] ([DiscountClassID], [Description]) VALUES (1, N'NA')
INSERT [dbo].[DiscountClass] ([DiscountClassID], [Description]) VALUES (2, N'Cheap')
INSERT [dbo].[DiscountClass] ([DiscountClassID], [Description]) VALUES (3, N'Moderate')
INSERT [dbo].[DiscountClass] ([DiscountClassID], [Description]) VALUES (4, N'Expensive')
SET IDENTITY_INSERT [dbo].[DiscountClass] OFF
GO
SET IDENTITY_INSERT [dbo].[DiscountLimit] ON 

INSERT [dbo].[DiscountLimit] ([DiscountLimitID], [DiscountClassID], [Limit]) VALUES (1, 1, CAST(0.0000000 AS Numeric(24, 7)))
INSERT [dbo].[DiscountLimit] ([DiscountLimitID], [DiscountClassID], [Limit]) VALUES (2, 2, CAST(50.0000000 AS Numeric(24, 7)))
INSERT [dbo].[DiscountLimit] ([DiscountLimitID], [DiscountClassID], [Limit]) VALUES (3, 3, CAST(200.0000000 AS Numeric(24, 7)))
INSERT [dbo].[DiscountLimit] ([DiscountLimitID], [DiscountClassID], [Limit]) VALUES (4, 4, CAST(1000.0000000 AS Numeric(24, 7)))
SET IDENTITY_INSERT [dbo].[DiscountLimit] OFF
GO
SET IDENTITY_INSERT [dbo].[DiscountPercentage] ON 

INSERT [dbo].[DiscountPercentage] ([DiscountPercentageID], [DiscountLimitID], [Quantity], [Percentage]) VALUES (1, 1, CAST(1.0000000 AS Numeric(24, 7)), CAST(0.0200000 AS Numeric(24, 7)))
INSERT [dbo].[DiscountPercentage] ([DiscountPercentageID], [DiscountLimitID], [Quantity], [Percentage]) VALUES (2, 2, CAST(4.0000000 AS Numeric(24, 7)), CAST(0.0100000 AS Numeric(24, 7)))
INSERT [dbo].[DiscountPercentage] ([DiscountPercentageID], [DiscountLimitID], [Quantity], [Percentage]) VALUES (3, 3, CAST(3.0000000 AS Numeric(24, 7)), CAST(0.0250000 AS Numeric(24, 7)))
INSERT [dbo].[DiscountPercentage] ([DiscountPercentageID], [DiscountLimitID], [Quantity], [Percentage]) VALUES (4, 4, CAST(2.0000000 AS Numeric(24, 7)), CAST(0.0500000 AS Numeric(24, 7)))
SET IDENTITY_INSERT [dbo].[DiscountPercentage] OFF
GO
SET IDENTITY_INSERT [dbo].[DiscountQuota] ON 

INSERT [dbo].[DiscountQuota] ([DiscountQuotaId], [DiscountClassId], [Allowed], [Allocated]) VALUES (1, 1, CAST(0.0000000 AS Numeric(24, 7)), CAST(0.0000000 AS Numeric(24, 7)))
INSERT [dbo].[DiscountQuota] ([DiscountQuotaId], [DiscountClassId], [Allowed], [Allocated]) VALUES (2, 2, CAST(10000.0000000 AS Numeric(24, 7)), CAST(0.0000000 AS Numeric(24, 7)))
INSERT [dbo].[DiscountQuota] ([DiscountQuotaId], [DiscountClassId], [Allowed], [Allocated]) VALUES (3, 3, CAST(50000.0000000 AS Numeric(24, 7)), CAST(0.0000000 AS Numeric(24, 7)))
INSERT [dbo].[DiscountQuota] ([DiscountQuotaId], [DiscountClassId], [Allowed], [Allocated]) VALUES (4, 4, CAST(200000.0000000 AS Numeric(24, 7)), CAST(5000.0000000 AS Numeric(24, 7)))
SET IDENTITY_INSERT [dbo].[DiscountQuota] OFF
GO
第二种观点:

   Create View vAllDiscounts As
   select DS.DiscountClassID,DS.Description
   ,DL.DiscountLimitID,DL.Limit
   ,DP.DiscountPercentageID,DP.Percentage,DP.Quantity
   ,DQ.DiscountQuotaId,DQ.Allowed,DQ.Allocated
   from DiscountClass DS Inner join
  DiscountLimit DL ON  DS.DiscountClassID = DL.DiscountClassID
  INNER JOIN DiscountPercentage DP ON DL.DiscountLimitID = DP.DiscountLimitID
  INNER JOIN DiscountQuota DQ ON DQ.DiscountClassId = DL.DiscountClassID
临时表格:

select *
INTO ##TempDiscount
from vAllDiscounts 


select *
INTO ##TempOrederData
from vSalesOrderAll 
奥迪西德

update TOD
SET TOD.ODiscID = (CASE WHEN TOD.LineTotal <= 49 AND TOD.OrderQty >= 1  THEN 1
            WHEN TOD.LineTotal >= 50 AND TOD.LineTotal <= 199 AND TOD.OrderQty >= 4 THEN 2
            WHEN TOD.LineTotal >= 200 AND TOD.LineTotal <= 999 AND TOD.OrderQty >= 3 THEN 3
            WHEN TOD.LineTotal >= 1000 AND TOD.OrderQty >= 2 THEN  4
            ELSE 0 END)
from ##TempOrederData AS TOD 
编辑: 我添加了Case语句以在达到极限时停止它

WITH TotalDisc AS
(
SELECT TOD.SalesOrderID,TOD.SalesOrderDetailID AS SOdID
,TOD.LineTotal,TOD.OrderQty,TOD.OrderDate,AD.DiscountClassID AS DiscID 
,Percentage ,(LineTotal*Percentage) AS Discount, AD.Allocated AS Allc,AD.Allowed AS Allo

FROM ##TempOrederData TOD
INNER JOIN ##TempDiscount AD ON TOD.ODiscID = AD.DiscountClassID 
), TotalAndDiscount AS
(
SELECT SalesOrderID,SOdID,LineTotal,OrderQty,OrderDate,DiscID,Discount,Allc,LineTotal-Discount AS FinalTotal
FROM TotalDisc
), FinalCalc AS
(
SELECT SOdID,LineTotal,DiscID,Discount,FinalTotal,
sum(Discount) over ( Partition by DiscID order by SOdID) AS FinalAllocated
FROM TotalAndDiscount
),TestAllo AS
(
Select *
,Allocated = SUM(CASE   WHEN DiscID = 1 AND FinalAllocated < 5000 THEN  FinalAllocated
                        WHEN DiscID = 2 AND FinalAllocated < 10000 THEN  FinalAllocated
                        WHEN DiscID = 3 AND FinalAllocated < 20000 THEN  FinalAllocated
                        WHEN DiscID = 4 AND FinalAllocated < 50000 THEN  FinalAllocated
                        Else '0' END ) 
from FinalCalc
group by FinalCalc.SodID,FinalCalc.LineTotal,FinalCalc.DiscID,FinalCalc.Discount,FinalCalc.FinalTotal,FinalCalc.FinalAllocated
)
select * from TestAllo
where Allocated != 0
order by DiscID
当分配达到限额时,我希望它停止折扣并将下一个折扣替换为0,并从折扣表中获取允许的折扣,如下所示:

CASE    WHEN DiscID = 1 AND FinalAllocated < (Select allowed from DiscountQuota where DiscId=1) THEN  FinalAllocated
同样,我试图实现的是在(finalaallocated)>允许表###中的ID时,创建一个游标或While语句来停止求和


提前感谢您

在临时表中创建输出字段以帮助计算

首先计算
最终分配的
,无任何限制:

WITH FinalAllocatedCTE AS (
  SELECT
      SalesOrderID
    , FinalAllocated
    , SUM(Discount) OVER (PARTITION BY DiscID ORDER BY LineTotal ASC) AS Calc_FinalAllocated
  FROM
    ##TempOrederData
)
UPDATE
  FinalAllocatedCTE
SET
  FinalAllocated = Calc_FinalAllocated
然后重置超出限制的记录:

UPDATE
  DST
SET
  FinalAllocated= 0
FROM
  ##TempOrederData AS DST
  INNER JOIN ##TempDiscount AS DISC
    ON     DST.DiscID = DISC.DiscID
       AND DST.FinalAllocated > DISC.Limit
;
现在,您可以对最终分配为0的记录执行任何操作:

DECLARE @MaxAllocated TABLE (DiscID INT, MaxAllocated DECIMAL...);

INSERT INTO MaxAllocated (DiscID, MaxAllocated)
SELECT DiscID, MAX(FinalAllocated) AS MaxAllocated FROM ##TempOrederData
;

UPDATE
  DST
SET 
    DST.FinalAllocated= MA.MaxAllocated
  , DST.Discount = 0
  , DST.Allocated = 0
FROM
  ##TempOrederData AS DST
  INNER JOIN @MaxAllocated AS MA
    ON DST.DiscID = MA.DiscID
WHERE
  TotalAllocated = 0
;

实现这一点的非游标循环方法称为“累积和”,可以找到。如果您真的想在循环中执行此操作,然后搜索“sql server cursor”,我已经这样做了,您可以在我的查询中看到,我现在尝试的是在它达到指定的数字时停止它,并将折扣替换为0(在达到指定的允许值后)。我不确定您的问题到底是什么。我认为您需要添加一个
CASE WHEN
表达式来检查您的情况,例如
CASE WHEN(SUM(折扣)OVER…)>=分配然后0 ELSE SUM(折扣)OVER。。。。结束
如果这对您没有帮助,请查看。(很好,你花了时间发布了所有代码(DDL和DML)来重新创建你的问题,但要处理的事情很多)。我使用Case语句解决了一半的问题。我将添加一个编辑,我现在唯一的问题是如何使这个工作
当DiscID=1和finalaallocated
你是da man时,我更改了查询,然后应用了你的解决方案,效果非常好,非常感谢你的光临。对于未来:当你开始忘记自己的解决方案时,试着把它分解成更小的步骤,一次只处理一个问题并解决它,不要试图一步解决所有问题。您始终可以返回并合并或优化解决方案的现有部分,是it
SUM()
还是
SUM()OVER()
?如果您只想计算每行的折扣,则不需要求和;如果您想计算滚动总和,则需要
SUM()OVER()
且不需要分组方式;如果您想获得所有折扣的总和,则需要在不同的查询中执行此操作。
SOdID   LineTotal   DiscID  Discount    FinalTotal  FinalAllocated  Allocated
    915 2144.112900     4   107.205645  2036.907255 48226.798765    48226.798765
    916 27055.760424    4   1352.788021 25702.972403    49579.586786    49579.586786
    918 8159.976000     4   407.998800  7751.977200 49987.585586    49987.585586
    924 1749.588000     4   0           1749.588000 49987.585586    0.000000
    928 1749.588000     4   0           1749.588000 49987.585586    0.000000
    932 1749.588000     4   0           1749.588000 49987.585586    0.000000
    934 2097.294500     4   0           2097.294500 49987.585586    0.000000
    942 1258.376700     4   0           1258.376700 49987.585586    0.000000
CASE    WHEN DiscID = 1 AND FinalAllocated < (Select allowed from DiscountQuota where DiscId=1) THEN  FinalAllocated
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
WITH FinalAllocatedCTE AS (
  SELECT
      SalesOrderID
    , FinalAllocated
    , SUM(Discount) OVER (PARTITION BY DiscID ORDER BY LineTotal ASC) AS Calc_FinalAllocated
  FROM
    ##TempOrederData
)
UPDATE
  FinalAllocatedCTE
SET
  FinalAllocated = Calc_FinalAllocated
UPDATE
  DST
SET
  FinalAllocated= 0
FROM
  ##TempOrederData AS DST
  INNER JOIN ##TempDiscount AS DISC
    ON     DST.DiscID = DISC.DiscID
       AND DST.FinalAllocated > DISC.Limit
;
DECLARE @MaxAllocated TABLE (DiscID INT, MaxAllocated DECIMAL...);

INSERT INTO MaxAllocated (DiscID, MaxAllocated)
SELECT DiscID, MAX(FinalAllocated) AS MaxAllocated FROM ##TempOrederData
;

UPDATE
  DST
SET 
    DST.FinalAllocated= MA.MaxAllocated
  , DST.Discount = 0
  , DST.Allocated = 0
FROM
  ##TempOrederData AS DST
  INNER JOIN @MaxAllocated AS MA
    ON DST.DiscID = MA.DiscID
WHERE
  TotalAllocated = 0
;