1

我试图在 ms sql server 中对结果进行分页,但在获得正确的结果时遇到了一些麻烦。我想达到与 mysql:s LIMIT 相同的结果,我正在尝试使用这个模型来做到这一点:

SELECT * FROM (
    SELECT TOP x * FROM (
        SELECT TOP y fields
        FROM table
        WHERE conditions
        ORDER BY table.field  ASC) as foo
    ORDER by field DESC) as bar
ORDER by field ASC

来自:http: //josephlindsay.com/archives/2005/05/27/paging-results-in-ms-sql-server/

列出前 30 行的原始查询如下:

SELECT TOP 30 pt.[BSNR], t.ID, pt.RESDATUMTID, pt.LAND1, pt.HPL1, pt.ANKDATUMTID, pt.LAND2, pt.HPL2
  FROM [statistik2].[dbo].[ttrip] AS t
  JOIN [statistik2].[dbo].[tparttrip] AS pt 
  ON t.ID = pt.TRIP_ID
  WHERE t.DBKRDAT > '2012-06-27'
  ORDER BY pt.BSNR DESC, t.ID, pt.RESDATUMTID

我的尝试是:

SELECT * FROM (
    SELECT TOP 10 * FROM (
        SELECT TOP 30 pt.ID AS PTID, pt.[BSNR], t.ID, pt.RESDATUMTID, pt.LAND1, pt.HPL1, pt.ANKDATUMTID, pt.LAND2, pt.HPL2
        FROM [statistik2].[dbo].[ttrip] AS t
        JOIN [statistik2].[dbo].[tparttrip] AS pt
        ON t.ID = pt.TRIP_ID
        WHERE t.DBKRDAT > '2012-06-27'
        ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID
    ) as pttt
    ORDER BY pttt.PTID DESC) AS ptttt
ORDER BY ptttt.PTID 

查询的输出: http: //speedy.sh/5NQeq/sqloutput.txt

有人可以解释我做错了什么吗?

4

2 回答 2

2

您可以使用 ROW_NUMBER() 来获得运行计数 - 这使得分页更容易......例如

(注意:这适用于 SQL 2005 及更高版本 - SQL 2000 不支持 row_number() 函数)

假设一个表有一列“名称”:

SELECT * FROM 
(
    SELECT ROW_NUMBER() OVER (ORDER BY Name) as RunningVal, * FROM Names
) as Running 
WHERE RunningVal BETWEEN 5 AND 10

老实说,整个三重排序有点老派:P

在您的情况下,它将类似于:

SELECT * FROM (
    SELECT TOP 30 
        ROW_NUMBER() OVER (ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID) as RunningVal, 
        pt.ID AS PTID, 
        pt.[BSNR], 
        t.ID, 
        pt.RESDATUMTID, 
        pt.LAND1, 
        pt.HPL1, 
        pt.ANKDATUMTID, 
        pt.LAND2, 
        pt.HPL2 
    FROM [statistik2].[dbo].[ttrip] AS t 
    JOIN [statistik2].[dbo].[tparttrip] AS pt 
    ON t.ID = pt.TRIP_ID 
    WHERE t.DBKRDAT > '2012-06-27' 
    ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID
    ) as Running 
WHERE RunningVal BETWEEN 1 AND 10

事实上,您甚至可以摆脱内部 TOP 并使用:

SELECT * FROM (
    SELECT     
        ROW_NUMBER() OVER (ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID) as RunningVal, 
        pt.ID AS PTID, 
        pt.[BSNR], 
        t.ID, 
        pt.RESDATUMTID, 
        pt.LAND1, 
        pt.HPL1, 
        pt.ANKDATUMTID, 
        pt.LAND2, 
        pt.HPL2 
    FROM [statistik2].[dbo].[ttrip] AS t 
    JOIN [statistik2].[dbo].[tparttrip] AS pt 
    ON t.ID = pt.TRIP_ID 
    WHERE t.DBKRDAT > '2012-06-27' 
    ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID
    ) as Running 
WHERE RunningVal BETWEEN @x AND @y

其中@x 是下限,@y 是上限(BETWEEN 包括在内,ROW_NUMBER() 从 1 开始,因此 x = 1 和 y = 10 将为您提供记录 1-10)

编辑:不确定当您在 LIMIT 中指定一个超出范围的 OFFSET 时 MySql 会发生什么(据我所知,官方文档似乎没有提到这个),但如果您指定 @ x = 100 和 @y = 110 并且表中只有 50 条记录,您将不会得到任何结果

Edit2:添加了一个 SQL 小提琴链接,如果你想摆弄它!

http://sqlfiddle.com/#!3/57808/3

于 2012-06-29T11:58:47.060 回答
1

注意示例查询。

最里面的子查询按 . 对结果进行排序field ASC。这是所有页面的主要顺序。最里面的子查询y按该顺序获取最上面的行。

中间层子查询颠倒顺序并从前一个结果x中获取顶部行,从而有效地获取整个数据集顶部行的底部行。xy

主查询只是重新建立行的主要顺序。

你也应该这样做。您最里面的查询对这样的行进行排序:

ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID

如果这是您的主行顺序,那么您应该在中间层子查询中使用它的反转版本,即像这样:

ORDER BY pt.BSNR ASC, t.ID ASC, pt.RESDATUMTID DESC

在主查询中如何对行进行排序可能并不重要,但我会按照示例再次反转顺序,使其与最里面的查询匹配。

于 2012-06-29T11:58:08.993 回答