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

Sql 为什么我从这个查询中得到了错误的输出?,sql,sql-server,sql-server-2008,tsql,Sql,Sql Server,Sql Server 2008,Tsql,我试图在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

我试图在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
发件人:

列出前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 
查询的输出:


有人能解释一下我做错了什么吗?

请注意示例查询

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

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

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

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

ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID
ORDER BY pt.BSNR ASC, t.ID ASC, pt.RESDATUMTID DESC
如果这是您的主行顺序,那么您应该在中间层子查询中使用它的反转版本,例如:

ORDER BY pt.BSNR DESC, t.ID DESC, pt.RESDATUMTID
ORDER BY pt.BSNR ASC, t.ID ASC, pt.RESDATUMTID DESC
在主查询中如何对行进行排序可能并不重要,但我会遵循示例并再次颠倒顺序,使其与最内部查询的顺序相匹配。

您可以使用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
事实上,您甚至可以去掉内部顶部,只需使用:

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是上限(介于两者之间,且行数()从1开始,因此x=1和y=10将给出记录1-10)

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

Edit2:如果你想修改它,就添加了一个sqlfiddle链接


什么版本的SQL?如果您使用的是MSSQL 2005+,则可以使用(按xxxx排序)上的行数()来获取运行计数,然后使用此函数来创建类似于MySql的LIMIT XX、XXIt的MSSQL 2008的函数,所以也许我应该尝试一下!谢谢我已经添加了一个答案——我将看看是否可以用您需要的查询更新它。有些人因为SQL产品的旧版本而不得不坚持老一套。不过,OP的DBMS很可能是SQL Server 2005或更高版本,但提及
行号()所需的最低版本不会对您的答案造成丝毫影响。:)啊已经在评论中问了这个问题-无论如何都会更新答案!再次感谢,我很感激,它看起来干净多了!