我在SQL Server 2008上运行了一个查询,我遇到的问题是它超出了maxrecursion
的限制,我不知道另一种方法。
让我解释一下:此查询列出了基于MfgPN
的每个ShipQuantity
的行数。
例如,如果MfgPN
为XYZ
且ShipQuantity
为5,则会返回5行......依此类推其他MfgPN
库...等
这个工作正常,直到最近我收到的记录有ShipQuantity
超过100K,而且它崩溃了,因为我相信maxrecursion
只允许高达32K。
请告诉我是否有其他方法可以返回超过100K的行?
提前感谢您的帮助。
这是代码。
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)
答案 0 :(得分:1)
我可以提出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
答案 1 :(得分:0)
每个递归查询都可以写成循环(小心)。您的递归查询有一个锚点部分和一个递归部分;它可以重构为:
你最终应该使用这种模式(伪代码):
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
答案 2 :(得分:0)
将其作为一种可能的解决方案。我们的想法是将一组详细信息或订单行插入到另一个表中,该表等于输入的数量。这是最适合作为触发器或作为插入详细信息表的单独存储过程的事物之一。
这是一个触发式解决方案。我基本上接受了你的CTE并限制了基于QTY的递归并将其粘贴在AFTER INSERT触发器中。
@Html.DropDownList("countries", Model)
这是一个存储过程解决方案。因为你正在运行一个报告,然后是一个插入(如果我正确地遵循了这个问题。基本上是相同的事情,但是使用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
--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