Итак, что пишет нам документация, а именно, файл snps_refmanual.pdf, о переменных.
Переменные могут быть использованы в любых выражениях (SQL и других), также как и в метаданных. Значение переменная получает во время выполнения той команды, в которой она используется, когда эту команду выполняет агент. Свойства переменной отображаются в закладках Definition и Refresh в Дизайнере, глобальные переменные располагаются на том же уровне, где и проекты, проектные (локальные) переменные - внутри дерева проекта.
Наименование переменной
Имя переменной регистрозависимое, и не должно содержать в себе символов, которые могут быть интерпретированы как разделители, например, пробелов.
Область видимости
Глобальные переменные видны во всех проектах, переменные проекта - только в своем проекте. ODI сначала ищет переменную локальную, а затем уже глобальную. Таким образом, если в команде используется переменная #YEAR, и есть две переменные, одна в текущем проекте, одна глобальная - будет использоваться локальная переменная.
Описание
Детальное описание переменной.
Тип переменной
Alphanumeric - значение до 255 символов, Date, Numeric (максимум 10 цифр) или Text (строка неограниченной длины).
Вид переменной (Action)
Определяет временной промежуток, в котором переменная сохраняет свое значение.
- Non-persistent: значение переменной сохраняется только на один запуск.
- Last value: ODI будет сохранять последнее значение переменной в репозитории.
- Historize: ODI будет сохранять все значения переменной в репозитории.
Значение по умолчанию
Значение переменной по умолчанию.
Обновление
Обновление позволяет присвоить новое значение переменной. Это значение получается из результата SQL выражения, заданного в свойствах переменной. После обновления все команды, использующие эту переменную, подставят вместо переменной ее новое значение.
Вот, пожалуй, на этом с документацией можно и закончить.
Какие особенности переменных хотелось бы выделить?
1. Типы переменных.
Обычно приходилось использовать только тип Alphanumeric. Тип Date не использовался ввиду формата этой самой даты, который может быть разным в разных ОС, СУБД и прочем - намного проще использовать строковое выражение для большинства задач. В случаях, когда 255 символов не хватает или есть многострочный текст пользуемся типом Text. Тип Numeric использовался только при необходимости организации циклов внутри пакета, когда один из шагов - инкрементное увеличение значения переменной.
2. Вид переменной.
Самая важная, на мой взгляд, характеристика переменной. Если переменная Non-persistent то ведет она себя вполне предсказуемо. Если переменная используется в интерфейсе или процедуре - у нее должно быть значение. В большинстве случаев, это значение появляется в переменной после шага обновления переменной в пакете. Реже - через передачу параметра в сценарий.
В случае же использования Historize вида - значение переменной будет храниться в репозитории в привязке к дате и к контексту. При обычном запуске сценариев ETL значение переменной может не обновляться в пакете. Достаточно того, чтобы хотя бы одно значение имелось в репозитории. А вот при перезапуске упавшего сценария значение переменной будет браться на ту дату, когда первый раз запускался сценарий.
3. Исторические переменные
Теоретически, если все переменные в проекте будут видом Historize можно на любой период времени, а, точнее, на конкретную дату/время запуска некоего ETL процесса получать актуальные на ту дату/время значения переменных. Правда, через интерфейс Оператора или Дизайнера, насколько мне известно, удобно сделать это нельзя, но выбрать значения по одной переменной довольно просто.
4. Исторические переменные 2
Есть одна фича, связанная с историческим видом переменных. Если обычная Non-persistent переменная, не имеющая значения по умолчанию, будет использована в интерфейсе, то выполнение этого интерфейса завершится со следующей ошибкой:
Variable has no value: W_PROJECT1.Variable1
Если тоже самое произойдет с исторической или Last value переменной, и у переменной будет сохранено хотя бы одно значение - интерфейс выполнится без ошибок.
А теперь если мы захотим перейти от исторической к простой переменной, мы можем столкнуться с такой ситуацией, когда переменная, уже будучи Non-persistent тем не менее, получит значение из истории, сохраненной в репозитории. Бывает это в том случае, если в ДЕВ репозитории история переменной почищена, а в ПРОД - нет, и, при этом, переменная явно не обновляется в пакете.
5. Исторические переменные 3
Продолжение предыдущего пункта решил выделить в отдельный абзац. Если переводим историческую переменную в простую, обязательно необходимо перегенерировать сценарии, которые используют эту переменную. Так как эти сценарии будут продолжать генерировать новые записи в таблицах репозитория, хранящих исторические значения для переменной.
6. Переменные Last Value
Подтип исторических. Просто используется последнее значение, вместо привязки к дате. В чем-то удобнее исторических, в чем-то нет. С ними стоит опасаться моментов, описанных выше.
6. Значение по умолчанию
Удобный механизм, кроме всего прочего, создания констант, а не переменных. В случае, если есть желание использовать как константы - рекомендую придерживаться правила именования, чтобы было понятно, что это константы, и, во-вторых - запретить, после создания, редактирование этих переменных разработчиком.
6. Наименование переменной
Имя переменной регистрозависимо. Несмотря на это, у меня встречалась ситуация, когда одна и та же переменная, в разных регистрах, интерпретировалась Дизайнером неправильно.
Выражалось это, в том числе, и в том, что отображалось в разделе Used in этой переменной; ну и сам интерфейс не работал корректно.
7. Обновить переменную в процедуре нельзя
К сожалению, обновить переменную в процедуре нельзя. Речь о переменных, которые являются проектными или глобальными. По крайней мере, пока я не знаю такого способа. Можно использовать еще более локальные переменные, например, в виде переменных Jython, которые бы обновлялись в модуле знаний (Knoweledge Module), и которые доступны только в пределах шагов этого модуля.
8. В пакете переменные могут
- быть объявлены (Declare Variable);
- участвовать в логическом сравнении (Evaluate Variable);
- обновить свое значение (Refresh variable);
- получить значение (Set Variable). Здесь возможен вариант установки нового значения или инкрементации существующего.
В интерфейсах, процедурах и модулях знаний переменные могут только использоваться. Т.е. вместо них будет использовано их значение.
9. Передача значения переменной в сценарий
Если в пакете используется объявление переменной, сценарий, сгенерированный из этого пакета, может получить актуальное значение этой переменной из вызывающего пакета. В сценарий можно передавать значение для переменной из другого проекта!
В сценарий, сгенерированный непосредственно из интерфейса, переменные можно передавать таким же способом.
Значение переменной, установленное в пакете (передачей параметра или обновлением), доступно дальше в тех объектах, которые выполняются далее в пакете: интерфейсах, процедурах, обновлениях других переменных.
10. Значение переменной в Операторе
Значение в Операторе отображается в виде #Проект.Переменная именно по причине того, что при перезапуске сценария переменной может быть присвоено старое значение, актуальное на дату первого запуска.
Было бы здорово, если бы для простых, Non-persistent, переменных, показывалось их значение. Тогда бы не пришлось делать вот такие вещи.
Другие посты, связанные с переменными можно найти по этой ссылке.
А как сравнить значения двух переменных в пакете?
ОтветитьУдалитьДак в общем-то вот так примерно:
ОтветитьУдалитьhttp://odi-usage.blogspot.com/2010/10/2-odi.html
а если в одну переменную типа alphanumeric юзер вбивает дату, например, '28.02.2011', в вторую переменную типа date автоматически кладется текущая дата. И нужно проверить, что первая меньше второй. Возникает ошибка, что переменные разных типов... Неявного преобразования типов понятно не происходит. А явное преобразование тоже не происходит, потому что пакет - это объект, непривязанный к конкретной технологии (oracle, sybase и др.)
ОтветитьУдалитьПриходится писать процедуру для сравнения двух переменных разных типов с вызовом пользовательского исключения, чтобы выполнение пакета могло пойти по стрелочке "KO" после выполнения этой процедуры.
ОтветитьУдалитьИнтересный подход.
ОтветитьУдалитьЯ попробую написать сегодня отдельный пост на тему того, как бы я пробовал решать данную задачу.
Но только уже после работы...