【问题标题】:Select rows before multiple ids选择多个 id 之前的行
【发布时间】:2012-08-28 01:56:33
【问题描述】:

我想在具有指定值的行之前获取 2 个行 ID。

所以我在一个表中有 ID 和值

ID   value
1,   x
3,   x 
7,   x
8,   error
9,   x
10.  x
11,  x
12   error

我想要错误前的两行。

我可以使用硬编码的错误行 ID 来做到这一点

SELECT id FROM thetable WHERE id < 8 ORDER BY ID DESC LIMIT 2  
UNION ALL
SELECT id FROM thetable WHERE id < 12 ORDER BY ID DESC LIMIT 2

但是我无法对错误 ID 进行硬编码,我该如何做到这一点,例如将其与 SELECT id FROM thetable WHERE value = 'error' 或任何其他方式结合使用?

我使用 sqlite 3,但我对一切都很感兴趣。

【问题讨论】:

  • 您之前的七个问题的答案都不能接受吗?
  • 我写过:这是 sqlite3
  • 对不起,我忘记接受答案(或者不知道,我必须这样做)。我现在就做!谢谢!

标签: sql database sqlite union


【解决方案1】:

SQL Fiddle Demo


我不知道 sqllite 是否具有排名功能,这会使解决方案变得更容易,但以下语句应该适用于任何符合 ANSI-92 的 DBMS。

解决方案的要点是

  • 第一步:获取所有error的ID
  • 第二步:使用 GROUP BY 子句获取所有 ID 的
  • 第 3 步:与第 2 步类似,但下降了一个级别。

SQL 语句

SELECT  ID
FROM    (
              -- Select the ROOT value
              SELECT  ID, 0 AS GroupID
              FROM    thetable
              WHERE   value = 'error'
              UNION ALL

              -- Selects the ROOT value - 1 
              SELECT  MAX(t.ID) AS ID, te.ID AS GroupID
              FROM    thetable AS t
                      INNER JOIN (
                        SELECT  ID
                        FROM    thetable
                        WHERE   value = 'error'
                      ) AS te ON te.ID > t.ID 
              GROUP BY
                      te.ID

              UNION ALL        

              -- Selects the ROOT value - 1 - 1 
              SELECT  MAX(t.ID), te.ID
              FROM    thetable AS t
                      INNER JOIN (        
                        SELECT  MAX(t.ID) AS ID, te.ID AS GroupID
                        FROM    thetable AS t
                                INNER JOIN (
                                  SELECT  ID
                                  FROM    thetable
                                  WHERE   value = 'error'
                                ) AS te ON te.ID > t.ID 
                        GROUP BY
                                te.ID
                      ) AS te ON te.ID > t.ID
              GROUP BY
                      te.ID
            ) AS t                  

ORDER BY
        ID

编辑

FWIW:如果 SQLite 允许排名函数和 cte 的,下面的语句返回相同的结果,但更简洁。

;WITH q AS (
  SELECT  ROW_NUMBER() OVER (ORDER BY ID) rn
          , ID
          , value
  FROM    thetable 
)
SELECT  q2.ID
FROM    q q1
        INNER JOIN q q2 ON q2.rn BETWEEN q1.rn - 2 AND q1.rn
WHERE   q1.value = 'error'

【讨论】:

  • 我需要一点时间 :) 谢谢
  • 我不能使用第二个,因为 sqlite 中不存在 ROW_NUMBER() 或等值项。 (如果我读得很好),我会尝试第一个
  • 好的,第一种方法在集成后的sqlite上也很好。只是有点太大了,我必须理解。谢谢,我会用的!
  • 这里的第一条语句没问题,但是当我不想例如错误前的 5 行和错误后的 2 行时,它真的很大。它可以在 sqlite 上更小吗?
  • @ald mike - 我对 sqlite 没有任何经验,但如果排名功能可用(如 jaycahpani 的回答中提到的 rowid),应该可以缩短它。
【解决方案2】:

我是 SQLite 的新手,所以我不知道它的语法和所有内容。但是试试下面的代码是否适合你

select id,value
from (select *,rowid rid from tbl
order by id)
where rid in
(
  select rowid-1 from tbl
  where value = 'error'
  order by id
)or rid in
(
  select rowid-2 from tbl
  where value = 'error'
  order by id
)

DEMO

【讨论】:

  • @aldmike 有什么问题?我已经处理了这种情况并检查了我的演示??
  • 你的演示没问题,我已经删除了我的评论。我现在需要一点时间来整合和检查灵魂 :) 谢谢
  • @aldmike 如果你觉得这个解决方案没问题,那就把它标记为答案,以便其他人可以参考。
  • +1 我现在不知道 SQLLite 中的 rowid 函数,但是这个 (正如我在回答中提到的) 使解决方案更具可读性。请注意,您没有自己选择实际错误行,但这很容易添加。
  • 哦不,不好,因为我的ID也是rowid。因为:“如果一个表包含一个 INTEGER PRIMARY KEY 类型的列,那么该列将成为 ROWID 的别名。然后您可以使用四个不同名称中的任何一个来访问 ROWID,即上面描述的原始三个名称或赋予INTEGER PRIMARY KEY 列。所有这些名称都是彼此的别名,并且在任何情况下都同样有效。”如果在错误之前跳过了一个 ID,那么我无法得到这两行
【解决方案3】:

试试这个:

SELECT id 
FROM thetable 
ORDER BY 
   CASE WHEN value = 'error' THEN value ELSE ID END
 DESC 

【讨论】:

    【解决方案4】:
    select id, value 
    from test where id in (select id-1 from test where value = 'error')
    

    如果您总是寻找错误背后的第一个 id,这将起作用。如果您可能会跳过一个 id,您可以使用 MIN 函数来获取最接近的现有 id。

    【讨论】:

    • 它可能会发生,不幸的是我不知道如何使用 MIN 函数解决。
    猜你喜欢
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 2021-08-03
    • 2018-11-07
    • 2014-12-24
    • 1970-01-01
    • 2015-10-27
    • 1970-01-01
    相关资源
    最近更新 更多