Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.server -> Re: What went wrong with this Function First?

Re: What went wrong with this Function First?

From: Charles Hooper <hooperc2000_at_yahoo.com>
Date: 6 Dec 2006 16:53:48 -0800
Message-ID: <1165452828.742944.253820@16g2000cwy.googlegroups.com>


dennis.pong_at_gmail.com wrote:
> Hi,
>
> I'm trying to flag the first record within each group of individual_id
>
> For example,
> INDIVIDUAL_ID FIRST_FLAG
> 1447620 7/30/2005 C 1
> 1447620 7/21/2005 C 0
> 1447620 7/15/2005 D 0
> 1447620 6/30/2005 D 0
> 1840354 12/1/2006 Z 1
> 1840354 11/28/2006 D 0
> 1840354 11/28/2006 D 0
> 1840354 11/28/2006 D 0
>
> HERE IS MY FUNCTION
>
> CREATE OR REPLACE Function First
> ( individual_id IN number )
> RETURN number
>
> IS
> stored_ind_id number(8);
> ind_first number(1);
>
>
> cursor c1 is
> select individual_id, activity_date , lead_grade
> from IND_ACTS
> GROUP BY individual_id, activity_date , lead_grade
> ORDER BY individual_id, activity_date desc, lead_grade;
>
>
> BEGIN
>
> stored_ind_id := 0;
> ind_first := 0;
>
>
> FOR IND_ACTS in c1
> LOOP
> If stored_ind_id <> individual_id then
> stored_ind_id := individual_id;
> ind_first := 1;
>
> END IF;
>
>
> END LOOP;
>
> RETURN ind_first;
>
> END;
>
>
> Don't know if someone could point out the possible flaws of this
> function that it doesn't work as expected.
>
> Thanks,

Have you considered doing the above using only SQL? It can be accomplished very easily.
The set up:
CREATE TABLE IND_ACTS(
  INDIVIDUAL_ID NUMBER(12),
  ACTIVITY_DATE DATE,
  LEAD_GRADE VARCHAR2(2));

INSERT INTO IND_ACTS VALUES (1447620,'30-JUL-2005','C');
INSERT INTO IND_ACTS VALUES (1447620,'21-JUL-2005','C');
INSERT INTO IND_ACTS VALUES (1447620,'15-JUL-2005','D');
INSERT INTO IND_ACTS VALUES (1447620,'30-JUN-2005','D');
INSERT INTO IND_ACTS VALUES (1840354,'01-DEC-2006','Z');
INSERT INTO IND_ACTS VALUES (1840354,'28-NOV-2006','D');
INSERT INTO IND_ACTS VALUES (1840354,'28-NOV-2006','D');
INSERT INTO IND_ACTS VALUES (1840354,'28-NOV-2006','D');

COMMIT; SELECT
  INDIVIDUAL_ID,
  ACTIVITY_DATE,
  LEAD_GRADE
FROM
  IND_ACTS; INDIVIDUAL_ID ACTIVITY_DATE LEAD_GRADE

      1447620   30-JUL-2005 00:00:00   C
      1447620   21-JUL-2005 00:00:00   C
      1447620   15-JUL-2005 00:00:00   D
      1447620   30-JUN-2005 00:00:00   D
      1840354   01-DEC-2006 00:00:00   Z
      1840354   28-NOV-2006 00:00:00   D
      1840354   28-NOV-2006 00:00:00   D
      1840354   28-NOV-2006 00:00:00   D

With the data in the table, we first need to determine the order of the rows when separated by INDIVIDUAL_ID. This can be accomplished using the ROW_NUMBER analytic function. Note: I added an order by clause to the SQL statement just to show that the ROW_NUMBER analytic function is not affected by the ORDER BY at the end of the SQL statement. SELECT
  INDIVIDUAL_ID,
  ACTIVITY_DATE,
  LEAD_GRADE,
  ROW_NUMBER() OVER (PARTITION BY INDIVIDUAL_ID ORDER BY ACTIVITY_DATE DESC,LEAD_GRADE) ROW_IN_GRP
FROM
  IND_ACTS
ORDER BY
  INDIVIDUAL_ID,
  ACTIVITY_DATE;

INDIVIDUAL_ID   ACTIVITY_DATE     LEAD_GRADE   ROW_IN_GRP
      1447620    30-JUN-2005 00:00:00    D                   4
      1447620    15-JUL-2005 00:00:00    D                   3
      1447620    21-JUL-2005 00:00:00    C                   2
      1447620    30-JUL-2005 00:00:00    C                   1
      1840354    28-NOV-2006 00:00:00   D                  4
      1840354    28-NOV-2006 00:00:00   D                  2
      1840354    28-NOV-2006 00:00:00   D                  3
      1840354    01-DEC-2006 00:00:00   Z                   1

Looking at the above, you only want to return the 1s, and set all other numbers to 0 - this can be accomplished with a DECODE function: SELECT
  INDIVIDUAL_ID,
  ACTIVITY_DATE,
  LEAD_GRADE,
  ROW_NUMBER() OVER (PARTITION BY INDIVIDUAL_ID ORDER BY ACTIVITY_DATE DESC,LEAD_GRADE) ROW_IN_GRP,
  DECODE(ROW_NUMBER() OVER (PARTITION BY INDIVIDUAL_ID ORDER BY ACTIVITY_DATE DESC,LEAD_GRADE),1,1,0) IS_FIRST FROM
  IND_ACTS
ORDER BY
  INDIVIDUAL_ID,
  ACTIVITY_DATE;

INDIVIDUAL_ID   ACTIVITY_DATE     LEAD_GRADE   ROW_IN_GRP   IS_FIRST
      1447620    30-JUN-2005 00:00:00    D                   4
            0
      1447620    15-JUL-2005 00:00:00    D                   3
            0
      1447620    21-JUL-2005 00:00:00    C                   2
            0
      1447620    30-JUL-2005 00:00:00    C                   1
            1
      1840354    28-NOV-2006 00:00:00   D                  4
          0
      1840354    28-NOV-2006 00:00:00   D                  2
          0
      1840354    28-NOV-2006 00:00:00   D                  3
          0
      1840354    01-DEC-2006 00:00:00   Z                   1
           1

For performance, use just SQL, if at all possible, rather than using a PL/SQL function or procedure.

Charles Hooper
PC Support Specialist
K&M Machine-Fabricating, Inc. Received on Wed Dec 06 2006 - 18:53:48 CST

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US