如何使用子查询加入自联接?

时间:2017-10-12 16:07:15

标签: mysql sql

数据:

create table `values` (
     id integer unsigned primary key auto_increment,
     value double,
     `time` time
);

insert into `values` (time, value) values
  ('00:00:01', 1),
  ('00:00:02', 2),
  ('00:00:03', 3),
  ('00:01:01', 4),
  ('00:01:02', 5),
  ('00:01:03', 6);

和同一个http://sqlfiddle.com/#!9/ec3e8/1的小提琴

SELECT
    vs1.time as t1,
    vs1.value as v1,
    vs2.time as t2,
    vs2.value as v2
FROM `values` vs1, `values` vs2
JOIN (
    SELECT MIN(time) as mint, MAX(time) as maxt FROM `values`
    GROUP BY hour(time), minute(time)
) as te on vs1.time = te.mint AND vs2.time = te.maxt
WHERE vs1.id != vs2.id AND hour(vs1.time) = hour(vs2.time) AND minute(vs1.time) = minute(vs2.time)

我在mysql中有一个时间序列数据。我想用一个SQL查询来聚合它的一些统计信息。我希望按时间分组值,然后从组中获取最小值,最大值,第一个和最后一个值。

我知道mysql没有聚合函数,ctes,第一个和最后一个函数,否则这将是微不足道的。

所以我的计划是创建所有行的产品(连接表自身)然后用每个间隔的最小和最大时间连接它以从间隔获得第一个和最后一个值,但这会给出错误。

Unknown column 'vs1.time' in 'on clause'

我的查询有什么问题?并且可以使用相同的行产品来获得最小值和最大值,还是需要使用group by加入另一个查询?

另一种选择是用某种编程语言制作程序。程序不是一种选择。我想比较原始SQL的性能并在编程语言中进行此操作。

这应该适用于mysql 5.6。

1 个答案:

答案 0 :(得分:2)

您正在将1992年以前的逗号分隔连接语法与正确的ANSI连接混合,您不应该这样做。文档(https://dev.mysql.com/doc/refman/5.7/en/join.html)明确说明:

  
    

但是,逗号运算符的优先级小于INNER JOIN,CROSS JOIN,LEFT JOIN等的优先级。如果在存在连接条件时将逗号连接与其他连接类型混合,则可能会出现'on子句'中未知列'col_name'形式的错误。

  

CROSS JOIN替换逗号使其有效:FROM `values` vs1 CROSS JOIN `values` vs2

然而,我发现你的大多数情况都是多余的。另外,为了便于阅读,更改连接顺序(特别是为了不假装交叉连接):

SELECT
    vs1.time as t1,
    vs1.value as v1,
    vs2.time as t2,
    vs2.value as v2
FROM 
(
  SELECT MIN(time) as mint, MAX(time) as maxt 
  FROM `values`
  GROUP BY hour(time), minute(time)
) as te
JOIN `values` vs1 ON vs1.time = te.mint
JOIN `values` vs2 ON vs2.time = te.maxt
ORDER BY vs1.time;