在SQL Server中选择N行

时间:2015-08-19 12:54:20

标签: sql sql-server tsql

以下查询将在10行中返回1-10。

DECLARE @start INT = 1;
DECLARE @end INT = 10;

WITH numbers AS (
    SELECT @start AS number
    UNION ALL
    SELECT number + 1 
    FROM  numbers
    WHERE number < @end
)
SELECT *
FROM numbers
OPTION (MAXRECURSION 0);

但是当我将@Range设置为10000时,它返回7374行。为什么此查询不能返回超过7374行。

更新

我刚刚找到另一种方法来实现我的要求,如下所示

{{1}}

没有最后一行代码,它突然出现错误最大递归100在语句完成之前已经用完了,我发现这行为无限递归指定0。但这个查询对我来说似乎有点慢。有没有更快的方法???

6 个答案:

答案 0 :(得分:11)

如前所述,这是因为您达到了sys.columns的行数。这是另一种生成数字列表或其他人称为Numbers TableTally Table的方法。

这使用级联CTE,据说是创建Tally Table的最快方法:

DECLARE @Range AS INT = 7374

;WITH E1(N) AS( -- 10 ^ 1 = 10 rows
    SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b), -- 10 ^ 8 = 10,000,000 rows
CteTally(N) AS(
    SELECT TOP(@Range) ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
    FROM E8
)
SELECT * FROM CteTally

如果您需要超过10,000行,可以轻松添加另一个CTE。

有关Tally Table的更多信息,请阅读Jeff Moden的这篇优秀article

对于生成Tally表的方法之间的性能比较,请阅读this

Jeff的解释article

  

CTE称为E1(如10E1中的科学记法所示)并不算什么   超过十个SELECT 1作为单个结果集返回。

     

E2自己CROSS JOIN E1。这会返回一个   结果集为10 * 10或最多100行。我说&#34;直到&#34;因为如果   TOP功能是100或更少,CTE是&#34; smart&#34;足以知道这一点   它实际上不需要再进一步E4E8赢了   甚至发挥作用。如果TOP的值小于100,则不是   E2能够制作的所有100行。它永远都是   根据{{​​1}}函数制作足够的内容。

     

你可以从那里开始。 TOPE4 CROSS JOIN的意思   最多100 * 100或10,000行,E2E8 CROSS JOIN   这将比大多数人需要的行数更多。如果你这样做   需要更多,然后只需添加E4作为E16的{​​{1}}并进行更改   CROSS JOIN的最终E8条款。

     

这个坏孩子真正令人惊讶的是产生 ZERO   READS 即可。绝对没有,纳达,没有。

答案 1 :(得分:3)

生成大量数字的一种方法是使用cross join在两个表之间创建一个笛卡尔积,这将产生一个n^2大小的集合。

然而,这种方法比the answer by Felix Pamittan中提出的解决方案要糟糕得多,因此不应该使用。

DECLARE @Range AS INT = 10000

;WITH CTE AS(
    SELECT TOP (@Range) Duration = ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
    FROM sys.all_columns a CROSS JOIN sys.all_columns b
)
SELECT Duration from CTE

这会在您的情况下生成一组54375876行。您应该考虑创建一个适合您需求的计数表,而不是动态生成行。

答案 2 :(得分:0)

当变量中的值超过值7374时,这无关紧要。该表只有7374行。

答案 3 :(得分:0)

这意味着您的查询返回的总行数是7374.如果您可以创建一些表并运行代码,您将看到数字的增加

答案 4 :(得分:0)

这是因为最大行数是7374,您可以使用master..spt_Values表进行交叉连接,并且您将获得所需6325225列的Duration值。< / p>

DECLARE @Range AS INT = 10000 

;WITH CTE AS(
    SELECT TOP (@Range) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) Duration
    FROM master..spt_values a cross join master..spt_values b
)
SELECT Duration from CTE

答案 5 :(得分:0)

我使用此功能来获取正在运行的数字。您可以直接在FROM(或JOIN或APPLY ...)

中使用它

在阅读其他评论后,我将其更改为“堆叠CTE”方法(thx to Felix)

CREATE FUNCTION [dbo].[GetRunningNumbers](@anzahl INT=10000000, @StartAt INT=0)
RETURNS TABLE
AS 
RETURN
WITH E1(N) AS( -- 10 ^ 1 = 10 rows
    SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b), -- 10 ^ 8 = 10,000,000 rows
CteTally AS(
    SELECT TOP(ISNULL(@anzahl,1000000)) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) -1 + ISNULL(@StartAt,0) As Nmbr
    FROM E8
)
SELECT * FROM CteTally;