繁体   English   中英

根据数量列出行数

[英]Listing Number Of Rows based on Quantity

我有一个在SQL Server 2008上运行的查询,但maxrecursion一个问题,它超出了maxrecursion限制,而且我不知道另一种方法。

让我解释一下:此查询基于ShipQuantity每个MfgPN的行数。

例如,如果MfgPNXYZShipQuantity为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个解决方案。 首先是修复,其次是更好。 使用适合您的东西。

  1. 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)
  1. 更好的解决方案

在数据库中创建表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. 从CTE结构中删除两个查询。
  2. 更改第一个(锚点)以将其结果放入#temp表中
  3. 更改第二个(递归),使其将#temp表联接到“子”记录,而不是递归调用CTE(它只是内部联接#temp代替内部联接feedinfo)
  4. 添加一个计数器来跟踪从0开始的“级别”
  5. 将第二个查询包装到while循环中,这样只要返回记录,它就可以继续运行。

您应该以这种模式(伪代码)结束:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM