Как сохранить данные с запятой в символах, которые проходят через триггер? - PullRequest
0 голосов
/ 14 мая 2018

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

Это мой триггер:

CREATE TRIGGER "public.usuarios_trigger_process_audit"


BEFORE INSERT OR UPDATE OR DELETE
  ON usuarios

FOR EACH ROW
  EXECUTE PROCEDURE process_audit();

Это ПРОЦЕДУРА:

DECLARE
    newtable text;
    col information_schema.columns %ROWTYPE;
    txtquery text;
    line_old TEXT;
    tmpquery text;
    i int;
    columns_old text[];
BEGIN
    IF ( TG_TABLE_SCHEMA = 'public' ) THEN
    SELECT TG_TABLE_NAME || '_actividad' INTO newtable;    /*  select TG_RELNAME || '_actividad' into newtable; */
    ELSE
    SELECT TG_TABLE_SCHEMA || '_' || TG_TABLE_NAME || '_actividad' INTO newtable;    /*  select TG_RELNAME || '_actividad' into newtable; */
    END IF;

    PERFORM creartablaactividad( TG_TABLE_SCHEMA, TG_TABLE_NAME );

    IF ( TG_OP = 'DELETE' ) THEN
    line_old := TRIM( substr(OLD::text,2,(select length(OLD::text)-2)) );
    columns_old := STRING_TO_ARRAY( line_old, ',' );
    i := 0;
    tmpquery := '''' || array_to_string(columns_old, ''',''') || '''';
    tmpquery := replace(tmpquery,','''',',',NULL,');
        /* SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, inet_client_addr(), now (), ''D'',' || replace(tmpquery, ',''''',',NULL') into txtquery; */
        SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, now (), ''D'',' || replace(tmpquery, ',''''',',NULL') into txtquery;
        EXECUTE txtquery;
        RETURN OLD;
    ELSIF ( TG_OP = 'UPDATE' ) THEN
    line_old := TRIM( substr(OLD::text,2,(select length(OLD::text)-2)) );
        columns_old := STRING_TO_ARRAY( line_old, ',' );
        i := 0;
        tmpquery := '''' || array_to_string(columns_old, ''',''') || '''';
        tmpquery := replace(tmpquery,','''',',',NULL,');
        tmpquery := replace(tmpquery,','''',',',NULL,');
        /* SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, inet_client_addr(), now (), ''ANT'',' || replace(tmpquery, ',''''',',NULL') into txtquery; */
        SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, now (), ''ANT'',' || replace(tmpquery, ',''''',',NULL') into txtquery;
        EXECUTE txtquery;
        line_old := TRIM( substr(NEW::text,2,(select length(NEW::text)-2)) );
        columns_old := STRING_TO_ARRAY( line_old, ',' );
        i := 0;
        tmpquery := '''' || array_to_string(columns_old, ''',''') || '''';
        tmpquery := replace(tmpquery,','''',',',NULL,');
        /* SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, inet_client_addr(), now (), ''U'',' || replace(tmpquery, ',''''',',NULL') into txtquery; */
        SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, now (), ''U'',' || replace(tmpquery, ',''''',',NULL') into txtquery;
        EXECUTE txtquery;
        RETURN NEW;
    ELSIF ( TG_OP = 'INSERT' ) THEN
    line_old := TRIM( substr(NEW::text,2,(select length(NEW::text)-2)) );
        columns_old := STRING_TO_ARRAY( line_old, ',' );
        i := 0;
        tmpquery := '''' || array_to_string(columns_old, ''',''') || '''';
        tmpquery := replace(tmpquery,','''',',',NULL,');
        /* SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, inet_client_addr(), now (), ''I'',' || replace(tmpquery, ',''''',',NULL') into txtquery; */
        SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, now (), ''I'',' || replace(tmpquery, ',''''',',NULL') into txtquery;
        EXECUTE txtquery;
        RETURN NEW;
    END IF;

    RETURN NULL; -- result is ignored since this is an AFTER trigger
END;

У меня в таблице обычно:

enter image description here

Ошибка:

enter image description here

1 Ответ

0 голосов
/ 14 мая 2018

Вы можете использовать format(), чтобы значительно упростить создание динамического SQL-запроса, поскольку он будет автоматически корректно обрабатывать идентификаторы и литералы.Люди обычно упускают из виду то, что вы можете расширить одно выражение записи для всех его столбцов, используя (...).* - это также работает для NEW и OLD переменных записи в триггере, например, select (new).*

* 1007.* Вы также можете передавать переменные в динамический SQL с помощью ключевого слова using оператора execute.Нет необходимости преобразовывать запись назад и вперед между записью и текстовым представлением.

Используя эту возможность, ваша функция триггера может быть упрощена до:

DECLARE 
  l_sql text;
BEGIN
    IF TG_TABLE_SCHEMA = 'public' THEN
      newtable := TG_TABLE_NAME || '_actividad';
    ELSE
      newtable := TG_TABLE_SCHEMA || '_' || TG_TABLE_NAME || '_actividad';
    END IF;

    PERFORM creartablaactividad(TG_TABLE_SCHEMA, TG_TABLE_NAME);
    l_sql := 'INSERT INTO actividad.%I  SELECT current_user, current_timestamp, %L, ($1).*';

    IF TG_OP = 'DELETE' THEN
      execute format(l_sql, newtable, 'D') using OLD;
      RETURN OLD;
    ELSE
      -- covers UPDATE and INSERT
      execute format(l_sql, newtable, 'U') using NEW;
      RETURN NEW;
    END IF;

    RETURN NULL; -- result is ignored since this is an AFTER trigger
END;

Использование заполнителей, таких как %I и %L также позволяют определить фактический SQL только один раз и использовать его повторно.Эти «параметры» заменяются функцией format() (которая сохраняет $1)

Обратите внимание на использование ($1).* внутри строки SQL.Это заставит оператор execute расширить параметр записи $1 на все его столбцы.Сама запись передается «изначально» с ключевым словом USING.


Использование INSERT без целевого списка столбцов (insert into some_table ... вместо insert into some_table (col1, col2, ...) ...) - довольно хрупкая вещьсделать.Если источник и цель не совпадают, вставка может потерпеть неудачу довольно легко.,


Если вы не запускаете масштабную отчетность по таблицам аудита (где наличие явных имен столбцов было бы намного эффективнее), вы можете подумать о более универсальном триггере аудита с использованием JSON илиHSTORE столбец для хранения всей записи.Доступно несколько готовых триггеров аудита:

...