【问题标题】:MySql - How get value in previous row and value in next row? [duplicate]MySql - 如何获取上一行的值和下一行的值? [复制]
【发布时间】:2013-12-30 23:07:13
【问题描述】:

我有下表,名为Example

id(int 11) //not autoincriment
value (varchar 100)

它有以下几行数据:

0  100
2  150
3  200
6  250
7  300

请注意,id 值不是连续的。

到目前为止,我已经编写了这个 SQL:

SELECT * FROM Example WHERE id = 3

但是,我不知道如何获取上一个id 的值和下一个id 的值...

如果id = 3,请帮我获取上一个值和下一个值?

P.S.:在我的示例中,它将是:上一个 - 150,下一个 - 250

【问题讨论】:

  • 你想要一排还是三排的值?
  • 不是投反对票的人,而是你尝试过什么,为什么要这样做?
  • @SlyRaskal 抱歉,我现在更新问题
  • @Bohemian 例如我有 id=3(不是自动添加),现在我想获得前一个 id 的值和下一个 id 的值。
  • @SlyRaskal 我更新问题

标签: mysql sql


【解决方案1】:

一种解决方案是使用临时变量:

select 
    @prev as previous,
    e.id,
    @prev := e.value as current
from
    (
        select
            @prev := null
    ) as i,
    example as e
order by
    e.id

要获得“下一个”值,请重复该过程。这是一个例子:

select 
  id, previous, current, next
from
  (
    select
      @next as next,
      @next := current as current,
      previous,
      id
    from
      (
        select @next := null
      ) as init,
      (
        select
          @prev as previous,
          @prev := e.value as current,
          e.id
        from
          (
            select @prev := null
          ) as init,
          example as e
        order by e.id
      ) as a
    order by
      a.id desc
  ) as b
order by
  id

查看the example on SQL Fiddle

可能有点矫枉过正,但它可能会帮助你

【讨论】:

  • 那是一个很好的(y)
  • @Barranka 它不再起作用了。您可以在 SQL Fiddle with MySQL 5.6 上查看它。上一个和下一个显示一些 Blob 值而不是正确的值。
  • 通过将第二行替换为:id, CONVERT(previous USING utf8), current, CONVERT(next USING utf8) 来修复它
  • 请注意,如果查询以某种方式包含变量组,则评估方式不同,这将不起作用。您需要包装您的查询。
【解决方案2】:

选择下面的下一行:

SELECT * FROM Example WHERE id < 3 ORDER BY id DESC LIMIT 1

选择上面的下一行:

SELECT * FROM Example WHERE id > 3 ORDER BY id LIMIT 1

在一个查询中同时选择两者,例如使用UNION:

(SELECT * FROM Example WHERE id < 3 ORDER BY id DESC LIMIT 1)
 UNION
(SELECT * FROM Example WHERE id > 3 ORDER BY id LIMIT 1)

你的意思是?

【讨论】:

    【解决方案3】:
    SELECT *,
           (SELECT value FROM example e1 WHERE e1.id < e.id ORDER BY id DESC LIMIT 1 OFFSET 0) as prev_value,
           (SELECT value FROM example e2 WHERE e2.id > e.id ORDER BY id ASC LIMIT 1 OFFSET 0) as next_value
    FROM example e
    WHERE id=3;
    

    如果您想为所选记录中的下一个和上一个值选择具有更高偏移量的记录,您可以在 OFFSET 关键字之后放置您自己的偏移量。

    【讨论】:

    • @Strawberry 随时欢迎更好的答案! (我有同样的问题,我想要最好的工作答案,所以最后我发现这个答案在我的情况下很完美,我在这里分享了它)希望它可以帮助某人更容易找到最佳答案。
    • 如果你这么说。我认为最佳答案比这更好。
    • @Strawberry 我尊重你的选择,但在某些情况下(比如当你想要两行或计算的差异时)我的回答对在同一行上进行计算更有帮助。
    • @Strawberry 假设一本书的章节!例如,如果你有一个带有 chapter_id 和 chapter_page_number 的表,你想显示当前章节的页数怎么办!计算公式为next_chapter_page_number - chapter_page_number。你仍然使用最佳答案吗?如果是这样,那怎么办?
    • 如果您有问题,建议您提出问题 - 使用正确的 DDL 和期望的结果!
    【解决方案4】:

    我的解决方案可能适合你:

    SELECT * FROM Example
    WHERE id IN (
    (SELECT MIN(id) FROM Example WHERE id > 3),(SELECT MAX(id) FROM Example WHERE id < 3)
    )
    

    演示:http://sqlfiddle.com/#!9/36c1d/2

    【讨论】:

      【解决方案5】:

      请试试这个sqlFiddle

      SELECT value,
             (SELECT value FROM example e2
              WHERE e2.value < e1.value
              ORDER BY value DESC LIMIT 1) as previous_value,
             (SELECT value FROM example e3
              WHERE e3.value > e1.value
              ORDER BY value ASC LIMIT 1) as next_value
      FROM example e1
      WHERE id = 3
      

      编辑:OP 提到在其中一个 cmets 中获取前一个 id 的值和下一个 id 的值,所以代码在这里 SQLFiddle

      SELECT value,
            (SELECT value FROM example e2
             WHERE e2.id < e1.id
             ORDER BY id DESC LIMIT 1) as previous_value,
            (SELECT value FROM example e3
             WHERE e3.id > e1.id
             ORDER BY id ASC LIMIT 1) as next_value
      FROM example e1
      WHERE id = 3
      

      【讨论】:

      • 看起来很繁琐,但实际上它是最快的..我在这里与其他解决方案进行了比较
      • 嗯,在我的桌子上大约有。 16000 行,带变量的替代方案要快得多(MySQL 5.5 - 0.09s vs. 17s !)
      • 这个答案更灵活。无论如何,您实际上并不希望对 ID 进行排序。我正在使用不可排序的 UUID。我可以用 'sequence' 替换 'value' 并收紧内部选择以从 Postgres 获取正确的 Prev/Next 行。
      【解决方案6】:

      一个可能的解决方案,如果你需要它在一行中

      SELECT t.id, t.value, prev_id, p.value prev_value, next_id, n.value next_value
        FROM
      (
        SELECT t.id, t.value,
        (
          SELECT id
            FROM table1
           WHERE id < t.id
           ORDER BY id DESC
           LIMIT 1
        ) prev_id,
        (
          SELECT id
            FROM table1
           WHERE id > t.id
           ORDER BY id
           LIMIT 1
        ) next_id
          FROM table1 t
         WHERE t.id = 3
      ) t LEFT JOIN table1 p
           ON t.prev_id = p.id LEFT JOIN table1 n
           ON t.next_id = n.id 
      

      样本输出:

      |身份证 |价值 | PREV_ID | PREV_VALUE |下一个 ID | NEXT_VALUE | |----|-------|---------|------------|---------|--- ---------| | 3 | 200 | 2 | 150 | 4 | 250 |

      这里是SQLFiddle演示

      【讨论】:

        【解决方案7】:

        如果您没有 ID,这对我有用。

        下一步:

        SELECT * FROM table_name
        WHERE column_name > current_column_data
        ORDER BY column_name ASC
        LIMIT 1
        

        上一个:

        SELECT * FROM table_name
        WHERE column_name < current_column_data
        ORDER BY column_name DESC
        LIMIT 1
        

        我将其用于成员列表,其中搜索是在成员的姓氏上。只要您有当前记录中的数据,它就可以正常工作。

        【讨论】:

          【解决方案8】:

          此查询使用用户定义的变量来计算与目标 id 的距离,并使用一系列包装查询来获得您想要的结果。桌子上只有一次传球,所以它应该表现良好。

          select * from (
              select id, value from (
                  select *, (@x := ifnull(@x, 0) + if(id > 3, -1, 1)) row from (
                      select * from mytable order by id
                  ) x 
              ) y
              order by row desc
              limit 3
          ) z
          order by id
          

          查看SQLFiddle

          如果您不关心最后的行顺序,您可以省略最外层的包装查询。

          【讨论】:

          • 问题,当row 不在选定的列中时,order by row 如何工作?
          • @ejay(在所有数据库中)您可以按未选择的表达式排序
          猜你喜欢
          • 1970-01-01
          • 2020-04-13
          • 2011-06-19
          • 1970-01-01
          • 1970-01-01
          • 2021-04-16
          • 2014-10-29
          • 2022-01-03
          • 2016-02-03
          相关资源
          最近更新 更多