Алгоритм интервала даты SQL - PullRequest
1 голос
/ 18 января 2010

В настоящее время я пишу приложение Delphi, которое выполняет запросы к базе данных DB2 с использованием ADO.

Одним из требований является то, что пользователь должен иметь возможность определять запросы, используя даты, например «показать мне все данные за последние 60 дней» или «показать все данные за период с 20 ноября 2009 года по 18 января 2010 года». Это не будет проблемой, за исключением двух фактов:

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

Мне нужно знать, существует ли эффективный алгоритм построения SQL, необходимый для извлечения указанной информации из базы данных. Например, сегодня 18 января, поэтому для извлечения всей информации с 20 ноября по сегодняшний день мне понадобится оператор SQL, который выглядит примерно так:

SELECT data WHERE 
((day >= 20) AND (month = 11) AND (year = 2009)) OR 
((month = 12) AND (year = 2009)) OR 
((day <= 18) AND (month = 1) AND (year = 2010))

Очевидно, что это тривиальный и относительно простой пример, но если бы пользователь захотел получить данные с ноября 2008 года, а не с 2009 года, запрос получился бы намного больше.

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

Ответы [ 6 ]

6 голосов
/ 18 января 2010

В DB2 следующие столбцы должны преобразовывать ваши отдельные столбцы в тип даты: дата (год || месяц || день)

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

дата (год || месяц || день)> CURRENT_DATE - 60

1 голос
/ 18 января 2010

Ответ, предоставленный Galghamon Алгоритм SQL Date Interval эффективен с точки зрения кода, но не сможет использовать индексы.

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

(DateCol > @DateVal)
(DateCol >= @DateVal)
(DateCol < @DateVal)
(DateCol <= @DateVal)
(DateCol = @DateVal)

Затем они могут быть расширены для вашей довольно неудачной схемы следующим образом (с использованием 1-го примера 2):

(YearCol > @YearVal OR (YearCol = @YearVal AND MonthCol > @MonthVal) OR (YearCol = @YearVal AND MonthCol = @MonthVal AND DayCol > @DayVal))
(YearCol > @YearVal OR (YearCol = @YearVal AND MonthCol > @MonthVal) OR (YearCol = @YearVal AND MonthCol = @MonthVal AND DayCol >= @DayVal))

ПРИМЕЧАНИЕ. Необходимо уточнить, где использовать инклюзивные и где использовать операторы исключительного неравенства.

1 голос
/ 18 января 2010

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

Имеет ли db2 вычисленные столбцы, по которымВы могли бы индексировать, и вы могли бы добавить это?Или, может быть, представление, которое может иметь индексированные / сохраняемые вычисляемые столбцы?

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

0 голосов
/ 19 января 2010

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

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

Так что, если вы все еще не можете внести изменения в БД, рассмотрите решение Galghamon, поскольку его легко понять (низкие затраты на обслуживание),Используйте решение Craig Young только в том случае, если влияние производительности заставит вас сделать это.

0 голосов
/ 18 января 2010

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

0 голосов
/ 18 января 2010

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

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