Использование языка perl

Обработка файлов формата DBF

Для взаимодействия с файлами этого формата существует специальный модуль — Xbase.pm На текущий момент поддерживается только возможность чтения таких файлов. Этот модуль подключается стандартным образом: use Xbase;

Новый Xbase объект создается следующим образом:

$database = new Xbase;

Будет создан объект $database, который в дальнейшем будет использоваться для взаимодействия со всевозможными методами, которые поддерживает модуль. Доступ к базе данных осуществляется следующим образом:

$database->open_dbf($dbf_name,$idx_name);

Мы ассоциировали DBF-файл и необязательный индексный файл с объектом. Чтобы определить тип (database type) можно сделать следующее:

print $database->dbf_type;

Вернется строка, которая, если Xbase файл открыт, будет содержать значение DBF3, DBF4 или FOX. Чтобы узнать дату последнего обновления делается следующее:

print $database->last_update;

Возвращает строку с датой.

Чтобы узнать номер последней записи можно сделать следующее:

$end=$database->lastrec;

Вернется номер последней записи в файле с базой данных.

Информацию о статусе базы данных можно посмотреть следующим образом:

$database->dbf_stat;

В стандартный выходной поток будет напечатана информация о статусе и структуре базы данных. Этот метод работает аналогично команде display status.

Посмотреть информацию о статусе индексного файла можно используя метод idx_stat:

$database->idx_stat;

Печатает в стандартный выходной поток (STDOUT) информацию о статусе открытого IDX-файла.

Для того чтобы перейти на начало файла есть метод go_top:

$database->go_top;

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

Для того чтобы перейти на конец файла есть метод go_bottom:

$database->go_bottom;

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

Чтобы перейти на следующую запись есть метод go_next:

$database->go_next;

Эквивалентно команде skip 1, которая передвигает курсор на следующую запись.

Чтобы перейти на предыдущую запись есть метод go_prev:

$database->go_prev;

Эквивалентно команде skip -1, которая передвигает курсор на предыдущую запись.

Есть возможность осуществить поиск по заданному ключу:

$stat=$database->seek($keyvalue);

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

Чтобы узнать номер записи, на которой стоит курсор можно использовать следующую команду:

$current_rec=$database->recno;

Метод bof возвращает значение true, если курсор находится в самом начале файла.

if ($database->bof) {
    print " At the very top of the file \n";
}

Аналогично действует метод eof:

if ($database->eof) {
    print " At the very end of the file \n";
}

Чтобы прочитать содержимое какого-либо поля записи можно поступить так:

print $database->get_field("NAME");

Возвращает строку с содержимым поля. Если данная запись помечена для удаления, то использует псевдоимя поля _DELETED.

Чтобы прочитать значения полей записи в массив можно поступить так:

@fields = $database->get_record;

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

Для закрытия базы данных используется метод close_dbf.

$database->close_dbf;

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

— Скачать исходник

Код:

#!/usr/bin/perluse Xbase;# подключение модуля$database = new Xbase;# создание объекта$d = «/home/smit/employee.dbf»;# имя файла с базой$i = «/home/smit/employee.cdx»;# имя индексного файла$database->open_dbf($d,$i);# открываем базу данных$database->dbf_stat;# печатаем статус и структуру# базы данных$database->idx_stat;# печатаем статус и структуру# индексов@fields = $database->get_record;print @fields,»\n»;# печатаем содержимое текущей записиprint $database->last_update, «\n»;# печатаем дату последнего обновления$end = $database->lastrec;print $end;#печатаем номер последней записи

Справочные материалы

Для дальнейшего изучения темы рекомендуется чтение следующей документации:

  • perlguts — введение во внутренности Perl;
  • perlapi — документация по API функциям Perl;
  • perlxs — документация по XS;
  • perlxstut — вводное руководство с хорошими примерами по созданию XS;
  • perlapio — документация по работе с интерфейсом PerlIO в XS.

Google также выдаёт много интересных ссылок, но надо быть внимательным, поскольку очень много материалов уже достаточно сильно устарели. Лучше ориентироваться на последнюю актуальную документацию в составе дистрибутива Perl. Успехов в изучении!

■ Владимир Леттиев

Pinto — собственный CPAN из коробкиВведение в разработку web-приложений на PSGI/Plack. Часть 2.

Викторина интересных запросов, которые имели место в реальности

Двойной to_date

Это была явная ошибка, но значимого влияния не оказывала. Однако очень изящно. Попробуйте в Oracle (PG, понятно, не пропустит из-за более строгой типизации):

У меня результат выдал тот же день и месяц, но «нулевой» год — 0020. Хотя, вероятно, зависит от nls.

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

Несколько ограничений ROWNUM
Встретился такой запрос:

А как я уже говорил выше — FETCH ONLY в подзапросах не работает. Решение — а зачем здесь внутренние rownum? Разве изменится результат, если их убрать?

Ограничение по периоду

Многие массивы данных имеют месячную динамику (чаще всего счета, начисления и все что связано с ежемесячными платежами).

Выбор значений за месяц:

Лишний подзапрос к dual, отказ от использования индекса по периоду. Меняем, приводим в нужный вид (where PERIOD >= … and < …).

Oracle всемогущий, что ж ты делаешь то?

Запрос очень изящный. Мне одному кажется, что стандарты SQL здесь нарушаются? Нет, не одному, PG обычно со мной солидарен, в нем не работает.

На самом деле Оракл посчитал просто запрос «без каунта», а сверху еще над результатом «каунт» навесил. Изящно, но надо переделать:

Результат идентичен.

Модуль отчетности

Фактически, основное мерило качества интеграции — идентичность данных в отчетах. Скрипты отчетов у нас оказались сложными, этому будет посвящен весь следующий раздел. Здесь было принято следующее решение — дорабатываем максимум скриптов, которые возможно, в «универсальный вид», чтобы они запускались на обоих базах. Затем убеждаемся, что «новые запросы» выдают идентичный результат (равный старому) и на oracle и на pg. Выводим эти запросы на прод oracle — чтобы потом было легче при окончательной миграции.

А как мы будем сравнивать данные отчетов, полученных из двух баз данных? Формировать отчеты стандартным способом (Excel), после чего сравнивать данные отчетов другим каким-либо способом?… Можно, но сложновато. А если много итераций сверки — то еще более сложновато. Нашли способ проще — создали «слепки» отчетов на обоих сторонах (create table as select). Можно и не создавать, а делать представления. Перелили оракловую таблицу в PG через fdw (можно и не переливать, а делать «на ходу»). А дальше дело техники — select from таблица1 except select from таблица2. Должна получиться пустота, если множества одинаковы. Если будете этот трюк делать в Oracle — вместо except напишите minus.

Perl API

Документация perlapi содержит список и описание всех публичных (доступных для использования в расширениях) функций. Perl API не является каким-то фиксированным набором функций, как и сам язык Perl, его C API претерпевает изменение: появляются новые функции, исчезают устаревшие. С каждым новым мажорным релизом Perl происходит закрепление нового API и в минорных выпусках стабильных версий API не изменяется. Именно по этой причине при установке новой мажорной версии Perl всегда требуется пересборка всех аппаратно-зависимых модулей. Как правило, поддерживается обратная совместимость, поэтому кроме пересборки никаких других манипуляций может не потребоваться. Но для надёжности существуют механизмы, о которых будет сказано чуть позже, которые позволяют без особых усилий поддерживать возможность сборки и работы ваших расширений на старых версиях Perl.

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

Например, создание новых переменных:

  • — создаёт новый скаляр и резервирует под него байт (дополнительный 1 байт зарезервирован под нуль-символ);
  • — создание нового массива;
  • — создание нового хеша.

Как видно, функции создания имеют общий вид: суффикс + возвращаемый тип данных (в верхнем регистре). Тип данных, который получит создаваемый скаляр может конкретизироваться суффиксом (в нижнем регистре), например функции:

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

Для доступа к значению (с выполнением преобразования), содержащимся в переменной, используются функции вида:

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

  • — получить длину массива;
  • — получить стеш (хеш-таблица символов переменных пакета).

Также присутствует набор макросов, название которых пишется полностью в нижнем регистре:

  • — очистить массив;
  • — получить массив по имени глобальной переменной;
  • — получить заданную Perl-подпрограмму.

Принцип именования также интуитивно понятен: , и подобное — указывают на тип данных, а дополнительные суффиксы и префиксы раскрывают суть выполняемой операции.

Также можно обратить внимание, что в названиях разных функций в названии типа можно увидеть дополняющие символ, например, cvn, pvf, pvs. В этом случае, под — понимается длина (т.е

в функции есть параметр, задающий длину ), — использование в функции параметра формата (), — статичной строки . Например:

  • — копирует одну строку в конец строки в ;
  • — копирует указанное число байтов из одной строки в конец другой;
  • — тоже самое, что и только копирует литеральную строку (нуль-терминированную);
  • — обрабатывает аргумента также как , добавляя отформатированный вывод в .

Глобальные переменные Perl API начинаются с префикса , например: — это , — длина строки, которая используется по умолчанию в операциях без указания длины строки.

Структуры управления

Perl имеет несколько видов управляющих структур.

Он имеет блочно-ориентированные структуры управления, аналогичные тем, что в языках программирования C, JavaScript и Java . Условия заключены в круглые скобки, а контролируемые блоки — в фигурные скобки:

label while ( cond ) { … }
label while ( cond ) { … } continue { … }
label for ( init-expr ; cond-expr ; incr-expr ) { … }
label foreach var ( list ) { … }
label foreach var ( list ) { … } continue { … }
if ( cond ) { … }
if ( cond ) { … } else { … }
if ( cond ) { … } elsif ( cond ) { … } else { … }

Если контролируется только один оператор, модификаторы операторов обеспечивают более сжатый синтаксис:

statement if cond ;
statement unless cond ;
statement while cond ;
statement until cond ;
statement foreach list ;

Логические операторы короткого замыкания обычно используются для воздействия на поток управления на уровне выражения:

expr and expr
expr && expr
expr or expr
expr || expr

(Операторы «и» и «или» аналогичны операторам && и ||, но имеют более низкий приоритет , что упрощает их использование для управления целыми операторами.)

Ключевые слова управления потоком (соответствующие C ), (соответствующие C ) , и являются выражениями, поэтому их можно использовать с операторами короткого замыкания.

Perl также имеет две неявные конструкции цикла, каждая из которых имеет две формы:

results = grep { … } list
results = grep expr, list
results = map { … } list
results = map expr, list

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

Вплоть до выпуска 5.10.0 в Perl 5 не было оператора switch . Начиная с 5.10.0, доступен оператор многостороннего перехода с именем / , который принимает следующую форму:

use v5.10; # must be present to import the new 5.10 functions
given ( expr ) { when ( cond ) { … } default { … } }

Синтаксически эта структура ведет себя аналогично операторам switch в других языках, но с некоторыми важными отличиями. Самым большим из них является то, что в отличие от структур switch / case, операторы given / when прерывают выполнение после первого успешного перехода, а не ждут явно определенных команд прерывания. И наоборот, явные s необходимы для имитации поведения переключения.

Для тех, кто не использует Perl 5.10, документация Perl описывает полдюжины способов достижения того же эффекта с помощью других структур управления. Также имеется модуль Switch, который обеспечивает функциональность по образцу родственного языка Raku . Он реализован с использованием исходного фильтра , поэтому его использование неофициально не рекомендуется.

Perl включает оператор, но он используется редко. Ситуации, когда a требуется на других языках, не так часто встречаются в Perl из-за широты возможностей управления потоком.

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

Работа с переменными

Переменные могут быть заданы двумя способами:

Если уже была определена &&variable, то значение будет подставлено во все дальнейшие переменные как &variable так и &&variable.

Если была определена &&variable, и скрипт запущен повтороно в ходе той же сессии работы с SQLplus — будет использовано старое значение переменной. Чтобы этого избежать — можно запрашивать интерактивный ввод в скрипте принудительно, испольтзуя команду:

ACCEPT можно использовать для валидации:

Для ввода дат в определенном формате:

SQL*Plus поддерживает четыре типа переменных: CHAR, NUMBER, BINARY_FLOAT, and BINARY_DOUBLE. При вводе с клавиатуры переменная будет типа CHAR.

Несмотря на это, можно использовать NEW_VALUE, чтобы задать числовую переменную, полученную как результат запроса.

Bind-переменные могут использоваться для передачи данных между PL/SQL и SQL блоками:

Присвоить bind-переменной значение &-переменной:

Вывести значение bind-переменной:

Присвоить &-переменной значение bind-переменной:

Получаем OUT-параметр процедуры в bind-переменную:

Условное выполнение в SQLplus:

Пример скрипта, принимающего несколько переменных на вход в формате c возможностью задать дефолтные значения:

Подходы к миграции

Настало время поговорить о подходах. Будем честны, опыта такой миграции в нашей команде еще не было. Зато появилась хорошая экспертиза на PG, так как последние проекты разрабатываем на нем. Поэтому для начала надо оглядеться, как люди это делают, почитать, поспрашивать. Здесь нам повезло, как раз не так давно мы были на pgConf, на котором было несколько очень качественных докладов на тему миграции. Вот они, например, от 2020 года — доступны всем желающим: https://pgconf.ru/2020/talks-and-tutorials. Если не смотрели, начните например, с Анатолия Афиногенова (РЖД) — просто, доступно и познавательно. Но там и другие очень интересные.
В процессе гугления интернета был найден очень интересный фолиант — Oracle to Azure Database for PostgreSQL Migration Guide. Пусть вас слово «Azure» не отпугнет, там все по делу и все про PostgreSQL. Очень подробно, 313 страниц на английском языке.
Технически же пойдем таким путем:

  1. Организуем схожую продуктивной площадку серверов (в качестве операционки была выбрана наша «родная» RedOS 7.2 «Муром»);
  2. Устанавливаем все «схожим образом». В качестве СУБД взяли самую свежую на сегодняшний момент PostgresPro Standard 13.

Особенности мигрируемой БД

Приложение у нас, как я называю «backend-центрированное», что означает:

  1. Используется ORM (hibernate);
  2. В БД не так много процедурного кода (почти нет);
  3. Используется не так много «изысков» SQL, как могло бы. Хотя, как выяснилось, так казалось на первый взгляд. Вообще, язык SQL очень хорошо стандартизирован и, казалось бы, должен «практически одинаково» работать на всех СУБД, которые заявляют совместимость со стандартом SQL-XX (здесь XX – это год выпуска стандарта). В реальной жизни все совсем иначе, разницу диалектов SQL можно (шутливо) проиллюстрировать следующей картинкой:
  4. В коде вперемежку встречается «native SQL» и «Hibernate QL». Также используется QueryDSL.

Доработка приложений

Вот мы и добрались до доработки приложений. Для начала давайте разберемся, где в приложениях мира java / spring живут sql запросы.

  1. В объектах repository. Как было написано выше, запросы бывают «native» и, назовем в рифму, «hibernative». Считаем, что первые надо дорабатывать, вторые скорее всего нет (оказалось, что все равно нужно);
  2. Явно в коде других модулей. Обычно такого не бывает, но иногда встречается;
  3. QueryDSL. Да, он у нас используется. Здесь история не про чистые SQL запросы, а про особенности и типы данных, там встречаются OracleTemplate и видимо связанные с этим особенности;
  4. Модуль интеграции. Модуль интеграции имеет свой xml настроечный файл, где прописаны все запросы извлечения данных. Извлечение у нас особо не меняется, но запросы вставки надо пересмотреть.
  5. Модуль отчетности. У него также есть настроечный файл yml где прописаны SQL скрипты формирования отчетов. Это, наверное самый большой блок, так как запросы здесь оказались максимально сложными для преобразования.
    В итоге приложения дорабатываем следующим образом:
    5.1. При старте приложение определяет — оно запущено под ora или под pg? Сделали это просто анализируя jdbc строку подключения. Повезло, что все настроечные и конфигурационные файлы — в философии приложения это не часть приложения, а конфигурация. И при старте приложения просто указывается, где лежат конфигурационные файлы для данного инстанса.
    5.2. Максимум запросов стараемся делать переносимыми между базами. Там где невозможно, то разводим код явно (if (ora) { ora code } else { pg code });

Проблемы
Куда без них.
Наверное, многих будет интересовать, какие проблемы придётся решать кроме тех, которые уже обозначены (чуть ранее про типы, про установку расширений).Первой и самой очевидной стала проблема со Spring Boot 1.5. По каким то неведомым причинам он отказался подставлять имя схемы в запросы (которые сам генерирует, не native). А так как обращения у нас идут к разным схемам, это было критично. Гугл особо не помог, но одно решение рассмотрели — использовать кастомный класс NamingStrategy, в котором учесть эти нюансы. Решение бы сработало, но решили, что это костыль и решили переходить на Spring Boot 2.Запуск приложений у нас оформлен как сервисы (systemctl), почему то под RHEL запуск приложения работает строкой «ExecStart=/path/to/spring_boot_based.jar», тогда как под RedOS заработало только если указать «ExecStart=/bin/bash /path/to/spring_boot_based.jar».В pg есть свой «модный» преобразователь типов — двойное двоеточие, например 1.23::int. Но вот эти двоеточия не любит hibernate, который начинает думать, что это параметры запроса. Поэтому — только старый добрый cast(x as integer).
Также pg намного (очень намного) более строго относится к типам данных. И есть еще одна проблема, которая называется «null в параметрах процедур». Т.е. если у нас в Repository присутствует запрос «select * from some_function(parameters)», то при попытке ее вызова pg кроме названия проверяет перечень и типы переданных параметров (в pg функции могут быть перегруженными), после чего вызывает нужную. Null его ставит в тупик, так как он определяет его как unknown. Возможно, тут есть какой-то workaround, но сходу мы его не нашли.Квотированные идентификаторы
SQL язык старый, раньше было «не модно» различать большие и маленькие буквы, так что он изначально родился регистронезависимым. Потом кто-то придумал, что было бы неплохо дать возможность называть колонки не техническими именами, а хоть как — хоть по-русски, хоть с пробелами. Вот так и возникли квотированные (т. е. в кавычках) идентификаторы. Сколько ж они привносят проблем …

Так вот, если идентификатор не квотирован, то он регистронезависим. Если квотирован, то должен писаться в точности.

В Oracle — по умолчанию все «воспринимается» большими буквами. В pg наоборот — маленькими. Что здесь было у нас — модуль отчетности (о нем ниже) был настроен на точное совпадение идентификаторов колонок, поэтому во всех запросах они были квотированы. Пришлось переделывать, учить модуль, убирать квотирование. Максимум проблем тут с использованием «зарезервированных» слов в названиях колонок (да, это плохо, но это было «на старте»). Например мы пишем table.some_field. Тут все хорошо. А если table.type? Тут плохо. Слово type зарезервировано и движок БД, например во view переделает это в table.»TYPE» (или в table.»type» ?). А это уже — квотированный идентификатор. Поэкспериментируйте, это интересно.

Создание БД PG

Раз уж существует инструмент ora2pg, то им и попробуем воспользоваться. Написан он, похоже, аж на Perl’е, что впрочем его не портит. Были какие-то мелкие заморочки с его установкой, но в целом он вполне работает.
Было решено с его помощью преобразовать только таблицы, представления же создать руками. Пакетов и процедур — минимум, их тоже руками.
В целом инструмент отработал вполне достойно, выдав рабочий скрипт создания таблиц. Из минусов — все первичные ключи он мне сделал как numeric(22), пришлось переделывать на int8 (он же bigint, примерно он же bigserial).
И вот здесь возникает первая большая сложность

Стоит крайне пристально обратить внимание на типы полей. Лучше даже вообще составить таблицу по типам «было» — «стало» и ее придерживаться

Основные проблемы возникают с number — float — numeric. Также надо запомнить разницу в датах — в Oracle в дате есть время, в pg нет. Доступно про типы описано здесь: https://habr.com/ru/post/335716/
Важный организационный момент — всем объектом устроили ревизию, т. е. как минимум все таблицы и представления было решено снабдить комментарием, что это и зачем. Если комментария нет, то значит, что мы не знаем, что это за объект и как используется. Эта работа была сделана командой линейного развития проекта.
Таблицы создали, надо наполнять их данными. Напомню, система живая, каждый день в ней появляются данные, основных потоков три — интеграционный, расчетный и пользовательский ввод.
Здесь посчитали важным реализовать репликацию ora → pg, чтобы в каждый момент времени БД pg была максимально близка к БД ora (максимально — значит каждый день). Так родился модуль репликации.

Доработка особенностей SQL запросов

Вот мы и добрались до самой главной боли. Вроде бы SQL — язык стандартизированный, не должен сильно зависеть от конкретной СУБД «и все такое». Но мы взрослые люди, понимаем, что это неправда

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

работающие и там и там).

Начнем с простого.

Правило, которые надо запомнить на всю жизнь: в Oracle null + some_text = some_text.

Практически во всех других базах = null. Oracle периодически за это троллят:
Так было в версии 7, заметьте фразу — «в следующей версии Oracle7»:

И, более чем 20 лет спустя, в релизе 19c:

С этим связан любопытный трюк, как нам безошибочно определить в какой базе мы находимся, изначально не зная в какой (при условии установленного в PG расширения orafce):

nvl — просто меняем на coalesce не думая, все работает.decode — немного ворчим о многословности, но все же переделываем в case.
Чуть сложнее. sysdate. Помним, что у Oracle — время есть, в pg — нет. Поэтому в зависимости от контекста либо current_timestamp, либо current_date.rownum. Очень любят приложения на spring хоть какой-нибудь ключ. Часто делают «ровнум» — так как это дешево и сердито. Чем может ответить pg?

А вот Oracle не пустит вам over с пустыми скобками, так что нужно добавлять order by, при этом выбирать правильную сортировку, которая не приведет к тормозам запроса.

А если у нас в запросах «where rownum < X». Ответ pg: limit. Но в Oracle не сработает. Компромисс для обоих баз: fetch next X rows only. Минус компромисса — не будет работать в подзапросах (rownum работает, limit скорее всего тоже нет).Update. Апдейт «не любит указание алиса при присвоении». Т.е. update some_table t set t.some_field = … Oracle нормально, PG нет, убираем алиасы. Связано это с тем, что скорее всего поле с алиасом воспринимается как вычисленное значение и его можно использовать в правой части, но при присваивании — PG настаивает на голом поле. Не забываем, что у PG есть свой синтаксис «update from join», следует всегда использовать его — иначе будут проблемы с производительностью.Именованные подзапросы. PG не любит безымянные подзапросы, например select * from (select …). Нужно «алиасить» подзапрос. Но where x in (select …) вполне нормально, никакой алиас не нужен.Group by 1,2,3. Это не на тему миграции, просто отмечу — это прекрасная фича PG, которой нет в Oracle. Некоторые базы тоже ее реализуют (firebird например). Это мегаудобно.Форматирование числовых значений. Что у нас форматированием числовых значений? Оно есть, но оно разное и там, и там. Но нам по идее немного надо — вывести число с двумя знаками после запятой, причем если число целое, то вывести без знаков. Это у нас поле «пропускная способность», т. е. Мы ее хотим вывести, например «2 Мбит/с». Получилось вот так:

Разница только в том, что в Oracle разделитель — запятая, в PG — точка. Но в данном случае приемлемо (возможно, через nls это тоже можно дорешить).Последовательности (sequence).
А вот тут нас ждало разочарование. Синтаксис различный и к единому его привести не удалось. Ладно хоть не так часто встречается явный вызов сиквенсов.
Синтаксис

Рейтинг
( Пока оценок нет )
Editor
Editor/ автор статьи

Давно интересуюсь темой. Мне нравится писать о том, в чём разбираюсь.

Понравилась статья? Поделиться с друзьями:
Люкс-хост
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: