MySQL-按时间获取最后一个条目(如果为空,则获取第一个条目)

MySQL-按时间获取最后一个条目(如果为空,则获取第一个条目),mysql,sql-server,cross-apply,Mysql,Sql Server,Cross Apply,我有以下SQL Server 2008查询: SELECT T.*,Data.Value FROM [Table] T OUTER APPLY (SELECT TOP 1 E.Value FROM [Table2] E ORDER BY CASE WHEN T.TDateTime >= E.EDateTime then 1 else 2 end, ABS(DateDiff(ss,T.TDateTime,E.EDatetime))) AS Data 这基本上得到了T

我有以下SQL Server 2008查询:

SELECT T.*,Data.Value FROM [Table] T OUTER APPLY      

(SELECT TOP 1 E.Value FROM [Table2] E     
ORDER BY CASE WHEN T.TDateTime >= E.EDateTime then 1 else 2 end,
ABS(DateDiff(ss,T.TDateTime,E.EDatetime))) AS Data
这基本上得到了T中每个记录的最后一个E值,但是如果T中的记录在E中的第一个记录之前,那么它得到了E中的第一个记录

MySQL中的等价物是什么

编辑

以下是我的模式和数据:

DROP TABLE IF EXISTS `data`;
CREATE TABLE `data` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `DataDateTime` datetime DEFAULT NULL,
  `Value` int(11) DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;


LOCK TABLES `data` WRITE;
INSERT INTO `data` VALUES (1,'2012-02-01 00:00:00',1),(2,'2012-03-01 01:00:00',2),(3,'2012-04-01 02:00:00',3),(4,'2012-05-01 03:00:00',4),(5,'2012-06-01 04:00:00',5),(6,'2012-07-01 05:00:00',6),(7,'2012-08-01 06:00:00',7),(8,'2012-09-01 07:00:00',8);
UNLOCK TABLES;


DROP TABLE IF EXISTS `t`;
CREATE TABLE `t` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `TDateTime` datetime DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

LOCK TABLES `t` WRITE;
INSERT INTO `t` VALUES (1,'2012-01-01 00:00:00'),(2,'2012-02-01 00:00:00'),(3,'2012-02-01 12:00:00'),(4,'2012-03-01 00:00:00'),(5,'2012-04-01 00:00:00'),(6,'2012-05-01 12:00:00'),(7,'2012-06-01 00:00:00'), (8,'2012-07-01 00:00:00');
UNLOCK TABLES;
SQLFiddle:

我的期望输出:

小组讨论

此链接可能会有所帮助:

您可以交叉连接t和数据,然后根据SQL Server查询中ORDER BY的等效值对每个t行的数据行进行排序

DATEDIFFss、dt1、dt2部分可以替换为UNIX_timestamdt2-UNIX_timestamdt1。排名可以使用变量来实现。以下是我尝试的解决方案:

SELECT
  ID,
  TDateTime,
  DataDateTime,
  Value
FROM (
  SELECT
    ID,
    TDateTime,
    DataDateTime,
    Value,
    @rnk := @rnk * (@lastid = ID) + 1 AS rnk,
    @lastid := ID
  FROM (
    SELECT
      t.ID,
      t.TDateTime,
      data.DataDateTime,
      data.Value
    FROM
      t CROSS JOIN data,
      (SELECT @lastid := 0, @rnk := 0) s
    ORDER BY
      t.ID,
      (t.TDateTime >= data.DataDateTime) DESC,
      ABS(UNIX_TIMESTAMP(t.TDateTime) - UNIX_TIMESTAMP(data.DataDateTime))
  ) s
) s
WHERE
  rnk = 1
;
您可以找到一个工作演示。

这是我提交的内容:

select *, if(Segment1Time<=ifnull(Segment2Time,Segment1Time),
             Segment1Value,
             Segment2Value) Value
from
(
  select *,
    (select DataDateTime from `data` where DataDateTime<=t.TDateTime order by DataDateTime desc limit 1) Segment1Time,
    (select Value from `data` where DataDateTime<=t.TDateTime order by DataDateTime desc limit 1) Segment1Value,
    (select DataDateTime from `data` where DataDateTime> t.TDateTime order by DataDateTime limit 1) Segment2Time,
    (select Value from `data` where DataDateTime> t.TDateTime order by DataDateTime limit 1) Segment2Value
  from `t` t
) X
order by tdatetime;

我花了一段时间才理解这些要求。最后,开始使用外部应用程序分析基本查询,并将其更改为:

SELECT t.*, data.*
  FROM t
  JOIN (SELECT t_ID = t.ID, 
        data_ID = ISNULL((SELECT TOP 1 ID FROM data WHERE data.DataDateTime <= t.TDateTime ORDER BY DataDateTime DESC),
                         (SELECT TOP 1 ID FROM data WHERE data.DataDateTime > t.TDateTime ORDER BY DataDateTime ASC))
   FROM t) lnk
    ON lnk.t_ID = t.ID
  JOIN data
    ON data.ID = lnk.data_ID
  ORDER BY t.ID
但执行计划显示它的效率较低,这让我有点吃惊。然而,在DataDateTime上添加索引会极大地改变这一点,这在MSSQL版本上可能很有用

无论如何,从这里开始,我在MySQL中创建了以下内容:

SELECT t.*, data.*
  FROM t
  JOIN (SELECT t.ID t_ID, 
           COALESCE((SELECT ID FROM data WHERE data.DataDateTime <= t.TDateTime ORDER BY DataDateTime DESC LIMIT 1),
                           (SELECT ID FROM data WHERE data.DataDateTime > t.TDateTime ORDER BY DataDateTime ASC LIMIT 1)) data_ID
   FROM t) lnk
    ON lnk.t_ID = t.ID
  JOIN data
    ON data.ID = lnk.data_ID
  ORDER BY t.ID

似乎做了预期的事情…

不幸的是,这无助于我取得成绩。在某些情况下,GROUP_CONCAT会起作用,但据我所知,外部应用/交叉应用不是SQL标准的一部分。如果错误,请更正我。它是一个特定于M$SQL server的函数。这是供应商锁定的典型症状。希望你能找到解决办法。是的,我知道!希望还有另一种方法。如果这可以通过另一种方法来实现,我洗耳恭听。你能在上面的'T'和'E'中包含模式吗,或者在SQLFIDLE上共享到上述示例的链接是的,你的权利安德烈,修改过了-在MySQL中,T-SQL中的一些简单的东西有点困难,但我想在其他情况下也可能相反谢谢,这个解决方案很有效,希望它能快一点,但仍然正确。+1谢谢,我在>和<符号周围做了一些更改,但这有一个优点,即从cI调用它更快、更容易,显然很难读取不起眼的表名上的t和d:修复了它-谢谢你的更正。我刚刚意识到我错过了我的datediff,但它可以很容易地添加。由于这两个段之间的依赖关系在这里表示为针对整个子查询合并,这将更加困难,不是吗?老实说,我仍然不能确定我是否“获得”了/original/query,因此我不确定是否需要额外的DateDiff。我只是试图根据描述和预期输出来确定需求。
ID  SELECT_TYPE TABLE   TYPE    POSSIBLE_KEYS   KEY KEY_LEN REF ROWS    EXTRA
1   PRIMARY <derived2>  ALL (null)  (null)  (null)  (null)  8   Using filesort
2   DERIVED t   ALL (null)  (null)  (null)  (null)  8   
6   DEPENDENT SUBQUERY  data    ALL DataDateTime    (null)  (null)  (null)  8   Using where; Using filesort
5   DEPENDENT SUBQUERY  data    index   DataDateTime    DataDateTime    9   (null)  1   Using where; Using index
4   DEPENDENT SUBQUERY  data    ALL DataDateTime    (null)  (null)  (null)  8   Using where; Using filesort
3   DEPENDENT SUBQUERY  data    index   DataDateTime    DataDateTime    9   (null)  1   Using where; Using index
SELECT t.*, data.*
  FROM t
  JOIN (SELECT t_ID = t.ID, 
        data_ID = ISNULL((SELECT TOP 1 ID FROM data WHERE data.DataDateTime <= t.TDateTime ORDER BY DataDateTime DESC),
                         (SELECT TOP 1 ID FROM data WHERE data.DataDateTime > t.TDateTime ORDER BY DataDateTime ASC))
   FROM t) lnk
    ON lnk.t_ID = t.ID
  JOIN data
    ON data.ID = lnk.data_ID
  ORDER BY t.ID
SELECT t.*, data.*
  FROM t
  JOIN (SELECT t.ID t_ID, 
           COALESCE((SELECT ID FROM data WHERE data.DataDateTime <= t.TDateTime ORDER BY DataDateTime DESC LIMIT 1),
                           (SELECT ID FROM data WHERE data.DataDateTime > t.TDateTime ORDER BY DataDateTime ASC LIMIT 1)) data_ID
   FROM t) lnk
    ON lnk.t_ID = t.ID
  JOIN data
    ON data.ID = lnk.data_ID
  ORDER BY t.ID