4

我需要通过使用星期几和时间作为唯一的信息来获取一系列日期。

我知道此操作的反向操作,即使用 WEEKDAY(date) 或 DAYOFWEEK(date),但这不是我需要的。

我有一个表格,看起来像这样,它将被持续扫描并与当前日期进行比较。

+----+---------+----------+----------+
| id | weekday | start    | end      |
+----+---------+----------+----------+
|  1 |       1 | 09:00:00 | 17:00:00 |
|  2 |       2 | 09:00:00 | 17:00:00 |
|  3 |       3 | 09:00:00 | 17:00:00 |
|  4 |       4 | 23:00:00 | 17:00:00 |
|  5 |       5 | 18:00:00 | 23:00:00 |
|  6 |       6 | 00:00:00 | 00:00:00 |
|  7 |       7 | 00:00:00 | 01:00:00 |
+----+---------+----------+----------+

以上是简单版本,我希望这张表有成百上千次可能的迭代。正如第四排所观察到的,时间也可能超过午夜,我必须补偿。

我需要一个查询,它将为我提供以下结果集,并且在锁定日期时遇到问题,该日期基于当前年份、月份和工作日列中经过的一周中的某一天。

示例结果集:

+---------------------+---------------------+
| start               | end                 |
+---------------------+---------------------+
| 2013-06-24 09:00:00 | 2013-06-24 17:00:00 |
| 2013-06-25 09:00:00 | 2013-06-25 17:00:00 |
| 2013-06-26 09:00:00 | 2013-06-26 17:00:00 |
| 2013-06-27 23:00:00 | 2013-06-28 17:00:00 | # <---- Notice the date difference here
| 2013-06-28 18:00:00 | 2013-06-28 23:00:00 |
| 2013-06-29 00:00:00 | 2013-06-30 00:00:00 | # <---- Also here, the span is 24 hours
| 2013-06-30 00:00:00 | 2013-06-30 01:00:00 |
+---------------------+---------------------+

任何帮助将不胜感激,我已经接近获得当前日期,但是,这给我带来了一些问题,因为这些日期稍后需要转换,所以我需要一个包含所有日期的数组,而不仅仅是当前日期天。

编辑:发布我当前的代码:虽然我不相信这是朝着正确的方向前进

SELECT  TIMESTAMP(IF (end < start,
                     CURRENT_DATE,
                     SUBDATE(CURRENT_DATE, 1)),
                  start) AS 'start',

        TIMESTAMP(IF (end < start,
                     CURRENT_DATE,
                     SUBDATE(CURRENT_DATE, 1))
                  end) AS 'end',

  FROM  shift

结果:

+---------------------+---------------------+
| start               | end                 |
+---------------------+---------------------+
| 2013-06-27 23:00:00 | 2013-06-28 17:00:00 | 
| 2013-06-28 18:00:00 | 2013-06-28 23:00:00 | # Needs the rest of the dates of the week
+---------------------+---------------------+

第二次编辑

感谢以下评论者的帮助,我得到了以下查询,尽管继续前进,但有些人对设计表示担忧,我将在确定答案之前进行一些测试。如果有更好的方法来完成这项工作,我真的很想听听它!

我想最好的一点是当月份在查询中途改变时,使用星期几来确定差异可能会很麻烦。

询问:

SELECT  @diff:=(CAST(weekday AS SIGNED) - (WEEKDAY(CURRENT_DATE) + 1)) as 'diff',
        @date:=DATE_ADD(CURRENT_DATE, INTERVAL @diff DAY) as 'start_date',
        TIMESTAMP(@date, start) AS 'start',
        TIMESTAMP(IF (end <= start,
                     DATE_ADD(@date, INTERVAL 1 DAY),
                     @date),
                  end) AS 'end'
 FROM   shift

结果:

+------+------------+---------------------+---------------------+
| diff | start_date | start               | end                 |
+------+------------+---------------------+---------------------+
|   -4 | 2013-06-24 | 2013-06-24 09:00:00 | 2013-06-24 17:00:00 |
|   -3 | 2013-06-25 | 2013-06-25 09:00:00 | 2013-06-25 17:00:00 |
|   -2 | 2013-06-26 | 2013-06-26 09:00:00 | 2013-06-26 17:00:00 |
|   -1 | 2013-06-27 | 2013-06-27 23:00:00 | 2013-06-28 17:00:00 |
|    0 | 2013-06-28 | 2013-06-28 18:00:00 | 2013-06-28 23:00:00 |
|    1 | 2013-06-29 | 2013-06-29 00:00:00 | 2013-06-30 00:00:00 |
|    2 | 2013-06-30 | 2013-06-30 00:00:00 | 2013-06-30 10:00:00 |
+------+------------+---------------------+---------------------+

第三次编辑

我已经在跨越一个月的开始和结束的时间段测试了上述查询,并发现它适合其目的,我将把上述查询以及一些注释移到答案中,希望有人会发现这很有用未来。

在这方面,我还将包括来自各种评论者的各种陷阱和建议,再次感谢所有花时间提供帮助的人。

4

2 回答 2

1

好的,所以我解决您的问题的方法是创建一个日期表(它甚至可以是动态创建的临时表)。而不是试图通过将日期连接到时间来伪造时差,我实际上是在以秒为单位拉动差异并将它们添加到DATETIME我们正在拉动的第一个标记中,并将日期与DAYOFWEEK(mydate) = weekday. 声明是说如果IF小时数相等则使用 24 小时,否则使用时差的绝对值来计算秒数。

不是火箭科学,但有点挑战性。

我正在使用的主要 SQL 是这样的(此处添加了硬返回以进行格式化):

select  m.mydate,
CONVERT(CONCAT_WS(' ',m.mydate,s.start) USING latin1) as startTime,
if(s.start=s.end,86400,
ABS(MOD(TIME_TO_SEC(s.end)-TIME_TO_SEC(s.start),86400))) as secs,
CONVERT(CONCAT_WS(' ',m.mydate,s.start) + INTERVAL
if(s.start=s.end,86400,
ABS(MOD(TIME_TO_SEC(s.end)-TIME_TO_SEC(s.start),86400))) 
second  USING latin1) as endTime  from StackOverflow.shifts s,
StackOverflow.mydates m where DAYOFWEEK(m.mydate)=s.weekday;

输出如下所示:

mydate      startTime           secs    endTime
2013-06-27  2013-06-27 18:00:00 18000   2013-06-27 23:00:00
2013-06-28  2013-06-28 00:00:00 86400   2013-06-29 00:00:00
2013-06-29  2013-06-29 00:00:00 3600    2013-06-29 01:00:00
2013-06-30  2013-06-30 09:00:00 28800   2013-06-30 17:00:00
2013-07-01  2013-07-01 09:00:00 28800   2013-07-01 17:00:00
2013-07-02  2013-07-02 09:00:00 28800   2013-07-02 17:00:00
2013-07-03  2013-07-03 23:00:00 21600   2013-07-04 05:00:00

这是SQL Fiddle

更新

我不以任何方式提倡这种方法。鉴于可用的信息,我只是在回答原始问题。有时数据以各种形式出现,如果他们可以强制要求数据的格式,那么使用起来会更加困难。虽然起初简单地尝试使用一个表似乎是不可能的,但添加日期表(甚至是临时表)使它变得容易得多。我能想到的唯一可能出现的其他问题是夏令时更改的转变,这将增加或减少一个小时,而这种方法没有考虑到这一点。

于 2013-06-28T04:55:12.380 回答
0

在对它进行了相当多的修改之后,我得出了下面的答案,以防将来有人遇到类似的问题。我要感谢所有花时间提供帮助的人,我发现各种各样的答案很有帮助,我想我会在下面列出我的发现。

我最终得到的查询是:

SELECT  @diff:=(CAST(weekday AS SIGNED) - (WEEKDAY(CURRENT_DATE) + 1)) as 'diff',
        @date:=DATE_ADD(CURRENT_DATE, INTERVAL @diff DAY) as 'start_date',
        CONVERT(TIMESTAMP(@date, start) USING latin1) AS 'start',
        CONVERT(TIMESTAMP(IF (end <= start,
                     DATE_ADD(@date, INTERVAL 1 DAY),
                     @date),
                  end) USING latin1) AS 'end'
 FROM   shift

那里发生了很多事情:

  1. 首先,我的目标是获取当前工作日与表中列出的工作日之间的差异。
  2. 我表上的 weekday 列实际上是由一个 UNSIGNED INTEGER 引用的,这使得当该差异为负数时,不可能在几天内获得差异。
  3. 上面的问题是通过使用 CAST 函数解决的,它必须被转换为一个有符号的整数,而不是允许负数。
  4. @date 变量仅用作占位符,以便在查询的其他位置使用它。
  5. TIMESTAMP 函数将字节数组返回到 C#,而不是字符串或日期数据,感谢 AbsoluteZERO 指出转换为 latin1 修正了问题。

上面的查询返回以下数据,这是期望的结果。由于该表是在 UTC 中设置的,并且被检查的时间随后由 C# 在业务逻辑上转换,因此这足以绕过此类计算通过夏令时可能出现的任何问题。

结果数据:

+------+------------+---------------------+---------------------+
| diff | start_date | start               | end                 |
+------+------------+---------------------+---------------------+
|   -4 | 2013-06-24 | 2013-06-24 09:00:00 | 2013-06-24 17:00:00 |
|   -3 | 2013-06-25 | 2013-06-25 09:00:00 | 2013-06-25 17:00:00 |
|   -2 | 2013-06-26 | 2013-06-26 09:00:00 | 2013-06-26 17:00:00 |
|   -1 | 2013-06-27 | 2013-06-27 23:00:00 | 2013-06-28 17:00:00 |
|    0 | 2013-06-28 | 2013-06-28 18:00:00 | 2013-06-28 23:00:00 |
|    1 | 2013-06-29 | 2013-06-29 00:00:00 | 2013-06-30 00:00:00 |
|    2 | 2013-06-30 | 2013-06-30 00:00:00 | 2013-06-30 10:00:00 |
+------+------------+---------------------+---------------------+

希望这可以帮助某人。

于 2013-06-28T05:36:46.863 回答