MySQL比较不同格式的时间

时间:2017-09-10 18:04:09

标签: mysql sql date time

我正在使用一个包含标题和持续时间的歌曲数据库。

我需要返回持续时间超过29:59(MM:SS)的所有歌曲。

数据以两种不同的方式格式化。

格式1

表格中的大部分数据都格式化为MM:SS,有些歌曲的格式大于60分钟,例如72:15。

格式2

表格中的其他歌曲格式为HH:MM:SS,其中格式1的示例将改为01:12:15。

我尝试了两种不同类型的查询来解决这个问题。

查询1

以下查询返回我为格式1返回的所有值,但是我找不到为格式2包含值的方法。

select title, duration from songs where 
  time(cast(duration as time)) > 
  time(cast('29:59' as time)) 

查询2

使用下一个查询,我希望使用str_to_date中的格式说明符来查找格式为HH:MM:SS的结果,但我收到的结果如3:50。解释器假设所有数据都是HH:MM的形式,我不知道如何在不破坏结果的情况下告诉它。

select title, duration from songs where
      time(cast(str_to_date(duration, '%H:%i:%s') as time)) >
      time(cast(str_to_date('00:29:59', '%H:%i:%s') as time))

我已尝试将第一次调用中的说明符更改为str_to_date%i:%s,这使我的所有值都大于29:59,但不会大于59:59。这比原始查询更糟糕。我还尝试了00:%i:%s'00:' || duration, '%H:%i:%s'。这两个特别会破坏结果,但我现在只是在摆弄。

我彻底难倒,但我确定解决方案很简单。任何帮助表示赞赏。

编辑:以下是评论中提供的一些数据。

show create table的结果:

CREATE TABLE `songs` (
 `song_id` int(11) NOT NULL,
 `title` varchar(100) NOT NULL,
 `duration` varchar(20) DEFAULT NULL,
 PRIMARY KEY (`song_id`),
 UNIQUE KEY `songs_uq` (`title`,`duration`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

请记住,列数比我上面描述的多,但为了简单起见,我留下了一些列。我也会将它们留在样本数据中。

示例数据

title                       duration
(Allegro Moderato)              3:50
Agatha                          1:56
Antecessor Machine             06:16
Very Long Song              01:24:16
Also Very Long               2:35:22

3 个答案:

答案 0 :(得分:2)

您正在将非结构化数据存储在关系数据库中。这让你不快乐。所以要构建它。

添加TIME列,或将song_id复制到可以加入的一侧的并行时间表中。选择所有两个冒号的持续时间并轻松更新TIME。重复,前置' 00:'所有单结肠持续时间。现在您已经解析了所有行,并且可以安全地忽略持续时间列。

好的,我想你可以构建一个提供UNION所有这两个查询的VIEW,但这很慢且很丑,更好地修复磁盘上的数据。

答案 1 :(得分:0)

忘记时间。转换为秒。这是一种方式:

select s.*
from (select s.*,
             ( substring_index(duration, ':', -1) + 0 +
               substring_index(substring_index(duration, ':', -2), ':', 1) * 60 +
               (case when duration like '%:%:%' then substring_index(duration, ':', 1) * 60*60
                     else 0
                end)
             ) as duration_seconds
      from songs s
     ) s
where duration_seconds > 29*60 + 59;

答案 2 :(得分:0)

经过一些研究,我得出了一个我自己的答案,我很满意。

select title, duration from songs where 
    case
    when length(duration) - length(replace(duration, ':', '')) = 1 
        then time_to_sec(duration) > time_to_sec('29:59')
    else time_to_sec(duration) > time_to_sec('00:29:59')
    end

感谢Gordon Linoff建议我将时间转换为秒。这使事情变得更容易。我刚刚发现他的解决方案有点过于复杂,它通过不使用time_to_sec来重新发明轮子。

输出数据

title                     duration
21 Album Mix Tape            45:40
Act 1                      1:20:25
Act 2                      1:12:05
Agog Opus I                  30:00
Among The Vultures         2:11:00
Anabasis                   1:12:00
Avalanches Mixtape           60:00
Beautiful And Timeless       73:46
Beggars Banquet Tracks       76:07
Bonus Tracks                 68:55 
Chindogu                     66:23
Spun                        101:08

注意:戈登提到他不使用time_to_sec的原因是为了超过23小时的歌曲。经过测试,我发现time_to_sec确实支持大于23的小时,就像它支持大于59的分钟一样。

对于其他不符合要求的格式,例如1:4:32(例如01:04:32),它也完全没问题。