Миграция на PostgreSQL¶
План анализа объектов T-SQL перед переходом на PG SQL¶
1. Проанализировать таблицу SmartExpressions
Пример:
SELECT ID as ИД_смарта
,se.Name as Название
,se.SubcatID as ИД_Категории
,sub.Description as Категория
,iif(IsFilter=1,'фильтр','выражение') as Тип_смарта
,TSqlContent
FROM SmartExpressions as se
LEFT JOIN Subcategories as sub ON sub.SubcatID = se.SubcatID
WHERE TSqlContent is not NULL
AND IsDeleted = 0
2. Проанализировать таблицу SmartScripts
Пример:
SELECT ss.SubcatId as ИД_Категории
,sub.Description as Категория
,ss.Id
,ss.Description as Название
,ScriptCode
FROM SmartScripts as ss
LEFT JOIN Subcategories as sub ON ss.subcatid = sub.SubcatID
3. Проанализировать наличие отчетов FR: Администрирование — Бизнес-логика — Отчеты. Необходимо оценить количество строк без отметки «Системный» и количество строк, у которых в колонке "Блок" есть значение.
4. Проанализировать наличие нестандартных хранимых процедур и функций для портальных блоков: Администрирование — Интерфейс — Конструктор порталов. Необходимо проверить наличие нестандартных виджетов "График", "Таблица" и других типов, использующих хранимые процедуры или функции.
5. Проанализировать наличие нестандартных хранимых процедур, скалярных и табличных функций, представлений.
Для этого необходимо подсчитать количество имеющихся объектов нужных типов, выгрузить список и сравнить его с эталонным перечнем
Пример:
-- Посчитать количество объектов нужных типов
/*использовать USE databasename, чтобы видеть объекты не из master*/
USE databasename;
SELECT type, count(name) as 'Кол-во'
FROM dbo.sysobjects
WHERE type in ( 'P' /*процедуры*/ ,'FN' /*скалярные функции*/ ,'TF' /*табличная функция*/ ,'V'/*представление*/ )
GROUP BY type
-- Получить список объектов нужных типов
/*использовать USE databasename, чтобы видеть объекты не из master*/
USE databasename;
SELECT
name, type
FROM dbo.sysobjects
WHERE type in
(
'P' /*процедуры*/
,'FN' /*скалярные функции*/
,'TF' /*табличная функция*/
,'V' /*представление*/
)
ORDER BY type, name
-- При необходимости — выгрузка кода ХП и функций
/*использовать USE databasename, чтобы видеть объекты не из master*/
USE databasename;
SELECT routine_name, routine_type
/* реальная длина кода, не усеченная до 4000, как в столбце routine_definition */
,len(object_definition(object_id(routine_name))) as Реальная_длина_кода
/* раскомментировать, если нужно взять код процедуры */
--,object_definition(object_id(routine_name)) as real_routine_definition
FROM INFORMATION_SCHEMA.ROUTINES
WHERE routine_type in ('PROCEDURE','FUNCTION')
ORDER BY routine_type, routine_name
6. Проанализировать наличие SQL Server Agent -- Jobs, относящихся к конкретной БД, т.к. они могут использовать нестандартную хранимую процедуру.
Унификация TSQL — PGSQL в смартах¶
MS SQL (TSQL)
PostgreSQL (PGSQL)
Что делать. Есть ли универсальный вариант для работы в любом SQL
Сложность замены
Частота использования
Идентификаторы, транзакции и пр.
При обращениях к объектам можно использовать квадратные скобки : [table].[field]
Название объекта, заключенное в [] даст ошибку синтаксиса, нужно либо удалить скобки, либо использовать двойные кавычки (если в названии объекта присутствуют недопустимые символы): "table"."field"
Удалить []. Не использовать экранирование идентификаторов с помощью [] без необходимости. Использовать общий способ именования объектов, чтобы [] или «» не требовались.
Легко, но трудоемко
Постоянно
WITH (NOLOCK) или (NOLOCK), а также его аналог SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
Аналога нет
Удалить
Легко
Постоянно
Типы данных
Использование строк ограниченной переменной длины, типа: varchar(max), nvarchar(n)
varchar(n)
Указать значение вместо "max" для varchar(max);
Исправить nvarchar на varchar (скорее всего, есть другой способ).
Использовать общий тип varchar(n)
Зависит от контекста
Средне
Работа с переменными
DECLARE @myvar INT SET @myvar = 5
SELECT * FROM somewhere WHERE something = @myvar
Самый простой из рекомендуемых способов — использовать CTE:
WITH vars AS (SELECT 5 AS myvar) SELECT * FROM somewhere,vars WHERE something = vars.myvar;
Пример для одной переменной:
WITH decl AS (SELECT '5' AS my_var)
SELECT my_var from decl
Пример для нескольких переменных:
WITH my_var (var1, var2) as (
values (5, 'foo')
)
SELECT *
FROM table1, my_var
/* т.е. используется CROSS JOIN */
WHERE something_from_table1 = var1
OR something_else = var2;
Сложно
Часто
Операторы, условия, циклы
SELECT TOP N ...
SELECT .... LIMIT N¶
TOP удалить, LIMIT добавить.
Использовать общий LIMIT.
Легко
Редко
ISNULL()
COALESCE()
Заменить ISNULL на COALESCE.
Использовать общий COALESCE.
Легко
Средне
IIF()
CASE WHEN...THEN
Заменить.
Использовать общий CASE.
Cредне
Редко
WHILE ... BEGIN ... END
WHILE ... LOOP... END LOOP
Добавить операторы LOOP, ограничивающие "тело цикла"
Легко
Редко
IF логическое-выражение BEGIN операторы
END
IF логическое-выражение
THEN операторы
END IF
При использовании более сложной конструкции вида:
IF-BEGIN-END-ELSE-BEGIN-END
в PG SQL может использоваться конструкция вида:
if-then-elseif-then-else-end if;
Cредне
Cредне
Функции работы со строками
Конкатенация строк:
- или CONCAT()
|| или CONCAT
Использовать общий CONCAT
Легко, но трудоемко
Постоянно
Определение длины строки:
LEN()
LENGTH()
Заменить
Легко
Редко
Определение расположения последовательности в строке:
CHARINDEX()
STRPOS()
Заменить
Легко
Редко
Вставка одной строки в другую с заданной позиции:
STUFF или STRING_AGG
STRING_AGG
Использовать общий STRING_AGG
Cредне
Редко
Дата, время, форматирование
Получение текущей даты и времени (локальное время):
GetDate()
CURRENT_TIMESTAMP
Заменить.
Использовать общий CURRENT_TIMESTAMP
Легко
Средне
Приращение даты-времени:
DATEADD
Пример:
select DATEADD(day,1,getdate())
функции:
interval или make_interval()
Пример:
select CURRENT_TIMESTAMP + interval '1 day';
select CURRENT_TIMESTAMP + make_interval(days => 1);
Переписать конструкцию.
Средне
Средне
Особенности написания SQL на PostgreSQL¶
При написании SQL на PostgreSQL нельзя использовать контекстные параметры smart-запросов SQL внутри конструкции DO $$ ... END $$;
Пример того, как нужно использовать контекстные параметры
;WITH myconstants (var0) as (
SELECT
LanguageID
FROM
Users
WHERE
UserID = @eventParam0
)
SELECT
CASE WHEN COALESCE(ld.Description, '') = '' THEN
REPLACE(REPLACE(t.Description, '<p>', ''), '</p>', '')
ELSE
REPLACE(REPLACE(ld.Description, '<p>', ''), '</p>', '')
END
FROM
Tasks t
LEFT JOIN (
SELECT Description
FROM Tasks_AllLocalized (@ContextID, (select var0 from myconstants) )
LIMIT 1
) ld on true
WHERE
TaskID = @ContextID;
Пример того, как не нужно использовать контекстные параметры
/*
DO $$
DECLARE
Lang INTEGER;
BEGIN
SELECT
LanguageID
INTO Lang
FROM
Users
WHERE
UserID = @eventParam0;
CREATE TEMPORARY TABLE temp_ld AS
SELECT
Description
FROM
Tasks_AllLocalized (@ContextID, Lang )
LIMIT 1;
END $$;
SELECT
CASE WHEN COALESCE(ld.Description, '') = '' THEN
REPLACE(REPLACE(t.Description, '<p>', ''), '</p>', '')
ELSE
REPLACE(REPLACE(ld.Description, '<p>', ''), '</p>', '')
END
FROM
Tasks t
LEFT JOIN temp_ld ld ON TRUE
WHERE
TaskID = @ContextID;
*/
Рекомендации¶
При создании функций, таблиц и представлений в базе данных следуйте приведенным ниже правилам. Это обеспечит корректную работу приложения и избежание распространенных ошибок.
1. Все создаваемые объекты (функции, таблицы, представления) должны размещаться в схеме базы данных custom.
2. Объекты БД следует создавать под пользователем, учетная запись которого используется приложением для подключения к базе — d10taskreader. Если объект создан под другим пользователем, необходимо выдать ему право владения созданным объектом.
3. При создании объектов не заключайте их названия в двойные кавычки.
Некорректно:
CREATE OR REPLACE VIEW custom."TestViewCat62087"
Корректно:
CREATE OR REPLACE VIEW custom.TestViewCat62087
Использование кавычек делает имя объекта чувствительным к регистру, что может привести к ошибкам при обращении из приложения (объект может быть не найден). Названия без кавычек интерпретируются независимо от регистра.
4. При заполнении поля «SQL-функция доступа» в настройках дополнительного параметра не используйте квадратные скобки вокруг имени функции.
Некорректно (MSSQL-синтаксис, не работает на PG):
[dbo].[MyAccessFunction]
Корректно:
custom.MyAccessFunction
ℹ️ Начиная с версии 2.267 Андромеда, при импорте конфигурации через утилиту переноса квадратные скобки в именах функций доступа к ДП автоматически удаляются на PG-окружениях. При ручном заполнении настроек правило по-прежнему применяется вручную.