Вставить в таблицу с 200 столбцами - PullRequest
1 голос
/ 21 марта 2020

У нас есть таблица в нашей Oracle БД с 200 столбцами, что мы должны сделать Вставить в нее, и у нас есть программа C, которая вставляет запросы в эту таблицу и использует Pro *C для вызова сохраненной запрограммируйте в oracle DB для выполнения этой работы.

В настоящее время мы сериализуем все поля в формате TLV {Tag-Length-Value} и имеем функцию с параметром Varchar2 (сериализованный список полей). например:

008603701212345678901201100611111104800622222220000633333320100644444401201420200321164712

более читабельно для человека:

0086 037 012 123456789012 011 006 111111 048 006 222222 200 006 333333 201 006 444444 012 014 20200321164712

, что означает:

String Len:86
Field037 with len 12:123456789012
Field011 with len 6:111111
Field048 with len 6:222222
Field200 with len 6:333333
Field201 with len 6:444444
Field012 with len 14:20200321164712

каждое из этих полей отображается на поле в таблице, Хранимая программа анализирует огромную строку и заполняет ее в тип строки и, наконец, вставляет строку в таблицу.

В течение многих лет она работала хорошо, но когда мы готовились к большему количеству запросов (таким образом, к большему количеству вставок), наш администратор БД говорит мы используем много ЦП для десериализации TLV. Поэтому нам нужно изменить наш метод вставки.

I В настоящее время мы создали структуру в C и сопоставили все поля в ней и вызвали:

typedef struct 
{ 
    char  field37[12+1];
    char  field11[6+1];
    char  field48[6+1];
    char  field200[6+1];
    char  field201[6+1];
    char  field12[14+1];
} NewRecord; 
NewRecord newRecord;
TlvToStruct(sTlv, &newRecord);//Mapper Function
EXEC SQL INSERT INTO MY_TABLE(FIELD37, FIELD11, FIELD200, FIELD201, FIELD12) VALUES(:newRecord);
EXEC SQL COMMIT WORK RELEASE;

Этот подход пока работает хорошо, но У меня вопрос: стоит ли мне продолжать разработку и добавлять все 200 полей в эту структуру и использовать этот подход, или лучше использовать вызов PL SQL (возможно, разработать и использовать другую функцию вставки) вместо этой SQL Вставка?

В настоящее время я знаю о преимуществах PL SQL, но здесь есть некоторые проблемы:

1- Pro*C does not support PLSQL Records

[Oracle Document] 1

2- It is not so reasonable to have a function with 200 parameters!
3- We use Types in plsql but never used them in Pro*C(actually I tried once and I failed long ago)

Я попытался описать проблему здесь, если неясно, пожалуйста, спросите

Спасибо

============= ===========================================

РЕДАКТИРОВАТЬ:

Вот наши старые функции Get_Tag и Put_Tag:

FUNCTION GET_TAG(P_TAG_NAME IN VARCHAR2, P_TLV_STRG IN VARCHAR2, P_TAG_LEN OUT NOCOPY PLS_INTEGER, P_TAG_VALUE OUT NOCOPY VARCHAR2)
    RETURN PLS_INTEGER IS
    V_COUNTER_LOOP                          PLS_INTEGER := 1;

    V_TLV_STRG                              VARCHAR2(4096) := SUBSTR(P_TLV_STRG, 5);
BEGIN
    P_TAG_VALUE   := NULL;

    P_TAG_LEN     := 0;

    WHILE V_COUNTER_LOOP < LENGTH(V_TLV_STRG) LOOP
        IF SUBSTR(V_TLV_STRG, V_COUNTER_LOOP, 3) = P_TAG_NAME THEN
            P_TAG_LEN     := TO_NUMBER(SUBSTR(V_TLV_STRG, V_COUNTER_LOOP + 3, 3));

            P_TAG_VALUE   := SUBSTR(V_TLV_STRG, V_COUNTER_LOOP + 6, P_TAG_LEN);

            RETURN (DECLARATION_CST.OK);
        END IF;

        V_COUNTER_LOOP   := V_COUNTER_LOOP + 6 + TO_NUMBER(SUBSTR(V_TLV_STRG, V_COUNTER_LOOP + 3, 3));
    END LOOP;

    RETURN 0;
EXCEPTION
    WHEN OTHERS THEN
        RETURN -1;
END GET_TAG;

==================================== ============================

FUNCTION PUT_TAG(P_TAG_NAME IN VARCHAR2, P_TAG_VALUE IN VARCHAR2, P_TLV_STRG IN OUT NOCOPY VARCHAR2)
    RETURN PLS_INTEGER IS
    V_COUNTER_LOOP                          PLS_INTEGER := 0;

    TMP_VARCHAR                             VARCHAR2(4096);
BEGIN
    P_TLV_STRG       := SUBSTR(P_TLV_STRG, 5);

    V_COUNTER_LOOP   := 1;

    WHILE V_COUNTER_LOOP < LENGTH(P_TLV_STRG) LOOP
        IF SUBSTR(P_TLV_STRG, V_COUNTER_LOOP, 3) = SUBSTR(P_TAG_NAME, 1, 3) THEN
            TMP_VARCHAR   :=
                   SUBSTR(P_TLV_STRG, 1, V_COUNTER_LOOP - 1)
                || SUBSTR(P_TAG_NAME, 1, 3)
                || TO_CHAR(NVL(LENGTH(P_TAG_VALUE), 0), 'FM000')
                || P_TAG_VALUE
                || SUBSTR(P_TLV_STRG, V_COUNTER_LOOP + 6 + TO_NUMBER(SUBSTR(P_TLV_STRG, V_COUNTER_LOOP + 3, 3)));

            P_TLV_STRG   := TO_CHAR(LENGTH(TMP_VARCHAR), 'FM0000') || TMP_VARCHAR;

            RETURN (DECLARATION_CST.OK);
        END IF;

        V_COUNTER_LOOP   := V_COUNTER_LOOP + 6 + TO_NUMBER(SUBSTR(P_TLV_STRG, V_COUNTER_LOOP + 3, 3));
    END LOOP;

    P_TLV_STRG       :=
           P_TLV_STRG
        || SUBSTR(P_TAG_NAME, 1, 3)
        || TO_CHAR(NVL(LENGTH(P_TAG_VALUE), 0), 'FM000')
        || P_TAG_VALUE;

    P_TLV_STRG       := TO_CHAR(LENGTH(P_TLV_STRG), 'FM0000') || P_TLV_STRG;

    RETURN 0;
EXCEPTION
    WHEN OTHERS THEN
        RETURN -1;
END PUT_TAG;

1 Ответ

1 голос
/ 21 марта 2020

Сначала необходимо создать таблицу сопоставления в базе данных, которая сопоставляется с полем и его длиной (в моем примере я использовал CTE в качестве таблицы сопоставления: YOUR_MAPPING_TABLE).

Oracle настройка:

SQL> CREATE TABLE TEST1234 (
  2      FIELD001   VARCHAR2(4000),
  3      FIELD002   VARCHAR2(4000),
  4      FIELD003   VARCHAR2(4000),
  5      FIELD004   VARCHAR2(4000)
  6  );

Table created.

Запрос решения:

SQL> INSERT INTO TEST1234
  2  WITH YOUR_MAPPING_TABLE (FIELD_ID, LEN)
  3  AS (
  4  SELECT 'FIELD001', 4 FROM DUAL UNION ALL
  5  SELECT 'FIELD002', 3 FROM DUAL UNION ALL
  6  SELECT 'FIELD003', 3 FROM DUAL UNION ALL
  7  SELECT 'FIELD004', 12 FROM DUAL
  8  )
  9  SELECT * FROM
 10      ( SELECT M.FIELD_ID, -- Your string will go in following substring
 11               SUBSTR('0086037012123456789012', M.STARTPOS + 1, M.TOTALLEN) AS FIELDVALUE 
 12          FROM ( SELECT FIELD_ID,
 13                        SUM(LEN) OVER(ORDER BY FIELD_ID ) - LEN AS STARTPOS,
 14                        LEN   AS TOTALLEN
 15                   FROM YOUR_MAPPING_TABLE
 16               ) M
 17      ) PIVOT (
 18          MIN ( FIELDVALUE )
 19          FOR FIELD_ID IN ( 'FIELD001', 'FIELD002', 'FIELD003', 'FIELD004' )
 20      );

1 row created.

Проверка результата

SQL> SELECT * FROM TEST1234;

FIELD001   | FIELD002   | FIELD003   | FIELD004
---------- | ---------- | ---------- | -------------
0086       | 037        | 012        | 123456789012

SQL>

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

...