1

I've seen the following used to return a list of numbers

SELECT TOP (SELECT MAX(Quantity) FROM @d) 
       rn = ROW_NUMBER() OVER (ORDER BY object_id)    
FROM   sys.all_columns 
ORDER BY object_id  

if the max quantity is 5 then I assume the above returns:

rn
1
2
3
4
5

Is there a more elegant, or even canonical, approach within T-SQL to return this list of numbers?

4

6 回答 6

7

你可以做:

SELECT        rn = 1 
  UNION ALL SELECT 2 
  UNION ALL SELECT 3 
  UNION ALL SELECT 4 
  UNION ALL SELECT 5;

当数字是 5,但不是 50 或 5000 时,这是可以容忍的。当您需要更多时,您可以做一些事情,例如使用 CTE 建立一组数字,然后交叉连接以分解该集合(您可以查看几个示例在这里,在 Inline 1 / Inline 2 下)。

或者你可以建立一个数字表,假设你可能需要 5 或者你可能需要 100 万:

SET NOCOUNT ON;
 
DECLARE @UpperLimit INT = 1000000;
 
WITH n AS
(
    SELECT
        x = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
    FROM       sys.all_objects AS s1
    CROSS JOIN sys.all_objects AS s2
    CROSS JOIN sys.all_objects AS s3
)
SELECT Number = x
  INTO dbo.Numbers
  FROM n
  WHERE x BETWEEN 1 AND @UpperLimit;
 
GO
CREATE UNIQUE CLUSTERED INDEX n ON dbo.Numbers(Number);
GO

然后,当您想要一些数字时,您只需说:

SELECT TOP (5) rn = Number 
  FROM dbo.Numbers 
  ORDER BY Number;

显然,使用 sys.all_columns 或任何具有足够行的内置对象避免了创建 Numbers 表的前期步骤(无论如何,出于某种原因,许多人反对)。

现在,如果有更优雅的方式来做到这一点,那就太好了,不是吗?您不会在任何当前版本中看到它,但我们有机会在未来版本中看到它。请在此处投票(更重要的是,评论您的用例):

http://connect.microsoft.com/SQLServer/feedback/details/258733/add-a-built-in-table-of-numbers

于 2012-06-13T17:42:32.190 回答
4

绝对不是最优雅的,但可能是较大序列的最快方法:

WITH
 E1(N) AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
           SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
           SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
           SELECT 1),                 --10E1  or 10 rows
 E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E2  or 100 rows
 E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E3  or 10000 rows
 E8(N) AS (SELECT 1 FROM E4 a, E4 b)  --10E4  or 100000000 rows
SELECT TOP (@DesiredRowCount) N = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E8
;

没有临时表,没有表读取,您可以自己定义最大值。

您可以从此处复制粘贴即用型功能

于 2014-05-26T21:56:19.523 回答
3

首先创建一个数字表 0 - 9

create table dbo.Digits (digit tinyint not null Primary Key) 
insert into dbo.Digits values (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)

然后您可以生成以下交叉连接以从 1 计数到 100:

select
D2.digit * 10 + 
D1.digit + 1 as n
from dbo.Digits D1,
dbo.Digits D2
order by n

要从 1 计数到 1000,您只需添加一个额外的交叉连接:

select
D3.digit * 100 +
D2.digit * 10 + 
D1.digit + 1 as n
from dbo.Digits D1,
dbo.Digits D2,
dbo.Digits D3
order by n

从 1 计数到 x(其中 x <= 1000)::

select top x
D3.digit * 100 +
D2.digit * 10 + 
D1.digit + 1 as n
from dbo.Digits D1,
dbo.Digits D2,
dbo.Digits D3
order by n
于 2013-06-14T19:38:39.917 回答
3

我过去曾使用过类似的东西——尽管它最多只能使用 100 个左右:

WITH Numbers(number) AS (
SELECT 1 number
UNION ALL
SELECT number+1 FROM Numbers WHERE number < 10)
SELECT * FROM Numbers
于 2012-06-13T18:01:29.333 回答
1

如果您只希望输出包含一个运行编号作为附加列,则以下内容也可以:

select row_number() over (order by (Select 1)) AS RowNum, * from Table_1 where Column_3 = 372 and Column_6 = 2017;
于 2017-05-23T09:00:10.753 回答
1

根据需要修改 Top 值:

SELECT TOP 30 ROW_NUMBER() OVER (ORDER BY [object_id]) 
FROM sys.all_objects

例如,下拉列表显示 NULL 范围,1 - 30 表示受教育年限。

<tr>
<td>Education</td>
<td>
<asp:DropDownList ID="EducationDropDownList" runat="server" DataSourceID="sd6"
 DataValueField="Education" DataTextField="Education" 
 SelectedValue='<%# Bind("Education") %>' CssClass="metro" />
<asp:SqlDataSource ID="sd6" runat="server" 
 ConnectionString="<%$ ConnectionStrings:cnYours %>" 
 SelectCommand="SELECT NULL AS Education UNION ALL SELECT TOP 30 ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects" 
 SelectCommandType="Text" />
</td>
</tr>
于 2017-01-28T07:40:10.747 回答