为什么我从这个查询得到错误的输出?

时间:2012-06-29 11:35:44

标签: sql sql-server sql-server-2008 tsql

我试图在ms sql server中分页结果,我遇到了一些麻烦,得到了正确的结果。我想获得与mysql相同的结果:s LIMIT和Iäm试图使用这个模型来做到这一点:

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

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

2 个答案:

答案 0 :(得分:2)

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

(注意:这是针对SQL 2005及更高版本的 - SQL 2000不支持row_number()函数)

假设一个表有一列'Name':

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

答案 1 :(得分:1)

注意示例查询。

最里面的子查询按field ASC对结果进行排序。这是所有页面的主要顺序。最里面的子查询按顺序排列前y行。

中间层子查询反转订单并从前一个结果中获取前x,从而有效地获取底部x整个数据集的顶部y行的行。

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

你应该这样做。您最内层的查询会按如下顺序排序:

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

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

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

在主查询中排序行的方式可能并不重要,但我会按照示例重新颠倒顺序,使其与最里面的查询匹配。