Mysql 使用WHERE子句从上一个匹配行查询差异

Mysql 使用WHERE子句从上一个匹配行查询差异,mysql,Mysql,要将一行与前一行区分开来,我要将一个表连接到它自己,并与前一个id(主键)进行比较: 我如何将其限制为数据的特定子集?例如,如果表中添加了一列user VARCHAR(32),如何将查询限制为仅区分特定用户?在两个SELECT查询中添加一个简单的WHERE子句将不起作用,因为整个前提取决于顺序ids。我想我可以将数据移动到一个临时表中,但是如果有一个更干净、更高效的解决方案,那么我会使用它 我的意图是添加一个WHERE user='someUser'子句,对于该子句,diff将仅对特定用户而不是

要将一行与前一行区分开来,我要将一个表连接到它自己,并与前一个
id
(主键)进行比较:

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

我的意图是添加一个
WHERE user='someUser'
子句,对于该子句,diff将仅对特定用户而不是整个表进行diff


这是一张工作票。我想修改此查询,使其仅适用于
WHERE name='a'
,因此结果将是
id=9,data=305,diff=125

这不是一个好的做法,但有时我会像这样加入半联接

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;

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

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;
给你:

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)
如果previous为
NULL
,则返回列数据的值。因此,没有前一行的行的差异为零

如果您还有更多问题,请随时提问

备注:此查询可能比您必须自行加入的查询更快。

给您:

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)
如果previous为
NULL
,则返回列数据的值。因此,没有前一行的行的差异为零

如果您还有更多问题,请随时提问


附言:这个查询可能比你必须自行加入的查询更快。

如果我正确理解你的问题,我认为你应该使用如下方式:

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
请看小提琴。这是标准的SQL,应该适用于任何DBMS

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

SELECT   id, data data_curr,
         data -
         (SELECT data FROM tablename WHERE name='a' ORDER BY id DESC LIMIT 1,1) data_diff
FROM     tablename
WHERE    name='a'
ORDER BY id DESC
LIMIT 1

请看。

如果我正确理解了你的问题,我认为你应该使用以下内容:

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
请看小提琴。这是标准的SQL,应该适用于任何DBMS

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

SELECT   id, data data_curr,
         data -
         (SELECT data FROM tablename WHERE name='a' ORDER BY id DESC LIMIT 1,1) data_diff
FROM     tablename
WHERE    name='a'
ORDER BY id DESC
LIMIT 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

演示

给定您的数据,数据字段的值似乎在上升,差值应始终为正值

这应该行得通

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

演示

您也可以这样做-尽管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;

您也可以这样做-虽然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;

谢谢Raheel Shan,但这不允许我将查询限制为仅针对特定用户进行差异化。我会让问题的这一部分更清楚。谢谢Raheel Shan,但这不允许我将查询限制为仅针对特定用户进行差异化。我会让问题的这一部分更清楚。期望结果中的id是9。您的sqlfiddle中没有16行。只是说说而已,所以没有人感到困惑。不编辑我自己,因为我提供了答案,没有人会说我作弊:)谢谢tombom,你是正确的,我做了编辑。期望结果中的id是9。您的sqlfiddle中没有16行。只是说说而已,所以没有人感到困惑。不编辑自己,因为我提供了答案,没有人会说我作弊:)谢谢tombom,你是正确的,我做了编辑。谢谢,这太棒了。我不知道如何使用
COALESCE
,我喜欢你对MySQL会话变量的雄辩使用。这是一个非常有用的答案,有一个非常聪明的解决方案。谢谢你tombom!谢谢,这太棒了。我不知道如何使用
COALESCE
,我喜欢你对MySQL会话变量的雄辩使用。这是一个非常有用的答案,有一个非常聪明的解决方案。谢谢你tombom!谢谢你,阿卡什。这似乎返回了最后的差异,而不是最高的差异。谢谢你,阿卡什。这似乎返回了最后的差异,而不是最高的差异。谢谢,这很有创意。谢谢,这很有创意。