使用WHERE子句从上一个匹配行查询diff

时间:2013-03-18 11:14:01

标签: mysql

要与前一行区分一行,我JOIN将一个表{self}并与之前的id(主键)进行比较:

CREATE TABLE `tablename` (
    id INT(5) PRIMARY KEY AUTO_INCREMENT,
    data INT
);

SELECT t1.id, t1.data, t1.data-(SELECT data FROM tablename WHERE id=t1.id-1) AS diff
FROM tablename t1 LEFT JOIN tablename t2 ON t1.id = t2.id
ORDER BY diff DESC LIMIT 1;

如何将此限制仅限于特定的数据子集?例如,如果将列user VARCHAR(32)添加到表中,我如何将查询限制为仅区分特定用户?为两个SELECT查询添加一个简单的WHERE子句将不起作用,因为整个前提依赖于顺序id。我想我可以将数据移动到临时表中,但如果有更清洁,更有效的解决方案,那么我会使用它。

我的意图是添加一个WHERE user='someUser'子句,diff只为特定用户而不是整个表区分。

这是一个有效的sqlfiddle。我想修改此查询,使其仅适用于WHERE name='a',因此结果为id=9, data=305, diff=125

5 个答案:

答案 0 :(得分:2)

你走了:

SELECT id, data, data - COALESCE(previous, data) as diff FROM (
SELECT
t.*,
@prev AS previous,
@prev:=t.data 
FROM
tablename t
, (SELECT @prev:=NULL) var
where name = 'a'
)sq
order by diff desc
limit 1

说明:

, (SELECT @prev:=NULL) var

变量的初始化。

@prev AS previous,
@prev:=t.data 

在第一列中输出变量的当前值,在第二列中分配当前行的值。

COALESCE(previous, data)

如果之前是NULL,则返回列数据的值。因此,没有前一行的行的diff为零。

随意询问您是否有更多问题。

P.S。:这个查询甚至比你必须自我加入的查询更快。

答案 1 :(得分:2)

如果我理解你的问题,我认为你应该使用这样的东西:

SELECT t1.id, t1.data data_curr, t2.data data_prev, t1.data - t2.data data_diff
FROM (
  SELECT t1.id, t1.data, MAX(t2.id) max_id
  FROM
    tablename t1 INNER JOIN tablename t2
    ON t1.name = t2.name
       AND t1.id > t2.id
  WHERE
    t1.name = 'a'
  GROUP BY
    t1.id, t1.data
) t1 INNER JOIN tablename t2
  ON t1.max_id = t2.id

请参阅小提琴here。这是标准SQL,适用于任何DBMS。

但是,如果您只需要LAST diff数据,则可以在主查询中使用LIMIT 1(按ID DESC排序)以获取name ='a'的最后一个数据,然后{{1}获取倒数第二个数据:

LIMIT 1,1

请看here

答案 2 :(得分:1)

鉴于您的数据,似乎数据字段的值正在上升,差异应始终为正值

这应该有效

SELECT 
  id, 
  max(data)-min(data) as diff,
  max(data) as data
  name
FROM
  (
    SELECT
      id,
      data,
      name 
    FROM 
      tablename 
    WHERE 
      name = 'a' 
    ORDER BY
      id desc 
    LIMIT 2 
  ) t
GROUP BY 
  name

SQLFiddle演示

答案 3 :(得分:1)

你也可以这样做 - 虽然tombom的版本可以更好地扩展......

 SELECT a.id
      , a.data
      , a.name
      , a.data-b.data ttl
   FROM
      ( SELECT x.* 
             , COUNT(*) rank 
          FROM tablename x 
          JOIN tablename y 
            ON y.name = x.name 
           AND y.id >=x.id 
         GROUP 
            BY x.id
      ) a
   JOIN
      ( SELECT x.* 
             , COUNT(*) rank 
          FROM tablename x 
          JOIN tablename y 
            ON y.name = x.name 
           AND y.id >=x.id 
         GROUP 
            BY x.id
      ) b
     ON b.name = a.name
    AND b.rank = a.rank + 1
  WHERE a.rank = 1;

答案 4 :(得分:0)

嗯,这不是一个好习惯,但我有时会像这样加入半连接

SELECT
  t1.id,
  t1.data,
  t1.data- t3.data AS diff
FROM tablename t1
  LEFT JOIN tablename t2
    ON t1.id = t2.id
  LEFT JOIN tablename t3
    ON t3.data = (SELECT
            data
          FROM tablename
          WHERE id > t1.id
          LIMIT 1)
ORDER BY diff DESC
LIMIT 1;