mirall: (job)
Как оказалось, стандарт ANSI не поддерживает функцию round для дат. А то, что в Oracle оно есть, так это просто жест доброй воли со стороны его разработчиков. На PostgreSQL пришлось изобретать самой. А т.к. я паталогически ленива и почему-то предпочитаю запихнуть всё в запрос, вместо того, чтобы писать длинный столбец ветвлений, то получилось следующее.
Код )
mirall: (job)
    По какой-то странной причине все данные, которые мне приходилось на регулярной основе грузить в базу, были в формате csv. Ничего не имею против csv, но для xml, к примеру, в oracle имеется вполне приличный api. А csv приходится парсить вручную.
    Я использовала два решения.
    Первый — подключить файл как внешнюю таблицу, одним запросом выгрести из внешней таблицы данные и удалить внешнюю таблицу. Минусы: много динамического sql, в случае ошибки внешняя таблица остаётся в базе и приходится писать дополнительные проверки, чтобы её выщемить и удалить.
    Второй — считать файл построчно, складировать в коллекцию, а потом с помощью bulk загрузить данные из коллекции в нужную таблицу. Минусы: возня с коллекциями.
    И общий минус для обоих решений: для каждого формата файла приходится писать собственную обработку, потому что обращаться к элементам коллекции по индексам можно, а вот к атрибутам записи — только по имени, плюс неопределённое количество явных преобразований текста в число или дату.
    Пораскинув мозгами, решила попробовать ещё одно решение, которое производительность скорее всего понизит, но зато кодировать будет проще. Надеюсь.
    Текстовый файл с разделителями считывается в двумерный тестовый массив. И уже потом массив переписывается в коллекцию. Из очевидных минусов — двойное копирование данных, что не может не сказаться на скорости. Из плюсов — не придётся для каждого формата файла писать обработчик с нуля. Достаточно сочинить одну функцию для считывания данных из файла и одну для преобразования двумерного текстового массива в коллекцию записей с определёнными атрибутами.
    Считывание уже нарисовалось. Нужно теперь сделать табличку, процедуру-конвертер и потестировать.
    Код )
mirall: (job)
    После вдумчивого ковыряния asktom.oracle.com, документации и металинка получилась следующая процедурка.
    Код )
mirall: (job)
    Задача: имеется некий запрос с динамически настраиваемым условием where. Параметры передаются с веб-интерфейса, при этом если параметр пуст, т.е. is null, то он не должен включаться в условие where. Дополнительное условие — постраничный вывод данных, но это мы уже проходили.
    Подход я придумала сама, давно уже. А выношу этот вопрос на публику сейчас, потому что сегодня наткнулась на статью приснопамятного Тома Кайта как раз на эту тему. Мой личный подход концептуально не отличается, но кажется более сложным, у Кайта как-то полегче. Но переделывать, наверное, уже не буду — слишком много в приложении на него завязано. Хотя кое-что можно попробовать поковырять с целью повышения производительности.
    Подробности и много кода )
mirall: (job)
    Особенность проекта — доступ к БД только через хранимые процедуры. Все процедуры возвращают output cursor. Поэтому для тех, которые возвращают заведомо одно значение, работает мелкий пакет returns. В т.ч. returns.ReturnTextSuccess.
    Текст )
    Т.е. вернуть фиксированное значение с возможностью задать имя столбца. По умолчанию возвращается 'SUCCESS'.
    Сегодня процедура GetEmailDefaultAttr начала возвращать этот самый 'SUCCESS'. Понятное дело, потому что значение атрибута было null. Но как-то я оказалась к такому выверту не готова :)
mirall: (job)
    Есть у меня функция
     GetPeriodEndDate )
    Как оказалось, если подать на вход 30 января и период 1 месяц, то вылетит ошибка ORA-01839: date not valid for month specified. Я настолько этого не ожидала, что вообще не обрабатывала исключения в этой функции — тестировщики указали на баг. И меня теперь мучает мысль, как лучше это безобразие обработать. Тридцать дней? Или ближайший доступный день требуемого месяца? Или лучше первый день следующего? Свинство со стороны оракла, честное слово :)

    UPD. ADD_MONTHS — наш выбор :)
mirall: (job)
    Имется примитивная функция сброса пароля.
    1. Проверка ответа на секретный вопрос.
    2. Сброс пароля.
    Псевдокод.
    
select 1
  from customer
  where login = i_sLogin
    and security_question = i_sSecurityQuestion
    and security_answer = i_sSecurityAnswer;
if notfound then
  raise_error ('SECURITY_ANSWER_NOT_FOUND');
end if;
update customer
  set password = i_sPassword
  where login = i_sLogin;
if sql%rowcount = 0 then
  raise_error ('CUSTOMER_NOT_FOUND');
end if;

    
    Запостили баг: ошибка CUSTOMER_NOT_FOUND отсутствует в репозитории. Она таки действительно там отсутствует. Но я вот всё пытаюсь понять, как они умудрились дойти до этой ошибки, если существование логина проверено ещё на этапе проверки ответа на секретный вопрос. И ежели логин не существует, то процедура ляснется с ошибкой SECURITY_ANSWER_NOT_FOUND. Т.е. ошибка-то не зарегистрирована. Но она и не может возникнуть. Или я что-то туплю?
mirall: (job)
    Нарисовала скрипт, сравнивающий схемы БД. Все объекты плюс содержимое всех таблиц (это чтобы справочники были правильно инициализированы на этапе инсталляции). Часть кода, естественно, утянула из инета. Кое-что подкрутила. Навесила батник и результирующие логи.
    Использую для проверки инсталляционных скриптов: если править их руками, то они иногда разъезжаются, а потом вылазят противные косяки из тех, что мелочь, но жизнь отравляет. А так — запустить батник, просмотреть логи, на основании логов поправить код. И можно быть уверенной в том, что база станет нормально.
mirall: (Default)
Был такой боянчик.

Смотрел код коллеги.. Вот как у нас программисты веселятся:
string iff(bool f)
{
  switch(f)
  {
    case 0:
      return "false";
      break;
    case 1:
      return "true";
      break;
    case 2:
      return "Хуясе О_о";
      break;
    default:
      return "Ненене, Дэвид Блэйн, ненене!!";
  }
}
Смешно. Сегодня просматриваю код. )
mirall: (job)
    Для того, чтобы стало возможным использование пакетов UTL_TCP, UTL_SMTP, UTL_MAIL, UTL_HTTP, UTL_INADDR необходимо некоторое количество танцев с бубном. В частности, настроить т.н. Access Control Lists (это примочка XML DB).
    Полностью процесс описан в документации: Oracle® Database Security Guide -> 4 Configuring Privilege and Role Authorization.
    Вкратце же, вся бодяга выглядит следующим образом.
  1. Создаётся access list (в дальнейшем - список контроля доступа)
    DBMS_NETWORK_ACL_ADMIN.CREATE_ACL (
      acl          => 'file_name.xml', 
      description  => 'file description',
      principal    => 'user_or_role',
      is_grant     => TRUE|FALSE, 
      privilege    => 'connect|resolve',
      start_date   => null|timestamp_with_time_zone,
      end_date     => null|timestamp_with_time_zone);
    причём параметр privilege чувствителен к регистру.
  2. Списку присваивается один или несколько адресов.
     DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL (
      acl         => 'file_name.xml',
      host        => 'network_host', 
      lower_port  => null|port_number,
      upper_port  => null|port_number);
  3. Привилегия на использование списка предоставляется пользователю или роли.
    DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE ( 
      acl         => 'file_name.xml', 
      principal   => 'user_or_role',
      is_grant    => TRUE|FALSE, 
      privilege   => 'connect|resolve', 
      position    => null|value, 
      start_date  => null|timestamp_with_time_zone,
      end_date    => null|timestamp_with_time_zone);
Если все манипуляции провести аккуратно, то получится с первого раза. Поскольку я патологически невнимательна, то у меня на всё про всё ушло около часа.
mirall: (job)
Так в своё время нас учили поступать с треугольной пирамидой с углом в 90 градусов в вершине.

Итак, стояла задача следующего вида.
Есть три таблицы:
1) Объект, имеющий некие характеристики.
tbl_object (
    obj_id number,
    obj_name varchar2);

2) Список всевозможных характеристик (field_type - тип данных характеристики)
tbl_field (
    field_id number,
    field_name varchar2,
    field_type number);

3) Характеристики объектов
tbl_obj_field (
    obj_id number,
    field_id number,
    field_data sys.anydata);


Помимо всех прочих манипуляций, необходимо было написать функцию, получающую на входе условие, например, where field1 < 5 and field2 = 'ABC' or field3 between to_date('21-01-2008','DD-MM-YYYY') and to_date('21-01-2008','DD-MM-YYYY'), где fieldN - имя характеристики (из таблицы field), и возвращающую все объекты с соответствующими характеристиками.

Решение было найдено. Сразу скажу, не шибко элегантное и, к сожалению, не слишком быстрое (на 1000 объектов с 999 характеристиками каждый процедура у меня отрабатывает за 6-8 секунд при наличии в условии where до трёх различных характеристик). Подобное решение было выбрано в ущерб производительности для того, чтобы можно было написать требуемое условие where, не ограничивая себя порядком следования полей, операторов сравнения, функция и т.д.
Две не очень мелкие процедуры )

Ref cursor

Apr. 25th, 2007 09:25 am
mirall: (job)
    What is the difference between cursor and ref cursor, and when would you appropriately use each of these.
    Answer )

    Difference between cursor and a ref cursor
Page generated Sep. 25th, 2017 06:06 am
Powered by Dreamwidth Studios