|
Программирование >> Проектирование баз данных
в символьном или числовом формате даты в таблицах Oracle хранятся крайне редко, поскольку нет никаких веских причин избегать формат DATE. Единственное исключение из этого правила - ситуация, когда записывается только год (например, год регистрации автомобиля). Этот год может храниться в числовом или символьном столбце с двумя или четырьмя значащими цифрами. Главная проблема с ПО, написанным для базы данных Oracle, состоит в конвертировании дат из внутреннего формата во внешний (отображаемый) и наоборот. В Oracle имеется механизм масок, позволяющий программисту задавать требуемый внешний формат даты. Это достигается путем склеивания набора компонентов. Вот некоторые примеры масок: DD Month YYYY, DD-MON-YY, DD/MM/YY, MM/DD/YY. Проблемы непременно возникнут, если в компоненте, обозначающем год, будет пропущен век, потому что в этом случае он считается равным 19. Специалисты Oracle были достаточно прозорливы, чтобы предвидеть эту проблему еще в 1993 г., когда была впервые выпущена Oracle?, и ввели маску RR. RR предполагает двадцатый век, если год больше или равен 50, и двадцать первый век, если год меньше 50. Так, TO DATE(04-JAN-05, DD-MON-RR) дает дату в 2005-м году, а TO DATEC01-MAR-68. DD-MON-RR) - дату в 1968-м году. К сожалению, проектировщики и программисты не особенно быстро проникаются важностью этого новшества и использование YY в масках дат продолжает процветать. Вероятно, 2000-й год все еще кажется им далеким будущим, особенно с точки зрения компьютерной индустрии. Даже в тех организациях, которые были достаточно дисциплинированы и узаконили использование маски RR, где это возможно, или ввели стандарт YYYY, этой практики обычно придерживаются только в новых разработках или при переработке существующего кода. В эксплуатируемых Oracle-системах все еще остается много строк кода, где для дат применяется маска YY или вообще никаких масок нет. Руководители только сейчас начинают осознавать всю глубину проблемы тысячелетия и потенциальную стоимость ее решения. Задача обнаружения всего исходного кода (в каком бы то ни было формате) и проверки каждой строки на предмет наличия возможных проблем колоссальна с точки зрения логистики и требует огромных трудозатрат. Некоторый исходный код неизбежно окажется не в нужном .месте, а единственным выходом будет его переписывание. Что нужно делать, если ваш начальник поставит перед вами, проектировщиком, задачу проанализировать проблему и обеспечить плавный переход в следующее тысячелетие? Прежде всего, не следует недооценивать масштабность этой задачи. Но как уменьшить потенциально колоссальные затраты на поддержку работоспособности существующих Oracle-систем при подходе к рубежу тысячелетий? Вот некоторые мысли на этот счет. Можно ли решить проблему непосредственно в базе данных? Ответ на этот вопрос таков: решить эту проблему в базе данных без корректировки прикладного кода можно лишь в очень ограниченной степени. Представим экранную форму, в которую пользователь вводит дату в типичное для Oracle девятисимвольное поле (без века). Возьмем эту экранную форму из промышленной системы, перенесем на тестовую арену и поэкспериментируем с ней. Вводим в поле дату 3I-DEC-00, выполняем фиксацию и запрашиваем эту запись - нам вьщается 31-DEC-00. Но если мы воспользуемся SQL*Plus и запросим поле даты с веком, то увидим 31-DEC-1900. В результате мы приходим к выводу, что в этой экранной форме для века не используется маска RR. Допустим, что вводимая дата - срок действия. Мы можем предположить, что она никогда не будет в прошлом. Учитывая это, можно написать триггер, который проверяет дату и, если она в прошлом, конвертирует ее в дату в 21-м веке. Вот код этого триггера: CREATE OR REPLACE TRIGGER policies biur BEFOR INSERT OR UPDATE OF expiry d ON policies FOR EACH ROW BEGIN IF :new.expiry d < TRUNC(SYSDATE) AND :new:expiry d IS NOT NULL THEN :new.expiry d := add montlis (new. expiry d, 1200); END IF; END; / Работает такой триггер нормально, но этот подход имеет ряд недостатков: Правильно ли предположение о том, что срок действия полиса никогда не будет датой в прошлом? Загружаются ли когда-нибудь сведения о старых полисах? Если да, то они вновь могут стать действгггельными и мы попадем в неловкое положение, начисляя премии давно умершим владельцам полисов. Изменив значение срока действия между экранной формой и базой данных, мы создали между ними противоречие. Экранная форма считает, что срок действия полиса истекает 3I-DEC-1900, тогда как база данных полагает, что он заканчивается 31-DEC-2000. Если мы изменим в экранной форме другое поле, то это вызовет обновление без предварительного повторного запроса и, вероятно, мы получим уведомление от приложения о том, что эту запись изменил другой пользователь. В действительности никакого изменения не было, но экранная форма выявила противоречие и предположила, что в этом виноват какой-то другой пользователь. Мы смогли написать триггер- регулятор для этого столбца, поскольку у нас было строгое правило, на котором мы могли построгггь свою логику (срок действия не может находиться в прошлом). Однако во многих другах случаях подобные допущения делать нельзя. Возьмем, например, дату рождения. В первом году столетия дата 01-DEC-00 может относиться или к очень молодому, или к очень старому человеку. Вероятно, мы могли бы просмотреть другие поля, например поле номера социального страхования, и определить, что у ребенка его еще нет, но это далеко не лучший подход. Данные, вводимые пользователем, - это лишь часть проблемы. В коде экранной формы, скорее всего, имеется условная логика, построенная на значениях дат. Могут быть даты, жестко закодированные в этой логике, но это встречается редко и вряд ли приведет к неоднозначности при определении века. В большинстве случаев вы встретете нечто вроде: IF :creation date > TO DATE(OI-DEC-90, DD-MON-YY) THEN process new policy; ELSE process old policy; END IF; Более вероятно, что программа содержет локальные переменные, которых хранятся представления значений дат, выбираемых из базы данных] Пример Б.4 содержит фрагменты кода из действующей системы, в которых может возникнуть проблема тысячелетия. Пример Б.4. Проблемные фрагменты кода инмцмализация :Ы . s start time := TO DATE (TO CHAR (SYSDATE, DD-MON-YY HH:MI:SS), DD-MON-YY HH:MI:SS); :global.stage date := TO CHAR(SYSDATE, DD-MON-YY); :bl.generation := TO NUMBER(TO CHAR(:bl.application date, YY)) условная логика IF .-огдг .deleted date > TO DATE (TO CHAR (SYSDATE, DD-MON-YY)) THEN предикаты ... AND TO NUMBER(TO CHAR(csh date started, YY)) < 85 ... ORDER BY TO DATE(hci month, MON-YY) DESC ... AND hist date < TRUNC(TO DATE(TO CHAR(SYSDATE, DD-MON-YY)), YEAR) в курсорах CURSOR count dates IS SELECT COUNT (DISTINCT (TO CHAR (hom offer of cover date, DD-MON-YY ) ) ) , COUNT (DISTINCT (TO CHAR (hom date issued, DD-MON-YY ) ) ) , COUNT(DISTINCT(TO CHAR(hom date cp notice, DD-MON-YY))), COUNT (DISTINCT (TO CHAR (hom date f inal cert, DD-MON-YY ) ) ) FROM homes WHERE (:bl.service type = HB3 AND hom hb3 service request no = :bl.service request no);
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |