Добавить имя таблицы динамически в хранимой процедуре - PullRequest
1 голос
/ 23 июня 2019

Я пытался найти способы динамического изменения имени таблицы в запросе, но пока не нашел работающего.Запрос содержит повторяющийся код (около 150 строк кода внутри каждого оператора case), поэтому я пытаюсь найти лучший способ сделать это.

Моя текущая процедура выглядит следующим образом:

CREATE OR REPLACE PROCEDURE PROC_MY_TEST (P_INPUTVAR       NUMBER,
                                          P_OUT        OUT SYS_REFCURSOR)
AS
BEGIN
   CASE P_INPUTVAR
      WHEN 1
      THEN
         OPEN P_OUT FOR
            WITH CTE
                 AS (SELECT COL_M, COL_N
                       FROM TBL_TEST
                      WHERE COL_G = 'mycondition1')
            SELECT COL_M, COL_N
              FROM TABLE_A a LEFT JOIN CTE m ON a.col1 = b.col1
             WHERE a.col2 = 'xyz' AND b.col4 = 'abc';
      WHEN 2
      THEN
         OPEN P_OUT FOR
            WITH CTE
                 AS (SELECT COL_M, COL_N
                       FROM TBL_TEST
                      WHERE COL_G = 'mycondition1')
            SELECT COL_M, COL_N
              FROM TABLE_B a LEFT JOIN CTE m ON a.col1 = b.col1
             WHERE a.col2 = 'xyz' AND b.col4 = 'abc';
      WHEN 3
      THEN
         OPEN P_OUT FOR
            WITH CTE
                 AS (SELECT COL_M, COL_N
                       FROM TBL_TEST
                      WHERE COL_G = 'mycondition1')
            SELECT COL_M, COL_N
              FROM TABLE_C a LEFT JOIN CTE m ON a.col1 = b.col1
             WHERE a.col2 = 'xyz' AND b.col4 = 'abc';
      WHEN 4
      THEN
         OPEN P_OUT FOR
            WITH CTE
                 AS (SELECT COL_M, COL_N
                       FROM TBL_TEST
                      WHERE COL_G = 'mycondition1')
            SELECT COL_M, COL_N
              FROM TABLE_D a LEFT JOIN CTE m ON a.col1 = b.col1
             WHERE a.col2 = 'xyz' AND b.col4 = 'abc';
   END CASE;
END;

Несколько решений SQL предложили следующий формат, но он выдает сообщение об ошибке «Table L_Temp не существует»:

CREATE OR REPLACE PROCEDURE PROC_MY_TEST (P_INPUTVAR       NUMBER,
                                          P_OUT        OUT SYS_REFCURSOR)
AS
   L_Temp   VARCHAR2 (200);   
BEGIN
   L_Temp :=
      CASE P_INPUTVAR
         WHEN 1 THEN 'TABLE_A'
         WHEN 2 THEN 'TABLE_B'
         WHEN 3 THEN 'TABLE_C'
         WHEN 4 THEN 'TABLE_D'
         ELSE NULL
      END;

   OPEN P_OUT FOR
      WITH CTE
           AS (SELECT COL_M, COL_N
                 FROM TBL_TEST
                WHERE COL_G = 'mycondition1')
      SELECT COL_M, COL_N
        FROM L_Temp a LEFT JOIN CTE m ON a.col1 = b.col1
       WHERE a.col2 = 'xyz' AND b.col4 = 'abc';
END;

Есть ли способ динамического изменения имен таблиц, когда все таблицы назначения содержатпохожие имена столбцов?

* Отредактировано * Добавлен код для дополнительного примера оператора обновления:

CREATE OR REPLACE PROCEDURE PROC_MY_TEST (P_INPUTVAR       NUMBER,
                                          P_OUT        OUT SYS_REFCURSOR)
AS
   L_Temp   VARCHAR2 (200);
   L_Total  NUMBER;
BEGIN
   L_Temp :=
      CASE P_INPUTVAR
         WHEN 1 THEN 'TABLE_A'
         WHEN 2 THEN 'TABLE_B'
         WHEN 3 THEN 'TABLE_C'
         WHEN 4 THEN 'TABLE_D'
         ELSE NULL
      END;

   OPEN P_OUT FOR
      WITH CTE
           AS (SELECT COL_M, COL_N
                 FROM TBL_TEST
                WHERE COL_G = 'mycondition1')
      SELECT COL_M, COL_N
        FROM L_Temp a LEFT JOIN CTE m ON a.col1 = b.col1
       WHERE a.col2 = 'xyz' AND b.col4 = 'abc';

      SELECT TOTAL INTO L_Total FROM L_Temp;

      UPDATE TBL_TEST2 
      SET a.TOTAL = l_Total 
      WHERE a.col2 = 'xyz';

END;

Ответы [ 2 ]

1 голос
/ 24 июня 2019

Вам необходимо создать оператор в виде строки, а затем открыть оператор в виде курсора:

CREATE OR REPLACE PROCEDURE PROC_MY_TEST (P_INPUT_VAR IN  NUMBER,
                                          P_OUT       OUT SYS_REFCURSOR)
AS
  strTable  VARCHAR2(30);
  strStmt   VARCHAR2(32767);
BEGIN
  strTable := CASE P_INPUT_VAR
                WHEN 1 THEN 'TABLE_A'
                WHEN 2 THEN 'TABLE_B'
                WHEN 3 THEN 'TABLE_C'
                WHEN 4 THEN 'TABLE_D'
              END;

  strStmt := 'WITH CTE AS (SELECT COL_M, COL_1, COL_4 ' ||
                           ' FROM TBL_TEST ' ||
                           ' WHERE COL_G = ''mycondition1'') ' ||
             'SELECT COL_M, COL_N ' ||
              ' FROM ' || strTable || ' t ' ||
              ' LEFT JOIN CTE m ' ||
                ' ON t.COL1 = m.COL_1 ' ||
              ' WHERE a.COL2 = ''xyz'' AND ' ||
                    ' m.COL_4 = ''abc''';

  OPEN P_OUT FOR strStmt;
END PROC_MY_TEST;

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

1 голос
/ 23 июня 2019

Вам необходимо использовать ВЫПОЛНИТЬ НЕМЕДЛЕННЫЙ оператор

Оператор EXECUTE IMMEDIATE выполняет динамический оператор SQL или анонимный блок PL / SQL. Вы можете использовать его для выдачи операторов SQL, которые не могут быть представлены непосредственно в PL / SQL, или для создания операторов, в которых вы не знаете всех имен таблиц

Для Пример :

execute immediate '
  update ' || myTable || '
 ...
';
...