2013-06-28 7 views
4

Мне нужно получить серию дат, используя день недели и время как единственный бит информации.MYSQL Получить дату с текущего года, текущего месяца и дня переменной

Мне известно об обратном этой операции, то есть используется WEEKDAY (дата) или DAYOFWEEK (дата), но это не то, что мне нужно.

У меня есть таблица, которая выглядит так, которая будет непрерывно сканироваться и сравниваться с текущей датой.

+----+---------+----------+----------+ 
| 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 | 
+----+---------+----------+----------+ 

Выше была простая версия, я ожидаю, что эта таблица будет иметь сотни или тысячи возможных итераций. Как отмечалось в 4-м ряду, время может также переходить в полночь, и я должен компенсировать это.

Мне нужен запрос, который предоставит мне следующие результирующие наборы, и у меня возникнут проблемы с блокировкой даты, основанной на текущем году, месяце и прошедшем дне недели из столбца буднего дня.

Пример набора результатов:

+---------------------+---------------------+ 
| 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 | 
+---------------------+---------------------+ 

Любая помощь будет оценена, я получил как можно ближе, чтобы получить только дата, однако, это создает некоторые проблемы для меня, так как эти даты позже должны быть преобразованы , поэтому мне нужен массив из них, а не только текущий день.

Edit: Добавлено мой текущий код: Хотя я не считаю, что это вполне движется в правильном направлении

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 
+---------------------+---------------------+ 

ВТОРОЙ EDIT

Благодаря помощи нижеподписавшихся, я пришел к следующему запросу, movi но некоторые из них выразили озабоченность дизайном, и я буду запускать некоторые тесты, прежде чем я соглашусь на ответ. Если есть лучший способ сделать это, мне было бы очень интересно услышать это!

Я полагаю, что лучше всего, когда месяц меняется на полпути через запрос, используя день недели, чтобы определить разницу, может быть, хлопотно.

Запрос:

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 | 
+------+------------+---------------------+---------------------+ 

Третьи Редактировать

Я тестировал выше запрос в течение периодов, которые охватывают через начало и окончание месяца, и нашли его чтобы быть подходящим для его цели, я переведу вышеуказанный запрос, а также некоторые примечания к ответу в надежде, что кто-то может найти это полезным в будущее.

В этой заметке я также расскажу о различных ошибках и рекомендациях от различных комментаторов, снова благодаря всем, кто нашел время, чтобы помочь.

+0

Пожалуйста, покажите, что вы пробовали, поэтому мы можем помочь вам исправить это, а не писать код для вас. – Barmar

+0

Я не писал, что у меня было до сих пор, потому что я не думаю, что это направлено в правильном направлении, и я действительно не собирался писать другим своим кодом для меня :) Однако, поскольку вы спросили, вот оно. –

+0

Расчет части даты 'end' должен добавить 1, если' end Barmar

ответ

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. Столбец дня недели на моем столе фактически ссылался на UNSIGNED INTEGER, что делало невозможным получить разницу в дни, когда эта разница была отрицательной.
  3. Вышеупомянутая проблема была решена с помощью функции CAST, ее нужно было отличить от значения SIGNED, а это значит, что это отрицательно.
  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 | 
+------+------------+---------------------+---------------------+ 

Надеется, что это поможет кому-то.

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.

Update

Я не защищаю этот метод любыми средствами. Я просто отвечал на исходный вопрос, учитывая информацию, которая была доступна. Иногда данные поступают в разных формах, и работать с ними сложнее, чем если бы у них была бы роскошь, если бы они могли определять формат данных. Хотя сначала казалось невозможным просто использовать одну таблицу, добавление таблицы дат (или даже временной таблицы) сделало ее намного проще. Единственная другая проблема, которую я могу думать о том, что может возникнуть, - это переход к изменению времени перехода на летнее время, что добавит или вычтен час, который этот метод не учитывает.

+0

Вот и вопрос. Спасибо, я изучу это и посмотрю, приносит ли он какую-либо пользу по запросу, продемонстрированному на том, что я поставил под вопросом «Второе редактирование». Я думаю, что я закончил с немного проще, но я бы приветствовал любые комментарии о том, почему это лучший вариант, чем то, что у меня есть? Кроме того, +1 :) Я могу сказать, что вы потратили довольно много времени на это! –

+0

@ francisco.preller потребовалось около 20 минут. Я немного сражался с латинскими вещами, потому что возвращал blob в MySQL Workbench. –

+0

Хм, интересно, это может быть поэтому, что C# дает мне печаль, преобразовывающую производный столбец TIMESTAMP() в значение DateTime, кажется, что он считает его типом данных byte [] ... Просто попробовал, вы абсолютно правы , Хотел бы я дать тебе больше бонусов. –