【问题标题】:Get previous and next row from rows selected with (WHERE) conditions从使用 (WHERE) 条件选择的行中获取上一行和下一行
【发布时间】:2015-01-21 01:48:51
【问题描述】:

例如我有这样的说法:

my name is Joseph and my father's name is Brian

这个语句是按单词分割的,像这张表:

------------------------------
|      ID      |   word      |
------------------------------
|       1      |   my        |
|       2      |   name      |
|       3      |   is        |
|       4      |   Joseph    |
|       5      |   and       |
|       6      |   my        |
|       7      |   father's  |
|       8      |   name      |
|       9      |   is        |
|       10     |   Brian     |
------------------------------

我想获取每个单词的上一个和下一个单词

例如我想获取“名称”的上一个和下一个单词:

--------------------------
|    my    |  name  |  is |
--------------------------
| father's |  name  |  is |
--------------------------

我怎样才能得到这个结果?

【问题讨论】:

  • 你的id有空缺吗?
  • 您使用的是什么数据库?您使用的是哪个版本的数据库? SQL 是一种语言,但几乎每个数据库都支持稍微不同的 SQL 方言。当您使用支持 leadlag 等分析功能的数据库时,这种事情会容易得多。
  • 我使用 SQL 2012,支持 LAG 和 LEAD,但我想快速获取 500 万字的结果,在我的程序中快速获取结果很重要

标签: sql sql-server sql-server-2012 rows


【解决方案1】:

为什么没有人给出简单的答案?

SELECT LAG(word) OVER ( ORDER BY ID ) AS PreviousWord ,
       word ,
       LEAD(word) OVER ( ORDER BY ID ) AS NextWord
FROM   words;

【讨论】:

  • 您未能将结果限制为特定单词的下一个/上一个。接受的答案有一个WHERE 子句。
【解决方案2】:

没有子查询:

SELECT a.word 
FROM my_table AS a
JOIN my_table AS b 
ON b.word = 'name' AND abs(a.id - b.id) <= 1
ORDER BY a.id

【讨论】:

  • 如果 id 序列有间隙,这将不起作用
  • @t-clausen.dk op 说表格是拆分句子创建的,所以不应该有任何差距
  • 额外的列 ROW_NUMBER() OVER (ORDER BY id) 就可以了
【解决方案3】:

使用Join 得到SQL Server 2005 plus 的预期结果。

    create table words (id integer, word varchar(20));

    insert into words
    values
    (1 ,'my'),
    (2 ,'name'),
    (3 ,'is'),
    (4 ,'joseph'),
    (5 ,'and'),
    (6 ,'my'),
    (7 ,'father'),
    (8 ,'name'),
    (9 ,'is'),
    (10,'brian');

SELECT A.Id ,  C.word AS PrevName , 
               A.word AS CurName , 
               B.word AS NxtName 
FROM words AS A
LEFT JOIN words AS B ON A.Id = B.Id - 1
LEFT JOIN words AS C ON A.Id = C.Id + 1
WHERE A.Word = 'name'

结果:

Fiddler Demo

【讨论】:

    【解决方案4】:

    如果您希望快速选择,这是一种不同的方法。这需要一些准备工作。

    • 在数据库中创建一个包含单词的新列(例如“短语”) 你要。 (即上一个、当前和下一个)。

    • 编写一个触发器,在插入时将新单词附加到前一个单词 行的短语并将前一行的单词添加到新行的单词并填充 短语。

    • 如果个别字词可以更改,您需要触发更新以保持短语同步。

    然后只需选择短语。您可以获得更快的速度,但代价是额外的存储空间、更慢的插入速度和更难的可维护性。显然,您必须更新现有记录的短语列,但您可以在其他答案中使用 SQL 来执行此操作。

    【讨论】:

      【解决方案5】:

      你没有指定你的 DBMS,所以下面是 ANSI SQL:

      select prev_word, word, next_word
      from (
          select id, 
                 lag(word) over (order by id) as prev_word,
                 word,
                 lead(word) over (order by id) as next_word
          from words
      ) as t
      where word = 'name';
      

      SQLFiddle:http://sqlfiddle.com/#!12/7639e/1

      【讨论】:

      • 使用此代码,在内部选择语句中,表的整行被合并,在外部:选择具有相同单词的行,如果我只想取一个单词,所有表单词都被合并然后选择一个其中...
      • 没关系,但我有超过 1 亿条记录,并且获取结果的时间非常重要,我可以提高这段代码的性能
      • @mahdiyousefi:请为此创建一个新问题。
      【解决方案6】:

      试试这个

      SELECT *
      FROM   tablename a
      WHERE  ID IN(SELECT ID - 1
                   FROM   tablename 
                   WHERE  word = 'name') -- will fetch previous rows of word `name` 
              OR ID IN(SELECT ID + 1
                       FROM   tablename 
                       WHERE  word = 'name') -- will fetch next rows of word `name`
              OR word = 'name' -- to fetch the rows where word = `name`
      

      【讨论】:

      • 没关系,但是我有超过一亿条记录,并且获取结果的时间很重要,我可以提高代码的性能吗?
      猜你喜欢
      • 1970-01-01
      • 2020-12-28
      • 1970-01-01
      • 1970-01-01
      • 2021-05-30
      • 2011-05-02
      • 1970-01-01
      • 2015-03-13
      相关资源
      最近更新 更多