【问题标题】:MS Access LIMIT X, YMS 访问限制 X、Y
【发布时间】:2011-12-24 21:46:11
【问题描述】:

是否可以模拟以下 MySQL 查询:

SELECT * FROM `tbl` ORDER BY `date` DESC LIMIT X, 10

(X是参数)

在 MS Access 中?

【问题讨论】:

    标签: ms-access


    【解决方案1】:

    虽然 Access/JET TOP 关键字不直接提供 OFFSET 功能,但我们可以使用 TOP、子查询和“派生表”的巧妙组合来获得相同的结果。

    这是一个示例,用于在ORDER BY NameIdPerson 表中从偏移量 20 开始获取 10 行。 .

    SELECT Person.*
    FROM Person
    WHERE Person.Id In 
          (
            SELECT TOP 10 A.Id
            FROM [
                   SELECT TOP 30 Person.Name, Person.Id
                   FROM Person
                   ORDER BY Person.Name, Person.Id
                 ]. AS A
            ORDER BY A.Name DESC, A.Id DESC
          )
    ORDER BY Person.Name, Person.Id;
    

    本质上,我们查询前 30 个,倒序,查询前 10 个,然后从表中选择匹配的行,再次按正序排序。这应该是相当有效的,假设 IdPRIMARY KEY,并且 Name 上有一个索引。可能需要针对 NameId(而不是仅针对 Name)的特定覆盖索引以获得最佳性能,但我认为索引隐含地覆盖了PRIMARY KEY

    【讨论】:

    • 但是考虑到限制是 10 并且有 11 行,偏移量 10 实际上会返回除第一行之外的所有行 (10)。所以它与队列机制非常相似——你只需弹出第一个元素,最后一个被推送。但想法是在偏移量为 10 时仅显示一个(最后)行,而您的查询不会这样做。
    【解决方案2】:

    另一种方式 - 假设您希望在一个名为 table1 的表中包含 1000 到 1999 条记录(当然,如果您有那么多记录),您可以这样做。

    MSSQL

    SELECT *
        FROM table1 LIMIT 1000, 1999;
    

    MS 访问

    SELECT TOP 1000 * 
    FROM table1 
    Where ID NOT IN (SELECT TOP 999 table1.ID FROM table1);
    

    分解一下

    SELECT TOP NumA * 
    FROM table1 
    Where ID NOT IN (SELECT TOP NumB table1.ID FROM table1);
    
    UpperLimit = 1999
    
    LowerLimit = 1000
    
    NumA = UpperLimit - LowerLimit + 1
    

    例如。 1000 = 1999 - 1000 + 1

    NumB = LowerLimit -1
    

    例如。 999 = 1000 - 1

    【讨论】:

      【解决方案3】:

      更好的查询是:

      SELECT Users.*
      FROM Users
      WHERE Users.id In 
            (
              SELECT TOP X A.id
              FROM [
                     SELECT TOP Y Users.*
                     FROM Users
                     ORDER BY Users.reg_date DESC
                   ]. AS A
              ORDER BY A.reg_date ASC
            )
      ORDER BY Users.reg_date DESC
      

      在哪里

      if((totalrows - offset) < limit) then
          X = (totalrows - offset)
      else
          X = limit
      

      还有:

      Y = limit + offset
      

      例如,如果 total_rows = 12,我们将 limit 设置为 10(每页显示 10 个用户),并且 limit strong>offset 计算为 p * limit - (limit) 其中 p 是当前页面的编号,因此在第一页 ( p = 1) 我们将得到:X = 12Y = 10,在第二个 X = 2 >Y = 20。用户列表按注册日期排序(降序)。

      【讨论】:

      • 当使用 TOP 进行分页时,最好在排序中包含主键作为决胜局并确保可预测的排序。
      • 看起来不错,除了我认为 X 应该是限制的最大值或(total_count - 偏移量)。否则,除非您查询最后一页,否则您最终会得到比预期更多的结果行。
      • @Steve Jorgensen 关于主键 - 你是完全正确的。我只是想为自己简化对这个“技巧”的理解。 X 评论怎么样 - 我不太明白你在这里。这很好,因为如果我们以我发布的示例为例,最后一页(page = 2)的查询将是SELECT TOP 2 以上SELECT TOP 20,实际上只会给您预期的两个结果。它永远不会重复前几页中的行,因为它是由total_rows - offset 计算的。所以对我来说一切都很好。
      • X 计算的问题是当您不在最后一页时会发生什么。如果您总共有 35 行,并且您希望 offset=11,limit=10,那么使用 X 和 Y 的规则,X 将为 24,Y 将为 21。结果,您将返回 21 行。 X 仅应为 total_count - 偏移量,当该数字
      • @Steve Jorgensen - 哦,对不起,你是对的。我选择你的答案是最好的,因为你给出了一个很好的解释。我认为如果您添加我在回答中提到的这一点会很好,以便其他人可以看到。再次感谢。
      【解决方案4】:

      简单快速的解决方案。

      myTable {ID*, Field2, Filed3...}


      1. 假设您的 SortOrder 仅包含 主键

        SELECT TOP PageItemsCount tb01.*
        FROM myTable AS tb01
         LEFT JOIN (
          SELECT TOP OffsetValue ID FROM myTable ORDER BY ID ASC
         ) AS tb02
        
         ON tb01.ID = tb02.ID
         WHERE ISNULL(tb02.ID)
         ORDER BY tb01.ID ASC
        

      1. SortOrder 基于具有重复值的其他字段,在这种情况下您必须在 SortOrder 中包含主键作为最后一个。

      例如,我的表

      +-------+--------+--------+
      | ID    | Field2 | Filed3 |
      +-------+--------+--------+
      | 1     | a1     | b      |
      | 2     | a      | b2     |
      | 3     | a1     | b2     |
      | 4     | a1     | b      |
      +-------+--------+--------+
      
      SELECT TOP 2 * From myTable ORDER BY FIELD2;
      +-------+--------+--------+
      | ID    | Field2 | Filed3 |
      +-------+--------+--------+
      | 2     | a      | b2     |
      | 4     | a1     | b      |
      | 3     | a1     | b2     |
      | 1     | a1     | b      |
      +-------+--------+--------+
      SELECT TOP 2 * From myTable ORDER BY FIELD2, FIELD3;
      +-------+--------+--------+
      | ID    | Field2 | Filed3 |
      +-------+--------+--------+
      | 2     | a      | b2     |
      | 4     | a1     | b      |
      | 1     | a1     | b      |
      +-------+--------+--------+
      

      但如果我们将 ID 添加到排序顺序 [AS LAST IN FIELDS LIST]

      SELECT TOP 2 * From myTable ORDER BY FIELD2, ID;
      +-------+--------+--------+
      | ID    | Field2 | Filed3 |
      +-------+--------+--------+
      | 2     | a      | b2     |
      | 1     | a1     | b      |
      +-------+--------+--------+
      

      最终请求

            SELECT TOP PageItemsCount tb01.*
              FROM myTable AS tb01
      
              LEFT JOIN (
                SELECT TOP OffsetValue ID FROM myTable ORDER BY Field2 ASC, ID
              ) AS tb02
      
              ON tb01.ID = tb02.ID
              WHERE ISNULL(tb02.ID)
              ORDER BY tb01.Field2 ASC, tb01.ID
      

      【讨论】:

        【解决方案5】:

        您绝对可以使用 top 关键字获得“限制”的等价物。见:
        Access Database LIMIT keyword

        【讨论】:

        • Top 关键字没有 MySQL Limit 关键字的两个参数
        • 我确实知道TOP 关键字,并且我尽可能使用它。但是我无法模仿OFFSET。这就是重点。
        • @CameronS 和@msgdie 众所周知,MySQL 的LIMIT 可以通过TOP 的组合获得,例如看Steve Jorgensen 的回答。对于@Zeki,您的回答并不完整,它看起来更像是评论,并且您提供的链接并不真正涉及有关LIMIT 的问题。请详细说明如何获得LIMIT 的模拟,我会投票给你。
        【解决方案6】:

        不,JET SQL 没有直接等效项。作为一种解决方法,您可以添加一个WHERE 子句,在两个值之间选择一个有序/id 列。

        如果可能,您还可以对现有 MySQL/其他数据库使用直通查询。

        虽然 MS-Access 中的 TOP 可以限制返回的记录,但它不像 MySQL 的 LIMIT 关键字那样需要两个参数(参见 this question)。

        【讨论】:

        • 谢谢。讨厌 MS Access 的另一个原因。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多