Как разбить smalldatetime на индексы года, месяца, дня?

#sql #sql-server

#sql #sql-сервер

Вопрос:

Я использую SQL Server 2008.

В моей базе данных есть несколько дат, которые, как я «думаю», я хочу разбить на более мелкие части. Даты — это дни рождения и смерти. Я хочу иметь возможность выводить их, например, запрашивая людей, которые родились в октябре или 12 мая или в 1945 году.

Мне сказали, что типичный способ сделать это — взять дату, разбить ее на более мелкие части и поместить каждую часть даты в отдельный столбец, вот так:

 2001-03-12 00:00:00 // EventDate column
  

Добавьте эти столбцы:

 2001 // EventYear column
03 // EventMonth column
12 // EventDay column
  

Во-первых, это хороший способ сделать это? Если да, то, во-вторых, могу ли я каким-то образом заставить SQL Server автоматически разбивать часть даты и помещать ее в свои собственные столбцы?

Я был бы признателен за идеи и решения.

Комментарии:

1. Сколько строк данных у вас в этой таблице?

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

3. Что значит распределить по 4-6 таблицам?

4. У меня будет четыре или пять таблиц с датами. В каждой таблице может быть 2000 строк.

5. Я не вижу причин указывать Erik разделять каждый столбец datetime с целью запроса 2000 записей.

Ответ №1:

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

 Select * from TABLEX
where DatePart(YEAR,EventDate) = 1945
  

Комментарии:

1. Как это будет выполняться, когда запрос будет на 12 мая?

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

3. У меня, конечно, не будет миллионов дат, возможно, всего несколько тысяч. Я хочу сделать это так, как если бы было миллион дат. Я бы предпочел написать запрос типа select * from DateTable где Year = 1945, чем указывать часть даты в каждом запросе.

4. Основное преимущество использования datepart заключается в том, что вам не нужно думать о создании нового столбца каждый раз, когда вы хотите разделить данные по-разному. Например … если вы решили, что хотите знать все события, произошедшие в субботу, вам не нужно создавать еще один столбец для day of the week, вы бы просто использовали datepart weekday .

5. Основным недостатком является то, что каждый запрос будет представлять собой tablescan, возможно , за исключением того, который включает год, месяц, день и т.д. в таком порядке (я не знаю, является ли DatePart переносимым, но частичные запросы определенно нет.)

Ответ №2:

Не похоже, что бизнес-требования сильно укреплены. По какой причине вам нужно было бы разделить разные части даты? Если вам это не нужно, я бы не стал.

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

Что-то вроде этого:

 create table DateTest
(
    SomeDate datetime not null,
    SomeYear as datepart(yy, somedate) persisted,
    SomeMonth as datepart(mm, somedate) persisted,
    SomeDay as datepart(dd, somedate) persisted
)
  

Комментарии:

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

2. Интересное решение. Это выше моего уровня опыта, но я собираюсь исследовать это и помнить об этом. Спасибо!

Ответ №3:

Вот что я делаю.

У меня есть таблица «lib.Dates». В качестве первичного ключа используется ДАТА.

В нем есть дополнительные столбцы с дополнительной информацией на эту дату. Это, например, день месяца, день до конца месяца, неделя года и т.д.

Объединение этой таблицы дат с датами позволяет мне: * Получить список всех дат (например, группировка продаж на человека по дате не будет иметь записи для нулевых продаж, таким образом, это может быть) * Делать забавные вещи, такие как все даты на 23-й неделе года, что обычно сложнее получить.

Это часть ряда таких таблиц, которые мои хранимые процедуры поддерживают ежедневно (-3 года, 5 лет).

Комментарии:

1. Вы имеете в виду Calendar таблицу, на которую может ссылаться любая другая таблица с date полем FOREIGN KEY ? Значит, никакой другой таблице не понадобятся сохраненные индексированные представления? Если да, 1 от меня.

2. Да, точно. Он также принадлежит библиотечному проекту, который я поддерживаю — я иногда добавляю сюда новые таблицы. Особенно иногда очень приятна функция объединения (поскольку она позволяет мне получать список ВСЕХ дат, а не только дат, содержащих данные).

3. Да, похожие вопросы время от времени появляются в SO: «найти все даты, по которым заказы не принимались».

4. TomTom, это интересное решение, но для меня это слишком много. Я ценю, что вы познакомили меня с этой идеей.