SQL - дата между (xxxx-06-21 и xxxx-09-21) - PullRequest
2 голосов
/ 29 сентября 2011

Как можно использовать функцию BETWEEN в MySQL для поиска дат в любой год, но между конкретным днем ​​/ месяцем и конкретным днем ​​/ месяцем? Или, если невозможно использовать МЕЖДУ, как еще я могу это сделать?

Чтобы быть более наглядным, я пытаюсь добавить сезонный поиск на мой сайт фотоархива. Поэтому, если пользователь выберет для поиска "летние" фотографии, он будет искать фотографии, сделанные в период с 21 июня по 21 сентября, но в любом году.

Если бы Carlsberg сделал SQL, я думаю, что это было бы:)

WHERE date BETWEEN 'xxxx-06-21' AND 'xxxx-09-21'

Большое спасибо

Ответы [ 7 ]

4 голосов
/ 29 сентября 2011

Решение, приведенное в другом месте, WHERE date.MONTH() || date.DAY() BETWEEN '0621' AND '0921', является хорошим (и его стоит проголосовать, так как оно подходит для большинства баз данных MySQL), но я хотел бы отметить, что оно (и большинство запросов, которые включают функции для каждой строки) ) не подойдет для больших таблиц.

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

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

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

Например, добавьте новый столбец CHAR(4) с именем MMDD и добавьте в него индекс. Затем настройте триггеры вставки / обновления для таблицы так, чтобы столбец date использовался для установки этого нового на основе уже предоставленной формулы date.MONTH() || date.DAY().

Затем при выполнении запроса пропустите функции для каждой строки и вместо этого используйте:

WHERE MMDD BETWEEN '0621' AND '0921'

Тот факт, что он индексируется, будет поддерживать скорость ослепительно высокой, при небольшой стоимости триггера во время вставки / обновления и дополнительного столбца.

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

И, хотя это технически «нарушает» 3NF в том смысле, что вы дублируете данные, это давняя традиция делать это по соображениям производительности, если вы знаете, что делаете (то есть триггеры уменьшают «ущерб»).

3 голосов
/ 29 сентября 2011

Я думаю, что самый простой способ - взять даты, превратить их в строки, взять постфикс и запустить его через BETWEEN:

WHERE date.MONTH() || date.DAY() BETWEEN '0621' AND '0921'
2 голосов
/ 29 сентября 2011

функция RIGHT может помочь

select
    current_date,
    right(current_date,5),
    right(current_date,5) between '06-21' and '09-21' `IsTodaySummer?`,
    '09-21' between '06-21' and '09-21' `Is 09-21 Summer?`;
+--------------+-----------------------+-----------------+-------------------+
| current_date | right(current_date,5) | IsTodaySummer? | Is 09-21 Summer? |
+--------------+-----------------------+-----------------+-------------------+
| 2011-09-29   | 09-29                 |               0 |                 1 |
+--------------+-----------------------+-----------------+-------------------+

, но, как сказал ajeal, лучше добавить еще один столбец для использования индекса.

1 голос
/ 29 сентября 2011

Если вам действительно нужен этот формат поиска,
Я думаю, что лучше разбить столбец даты на два,

  • year int(4) unsigned (это год)
  • month_day int(4) unsigned (ммдд)

построение составного индекса для month_day, year,
Идея в том, чтобы индекс работал лучше

пример запроса типа

where month_day between 621 and 921 -- make use on index

другой пример

where year=2011 and month_day between 900 and 930 -- make use on index too
0 голосов
/ 29 сентября 2011

Так как вам не нужен год, вычтите его из даты. В MySQL вы можете сделать что-то вроде этого:

select * from some_table
where date_sub(date_col, interval year(date_col) year)
between '0000-06-21' and '0000-09-21';
0 голосов
/ 29 сентября 2011

Вы можете разделить даты с помощью функций month и day:

where month(date_column) between 6 and 9
  and if(month(date_column) = 6 and day(date_column) < 21, 0, 1)
  and if(month(date_column) = 9 and day(date_column) > 21, 0, 1)

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

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

0 голосов
/ 29 сентября 2011

В MySQL должен быть эквивалент функции Oracle to_date ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...