0
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;

Actually there are two queries as mensioned above

Letsay this query as 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

and this query as Q2 :

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

In both the qyery i am scanning complete table,which i think there is no need. I am iterating result of Q1 and then again scanning the table to count similar first_name. If a particular firstName occur more than two times i wrote business logic.

Can i combine both the queries,Means i want to store result of Q1 in some PL/SQL dataStructure and want to perform Q2 on result of Q1.

I want to modify Q1 as

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

But how to store 'select *' result in pl/sql dataStructure and How to pass these records to second query..Can u tell me how my code will look like? try to be more clear, i'm in lack of ideas in this PL/SQL, even it sounds like a classic :I have spend hours trying to play around with this but have got nowhere

@Ollie I changed the code as suggested by u but getting some error and not able to solve them

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;
       /

Error 1: PL/SQL: SQL Statement ignored {Indicating : "WITH include_rec" Line} Error 2 : PL/SQL: ORA-01789: query block has incorrect number of result columns {Indicating line : "AS (SELECT first_name,COUNT(1) OVER (PARTITION BY first_name)"} thanks in advance waiting for ur reply

javanna
  • 59,145
  • 14
  • 144
  • 125
user595014
  • 114
  • 3
  • 8
  • 20
  • 2
    Please don't create migratory questions here on SO. A "migratory question" is one that gets its answer, then is edited to add new content, new problems, then get an answer to those, and then is edited to add yet more content. They typically contain text like "I tried what you suggested, and it did fix my problem, but now I have a new one...". In this case, accept the answer here, work on your problem a bit more, and then leave a new question with the new problem. – Lasse V. Karlsen Aug 11 '11 at 10:25
  • 1
    A typical result of this is that the people answering will have to keep editing their answers. Additionally, new people might only answer the latest problems, leaving bits and pieces of the solutions to *all* your problems all over the place. Ask 1 question, accept 1 answer, and move on. – Lasse V. Karlsen Aug 11 '11 at 10:26

2 Answers2

0

I'd like to caveat this by saying that I haven't had a lot of time to work on this so there may be a few errors but it should give you the gist of what i'm trying to tell you:

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...

I'd also say that if you are expecting a large resultset then put the BULK COLLECT into a loop too to reduce your memory requirements.

In an ideal world, you'd pass the variables activationStartDate, activationEndDate, deActivationStartDate and deActivationEndDate into the cursor as cursor parameters to keep the cursor modular but that's up to you. ;-)

Hope this helps... Ollie.

EDIT: In response to your question about using records to select * from the table, you can declare an associative array based on the cursor columns, for the example above if you wanted to select more than one column from EMPLOYEE then after the WITH clause you would select the named columns from EMPLOYEE you want and instead of:

FirstNameListTable dbms_sql.varchar2_table;

declare the associative array type and variable as:

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

This gives you a flexible array that will automatically hold the columns selected in your cursor (main_cur).

You would collect the records into this array with the BULK COLLECT:

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

and loop through them with:

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

as for returning your resultset to Java, well I'm no java expert and you'll need to ask that in another forum or tag this question with the Java tag and hope a Java person picks it up and answers it for you.

Ollie
  • 17,058
  • 7
  • 48
  • 59
  • If you are performing a full table scan in your main query, perhaps you should talk to your DBA's and ask them if an index on start_date would be possible/beneficial. – Ollie Aug 10 '11 at 10:56
  • @Ollie--Please see original question, i edited, as suggested by u...but getting some error.....waiting for ur reply...I am new to pl/sql – user595014 Aug 10 '11 at 11:36
  • You have NOT copied what I gave you, I can see a MINUS in your code which I have totally eliminated from the code I wrote. If you are going to use the code I give you, at least use it as intended and not some hybrid of your original code and the answer I give you. Try the code I gave you as it is and see if you get an error. – Ollie Aug 10 '11 at 12:55
  • Also, in the second set of code you have introduced an OUT parameter which was not present in your original question. You need to decide what it is you need to achieve and not move the goalposts on me if you want me to help you fix your issue. – Ollie Aug 10 '11 at 13:07
  • OK,Ok.....I will take care of this in future....Can u please tell me How to use records instead of nested tables.If i want to select all the colums like "SELECT * BULK COLLECT INTO FirstListTable"....and how will i pass to all columns to my java code in pl/sql. Like for Nested table i used – user595014 Aug 10 '11 at 13:18
  • @Olie in contiuos to my previus comment"OPEN Out_Entity FOR SELECT * FROM TABLE(CAST ( FirstNameListTable AS LIST_TABLE)) Nos; Thanks for ur help – user595014 Aug 10 '11 at 13:25
  • I have edited my original answer to address your second question. I'm sure there are people on here (or Google) that can show you how to return an associative array to a calling Java program. As that was not even mentioned in your original question and I have no deep knowledge of Java to Oracle calls I can't answer that for you. – Ollie Aug 10 '11 at 13:32
  • Very-2 thanks for ur reply!!,How Pl/sql will send 'main_cur_tab' to java program? I am not asking how java will retrieve it? I am asking in what and how 'OUT' parameter pl/sql will send it? – user595014 Aug 11 '11 at 05:24
  • ,How will i define index of assosiative array – user595014 Aug 11 '11 at 05:42
  • You can pass an array out of a procedure or function if it is declared at a higher level. A packaged procedure could pass out an array if the array definition is declared at the package level. A standalone procedure could pass an array out if the array type is declared at the database object level. You need to look again at what you are trying to achieve. If you merely want to get the resultset of the main cursor into a Java array then call the SQL from the cursor using a Java prepared statement and handle it all in Java. – Ollie Aug 11 '11 at 08:53
  • ,i didnt understand, what do u want to say?I am using standalone procedure, i want to link "main_cur_tab" to "Out_Entity OUT TEST1.RefCsr", so that i can retrieve it in java......Actually i explained it http://stackoverflow.com/questions/7021543/how-can-i-pass-output-associative-array-of-pl-sql-to-java here which i want to achieve......Can u please give ur valueable advice or piece of code over there? – user595014 Aug 11 '11 at 09:15
  • 1
    No, I have answered your original question and as you don't seem to understand either the Pl/SQL which I have given you or the advice and seem to be struggling with the Java side of things too. I would recommend you call a consultant in to help you and your organisation. Every question you ask I answer and then you ask further questions. That is NOT what this forum is for. As i have more than answered your original question about the performance of your PL/SQL and SQL query and given you plenty of help around the subject too I am no longer able to help you further. Best of luck. – Ollie Aug 11 '11 at 10:09
  • 1
    @user595014 - Your question keeps changing, so providing an answer becomes _very_ difficult. Consider asking _separate_ questions when the help you receive here changes the scope of your problem. Ollie has been extremely patient, but you need to stick to your original question. – Tim Post Aug 11 '11 at 10:24
  • @Ollie,@Tim post : I will take care all of ur suggestion, If i would want to ask some thing else, then i will create new thread.....thanks for ur help – user595014 Aug 11 '11 at 13:00
0

Can you do this in SQL? E.g. maybe using a WITH like this:

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

If you can do it in SQL you can always embed it in PL/SQL afterwards if you need to.

cxm8002
  • 411
  • 4
  • 2