[英]Listing Number Of Rows based on Quantity
我有一个在SQL Server 2008上运行的查询,但maxrecursion
一个问题,它超出了maxrecursion
限制,而且我不知道另一种方法。
让我解释一下:此查询基于ShipQuantity
每个MfgPN
的行数。
例如,如果MfgPN
为XYZ
且ShipQuantity
为5,则它将返回5行...对于其他MfgPN
基等,依此类推。
直到最近我收到的记录显示ShipQuantity
超过100K为止,这一直很好,并且由于我认为maxrecursion
仅允许最多32K的记录而崩溃。
请让我知道是否有另一种方法可以返回超过10万行?
在此先感谢您的帮助。
这是代码。
WITH feedInfo AS
(
SELECT
df1.dfID, MfgPN, LinkID, ShipQuantity,
df1.ShipDescription, df1.Description, 1 AS Number
FROM
EXT_Feed df1
WHERE
1 = 1
AND df1.mfgPN IN ('XYZ')
AND df1.InvoiceDate = '2015-12-07'
AND df1.dfID = '2666'
UNION ALL
SELECT
df2.dfID, df2.MfgPN, df2.LinkID, df2.ShipQuantity,
df2.ShipDescription, df2.Description, feedInfo.number + 1 AS Number
FROM
EXT_Feed df2
INNER JOIN
feedInfo ON df2.dfID = feedInfo.dfID
WHERE
1 = 1
AND number < feedInfo.ShipQuantity
--AND df2.MfgPN = feedInfo.MfgPN
AND df2.mfgPN IN ('XYZ')
AND df2.InvoiceDate = '2015-12-07'
AND df2.dfID = '2666'
)
SELECT *
FROM feedInfo
OPTION (maxrecursion 30000)
我可以提出2个解决方案。 首先是修复,其次是更好。 使用适合您的东西。
MAXRECURSION 0
如果您确定查询正确结束,请不要担心MAXRECURSION 0
。
此查询将在22秒内在我的笔记本上执行:
WITH SampleValue AS(
SELECT
id = 1
,ShipQuantity = 1000000 -- One million iterations is not problem
),
REC AS(
SELECT id, ShipQuantity, number = 1
FROM SampleValue
UNION ALL
SELECT
id, ShipQuantity, number = REC.number + 1
FROM
REC
WHERE
ShipQuantity > number
)
SELECT TOP(10) * FROM (
SELECT * FROM Rec
)S
ORDER BY number DESC
OPTION (MAXRECURSION 0)
在数据库中创建表NUMBERS,并使用值1..1000000填充它。 这是报表数据库中的常用技术。
CREATE TABLE NUMBERS(number int PRIMARY KEY);
WITH REC AS(
SELECT NUMBER = 1
UNION ALL
SELECT
number = REC.number + 1
FROM
REC
WHERE
NUMBER < 1000000
)
INSERT INTO NUMBERS
SELECT NUMBER FROM REC
OPTION (MAXRECURSION 0);
之后,您无需在查询中进行递归。 您可以这样写:
SELECT
df1.dfID, MfgPN, LinkID, ShipQuantity,
df1.ShipDescription, df1.Description, N.Number
FROM
EXT_Feed df1
JOIN Numbers N ON df1.ShipQuantity <=N.Number
每个递归查询都可以写成一个循环(小心)。 您的递归查询具有锚点和递归部分; 可以重构为:
您应该以这种模式(伪代码)结束:
select <original anchor query>, level = 1 into #temp
set @level = 0
while records are returned (perhaps @@rowcount > 0)
begin
set @level += 1
insert into #temp select #temp join <original recursive query> where level = @level
end
将此作为可能的解决方案。 这个想法是让插入到另一张表中的一定数量的明细或订单行等于输入的数量。 这是最适合作为插入明细表的触发器或单独存储过程的事情之一。
这是触发的解决方案 。 我基本上采用了CTE,并基于QTY限制了递归,并将其固定在AFTER INSERT触发器中。
--CREATE TABLES
if object_id('shippingTest','U') is not null
drop table shippingTest;
create table shippingTest(shipID int identity, mfrID int, shipQty int);
GO
if object_id('shippingTestDetail','U') is not null
drop table shippingTestDetail
create table shippingTestDetail (detailID int identity, shipID int, mfrID int, shipQty int, detailLineNum int);
GO
--CREATE TRIGGER ON INSERT
CREATE TRIGGER tr_shippingTest_Insert_shippingTestDetail
ON shippingTest
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
with cteQty --original cte with recursion limited by shipQty
as
(
select shipID, mfrID, shipQty, 1 as lineNum
from inserted
union all
select i.shipID, i.mfrID, i.shipQty, c.lineNum+1 as lineNum
from inserted i
JOIN cteQty c on c.shipID=i.shipID
where c.lineNum < i.shipQty
)
insert shippingTestDetail
select shipID, mfrID, shipQty, lineNum
from cteQty
order by shipID
END
GO
--INSERT VALUES
insert shippingTest
values (111,1),(222,2),(555,5)
select * from shippingTest
select * from shippingTestDetail order by shipid
这是一个存储过程解决方案 。 由于您运行的是报表,然后是插入报表(如果我正确地回答了该问题。执行基本相同的操作,但是循环调用以shipID作为参数的SP。
--CREATE TABLES
if object_id('shippingTest','U') is not null
drop table shippingTest;
create table shippingTest(shipID int identity, mfrID int, shipQty int);
GO
if object_id('shippingTestDetail','U') is not null
drop table shippingTestDetail;
create table shippingTestDetail (detailID int identity, shipID int, mfrID int, shipQty int, detailLineNum int);
GO
--INSERT VALUES
insert shippingTest
values (111,1),(222,2),(555,5);
select * from shippingTest;
go
--create proc to insert detail records
if object_id('usp_insert_shippingTestDetail','P') is null
exec sp_executesql N'create proc usp_insert_shippingTestDetail as select getdate() STUB';
go
alter proc usp_insert_shippingTestDetail (@shipID int)
as
with cteQty --original cte with recursion limited by shipQty
as
(
select shipID, mfrID, shipQty, 1 as lineNum
from shippingTest
where shipID = @shipID
union all
select st.shipID, st.mfrID, st.shipQty, c.lineNum+1 as lineNum
from shippingTest st
JOIN cteQty c on c.shipID=st.shipID
where c.lineNum < st.shipQty
)
insert shippingTestDetail
select shipID, mfrID, shipQty, lineNum
from cteQty
order by shipID
go
--loop through records and insert per shipID
declare @shipID int
--initialize variables
select @shipID = min(st.shipID)
from shippingTest st
left join shippingTestDetail std on std.shipID = st.shipID
where std.shipID is NULL;
while @shipID is not null
begin
exec usp_insert_shippingTestDetail @shipID;
select @shipID = min(st.shipID)
from shippingTest st
left join shippingTestDetail std on std.shipID = st.shipID
where std.shipID is NULL;
end
select * from shippingTestDetail order by shipid;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.