Улучшение производительности pl / sql, хотите выполнить Q2 на результат Q1 - PullRequest
0 голосов
/ 10 августа 2011
CREATE or REPLACE PROCEDURE TEST(
activationStartDate IN DATE,
activationEndDate IN DATE,
deActivationStartDate IN DATE,
deActivationEndDate IN DATE
)
AS
FirstNameListTable LIST_TABLE;

{--COMMENT :LIST_TABLE is nested table :create or replace TYPE "LIST_TABLE" as table     of varchar2(20);-----Nested Table Declaration
/
}

totalSameFirstName NUMBER;
j NUMBER := 1;
BEGIN



SELECT first_name BULK COLLECT INTO FirstNameListTable FROM Employee where start_date between activationStartDate AND activationEndDate 
MINUS 
SELECT first_name FROM Employee where start_date between deActivationStartDate AND deActivationEndDate


FOR i IN FirstNameListTable.FIRST .. FirstNameListTable.LAST LOOP
     SELECT count(*) INTO totalSameFirstName FROM Employee where start_date between activationStartDate AND activationEndDate AND first_name=FirstNameListTable(i)

       IF totalSameFirstName > 2 THEN
            ---business logic
       END IF;
END LOOP;

На самом деле есть два запроса, о которых говорилось выше

Давайте ответим на этот запрос как Q1:

SELECT first_name BULK COLLECT INTO FirstNameListTable FROM Employee where start_date between activationStartDate AND activationEndDate 
MINUS 
SELECT first_name FROM Employee where start_date between deActivationStartDate AND deActivationEndDate

и этот запрос как Q2:

SELECT count(*) INTO totalSameFirstName FROM Employee where start_date between activationStartDate AND activationEndDate AND first_name=FirstNameListTable(i)

В обоих запросах я сканирую полную таблицу, в которой, я думаю, нет необходимости. Я повторяю результат Q1, а затем снова сканирую таблицу, чтобы посчитать аналогичный first_name. Если конкретное firstName встречается более двух раз, я пишу бизнес-логику.

Могу ли я объединить оба запроса, значит я хочу сохранить результат Q1 в некоторой PL / SQL dataStructure и хочу выполнить Q2 с результатом Q1.

Я хочу изменить Q1 как

SELECT * BULK COLLECT INTO FirstNameListTable FROM Employee where start_date between activationStartDate AND activationEndDate 
 MINUS 
 SELECT * FROM Employee where start_date between deActivationStartDate AND deActivationEndDate

Но как сохранить результат 'select *' в pl / sql dataStructure и как передать эти записи во второй запрос ... Можете ли вы сказать мне, как будет выглядеть мой код? Попробуй быть более понятным, мне не хватает идей в этом PL / SQL, даже если это звучит как классика: я потратил часы, пытаясь поиграть с этим, но не получил ничего.

@ Олли Я изменил код в соответствии с предложением, но получил ошибку и не смог ее решить

CREATE or REPLACE PROCEDURE TEST(
 activationStartDate IN DATE, 
 activationEndDate IN DATE, 
 deActivationStartDate IN DATE, 
  deActivationEndDate IN DATE, 
 Out_Entity OUT TEST1.RefCsr
 )
  AS
  FirstNameListTable CRITERIA_LIST_TABLE;
  out NUMBER;
  j NUMBER := 1;

  CURSOR main_cur
  IS
    WITH include_rec
      AS (SELECT first_name,COUNT(1) OVER (PARTITION BY first_name) name_count  FROM employee where start_date between activationStartDate AND activationEndDate 
     MINUS
        SELECT first_name FROM employee where start_date between deActivationStartDate AND deActivationEndDate)
       SELECT first_name FROM include_rec WHERE name_count > 2;             

    BEGIN
     OPEN main_cur;
     FETCH main_cur BULK COLLECT INTO FirstNameListTable;
     CLOSE main_cur;

      OPEN Out_Entity FOR SELECT * FROM TABLE(
                                               CAST (
                                                    FirstNameListTable AS LIST_TABLE
                                                 )
                                    ) Nos;

      END;
       /

Ошибка 1: PL / SQL: оператор SQL игнорируется {Указывает: строка «WITH include_rec»} Ошибка 2: PL / SQL: ORA-01789: в блоке запроса указано неверное число столбцов результата заранее спасибо жду твоего ответа

Ответы [ 2 ]

0 голосов
/ 14 августа 2011

Можете ли вы сделать это в SQL?Например, возможно, используя WITH следующим образом:

WITH q1 AS (SELECT ....)
SELECT /* q2 */ ... FROM q1
WHERE ..
GROUP BY etc

Если вы можете сделать это в SQL, вы всегда можете встроить его в PL / SQL, если вам нужно.

0 голосов
/ 10 августа 2011

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

CREATE or REPLACE 
PROCEDURE TEST( 
   activationStartDate IN DATE, 
   activationEndDate IN DATE, 
   deActivationStartDate IN DATE, 
   deActivationEndDate IN DATE ) 
AS 
   CURSOR main_cur
   IS
      WITH include_rec 
        AS (SELECT first_name, 
                   start_date,
                   COUNT(1) OVER (PARTITION BY first_name) name_count
              FROM Employee 
             WHERE start_date BETWEEN activationStartDate 
                                  AND activationEndDate)
      SELECT DISTINCT 
             first_name
        FROM include_rec
       WHERE start_date NOT BETWEEN deActivationStartDate 
                                AND deActivationEndDate
         AND name_count > 2; 
   --
   FirstNameListTable dbms_sql.varchar2_table;    
BEGIN    
    OPEN main_cur;
    FETCH main_cur BULK COLLECT INTO FirstNameListTable;
    CLOSE main_cur;

    FOR i IN FirstNameListTable.FIRST .. FirstNameListTable.LAST 
    LOOP                 
           ---business logic         
    END LOOP; 

    etc...

Я бы также сказал, что если вы ожидаете большой набор результатов, то поместите BULK COLLECT в цикл, чтобы уменьшить ваши требования к памяти.

В идеальном мире вы должны передать переменные ActivationStartDate, активацииEndDate, deActivationStartDate и deActivationEndDate в качестве параметров курсора, чтобы курсор оставался модульным, но это зависит от вас. ; -)

Надеюсь, это поможет ... Олли.

EDIT: Отвечая на ваш вопрос об использовании записей для выбора * из таблицы, вы можете объявить ассоциативный массив на основе столбцов курсора, например, в приведенном выше примере, если вы хотите выбрать более одного столбца из EMPLOYEE, то после предложения WITH вы должны выбрать именованные столбцы от работника, которого вы хотите, а не:

FirstNameListTable dbms_sql.varchar2_table;

объявляет тип ассоциативного массива и переменную как:

TYPE main_cur_tabtype IS TABLE OF main_cur%ROWTYPE
     INDEX BY PLS_INTEGER;
main_cur_tab main_cur_tabtype;

Это дает вам гибкий массив, который будет автоматически содержать столбцы, выделенные вашим курсором (main_cur).

Вы должны собрать записи в этот массив с помощью BULK COLLECT:

OPEN main_cur;
FETCH main_cur BULK COLLECT INTO main_cur_tab;
CLOSE main_cur;

и перебрать их с помощью:

FOR i IN main_cur_tab.FIRST .. main_cur_tab.LAST
LOOP
   etc.

что касается возврата вашего набора результатов в Java, я не эксперт по Java, вам нужно будет задать это на другом форуме или пометить этот вопрос тегом Java и надеяться, что специалист по Java заберет его и ответит за вас. .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...