【问题标题】:retrieve specific range of rows in a SQL Server table检索 SQL Server 表中特定范围的行
【发布时间】:2009-06-21 12:58:31
【问题描述】:

我有一个类似 (OrderID [uniqueidentifier], OrderDeciption [nvarchar]) 的表结构,我使用的是 ADO.Net + C# + VSTS 2008 + SQL Server 2008。表很大,我想让客户给我两个输入,开始范围索引和结束范围索引,我将返回该范围内的表的特定行(在开始范围索引和结束范围索引之间)。

比如客户端给我输入50、100,我想返回第50行直到第100行。

提前致谢, 乔治

【问题讨论】:

    标签: c# .net sql-server-2008 ado.net


    【解决方案1】:

    您可以在 TSQL(2005 年以后)中使用 ROW_NUMBER 来执行此操作:

    SELECT  ID, Foo, Bar
    FROM     (SELECT  ROW_NUMBER() OVER (ORDER BY ID ASC) AS Row,
              ID, Foo, Bar
    FROM    SomeTable) tmp
    WHERE   Row >= 50 AND Row <= 100
    

    或使用 LINQ-to-SQL 等:

    var qry = ctx.Table.Skip(50).Take(50); // or similar
    

    【讨论】:

    • SQL Server 管理工作室的输出有误。我以这种方式尝试了您的SQL Statement,从 (SELECT ROW_NUMBER() OVER (ORDER BY Date DESC) AS Row, [OrderStatus].[OrderID], [OrderStatus].[OrderID], [OrderStatus].[OrderStatus] OrderStatus].[OrderStatus] from [OrderStatus]) where Row >= 0 and Row
    • 您的解决方案在哪里?我很困惑。你能指出来吗? :-)
    • 我添加了一个名为 OrderCreateTime 的新列,我认为如果我们 SELECT xxx,ROW_NUMBER() OVER (ORDER BY OrderCreateTime) 应该比按订单 ID 的订单更好,对吗?为什么?
    • 如果 OrderID 是一个 IDENTITY 列,无论如何它可能会随着时间的推移而增加,并且是一种更简单的数据类型。当然,如果您在 OrderCreateTime 上有一个聚集索引,那么它是排序的理想选择...
    • 参见“FROM SomeTable) tmp”——这个别名就是让它工作所需要的全部。
    【解决方案2】:

    基本上,您在 SQL Server 2005 和 2008 中的最佳选择是 CTE - 公用表表达式 - 其中包含 ROW_NUMBER() 函数 - 如下所示:

    WITH MyOrders AS
    (
      SELECT
        OrderID,
        OrderDescription,
        ROW_NUMBER() OVER (ORDER BY OrderID) as 'RowNum'
      FROM YourOrders
    )
    SELECT * FROM MyOrders
    WHERE RowNum BETWEEN 50 AND 100
    

    但这需要一个有用且合适的ORDER BY 子句,并且按GUID 排序确实不是一个好主意。 DATETIME 或不断增加的 ID 是最好的。

    马克

    【讨论】:

    • 嗨 Marc,抱歉我的描述不好,我不想让客户端通过 GUID orderID 的值指定范围,而是通过表的物理行号指定范围。有什么想法可以实现吗?
    • 好吧,我在我的帖子中的 CTE 就是这样做的——只是通过 GUID 选择是一种非常糟糕的数据排序方式——它基本上完全是随机的……但如果那是你在找什么,我的代码 sn-p 应该可以实现这一点。
    • 对这个语句感到困惑 -- "ROW_NUMBER() OVER (ORDER BY OrderID) as 'RowNum'" -- 因为 orderID 是随机 GUID,我想按数据库表中的物理行范围检索范围,不是订单ID的取值范围。看起来从我引用的语句中您可以按 orderID 选择行范围?
    • @George2:是的,按 OrderCreateTime 选择会更好——因为它定义了一个真实的订单——按创建订单的日期/时间。订单 ID 的 GUID 只是一个随机数,实际上没有排序特征。
    • 必须在排序定义上定义“ROW_NUMBER()”函数。只有当您将所有行放入 ORDER(任何类型)时,您才能将 ROW_NUMBER 附加到它们。 SQL Server 行集本身没有任何顺序 - 这就是为什么您必须通过发出 OVER (ORDER BY (列名)) 来定义顺序,以便 ROW_NUMBER 函数知道如何将行号附加到行。
    【解决方案3】:

    试试这个,结果将按 OrderID 列排序。用您的表更改 MyTable

    SELECT * 
    FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY OrderID) AS row FROM MyTable) a 
    WHERE row > 50 AND row <= 100
    

    选定的行从 50100,但请注意第 50 行不包含在结果中。

    【讨论】:

    • 我执行了你的语句,但是来自 SQL Server Management Studio。 select * from (SELECT ROW_NUMBER() OVER (ORDER BY [OrderStatus].[OrderID]) AS Row from [OrderStatus]) where Row >= 0 and Row
    • 嘿,你把第三行 SELECT 后面的字母 a 擦掉了。这是一个别名,是必要的。
    • 我添加了一个名为 OrderCreateTime 的新列,我认为如果我们 SELECT *, ROW_NUMBER() OVER (ORDER BY OrderCreateTime) 应该比按订单 ID 的订单更好,正确,为什么?
    • “a”为括号内的匿名查询命名。
    • @maydenec 这相当于 MySQL 中的 "SELECT * FROM MyTable LIMIT 50, 50"。
    【解决方案4】:

    SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY OrderId) as row FROM Orders) a WHERE row > 5 and row

    【讨论】:

    • 我已经尝试过您的解决方案,但出了点问题,SELECT * FROM [dbo].[OrderStatus] (SELECT *, ROW_NUMBER() OVER (ORDER BY [OrderID]) as row FROM [dbo]。 [OrderStatus]) where row > 0 and row
    • 我添加了一个名为 OrderCreateTime 的新列,我认为如果我们 SELECT xxx,ROW_NUMBER() OVER (ORDER BY OrderCreateTime) 应该比按订单 ID 的订单更好,对吗?为什么?
    • 你错过了命名选择“.. from Orders) >>a
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-22
    • 2014-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多