Sql server 每行或每行的Sql server
首先,我使用了AdvantureWork2019 DB,您可以使用它查看与我相同的结果,如果您想测试它,我将添加一个脚本,在末尾创建折扣表,并创建我用于创建##诱惑的视图,我的问题是: 我有两个临时表,第一个是: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
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
的其余行添加0DiscID
,然后转到下一个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时,我更改了查询,然后应用了你的解决方案,效果非常好,非常感谢你的光临。对于未来:当你开始忘记自己的解决方案时,试着把它分解成更小的步骤,一次只处理一个问题并解决它,不要试图一步解决所有问题。您始终可以返回并合并或优化解决方案的现有部分,是itSUM()
还是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
;