clarification of analytical FIRST_VALUE function

How Sal is calculated in the query below. first_value will fetch the first value in a window of.

For deptno = 10 we have 3 files so why is filling for all records of deptno = 2450 10.I was clear with output if I use the command by sal after partition by deptno but under output query is not clear.

clarification of the request:

Select empno, deptno, first_value (sal) on sal (deptno partition)

WCP

o/p:

deptno, EmpNo, sal

7782102450
7934102450
7839102450
7902203000
7788203000
7566203000
7369203000
7876203000
7521301250
7654301250
7844301250
7900301250
7499301250
7698301250

the EMP data:

Select * from emp;

7782CLARKMANAGER7839JUNE 9, 81245010
7934MILLERCLERK7782JANUARY 23, 82130010
7839KINGPRESIDENTNOVEMBER 17, 81500010
7902FORDANALYST7566DECEMBER 3, 81300020
7788SCOTTANALYST7566APRIL 19, 87300020
7566JONESMANAGER78392 APRIL 81297520
7369SMITHCLERK7902DECEMBER 17, 8080020
7876ADAMSCLERK7788MAY 23, 87110020
7521WARDSELLER7698FEBRUARY 22, 81125050030
7654MARTINSELLER769828 SEP-811250140030
7844TURNERSELLER769808 SEP-811500030
7900JAMESCLERK7698DECEMBER 3, 8195030
7499ALLENSELLER7698FEBRUARY 20, 81160030030
7698BLAKEMANAGER7839MAY 1, 81285030

If you do not specify a COMMAND BY ADOPTERAIS function FIRST_VALUE returns then a deterministic in.

Tags: Database

Similar Questions

  • assign the number to a line based on the analytical condition function

    Oracle 11g Server

    ID val1 val2
    100a
    110 b
    120c
    200a
    220 b

    WITH input AS
     (SELECT 1  id
            ,0  val1
            ,'0a' val2
        FROM dual
      UNION ALL
      SELECT 1  id
            ,1  val1
            ,'0b' val2
        FROM dual
      UNION ALL
      SELECT 1  id
            ,2  val1
            ,'0c' val2
        FROM dual
      UNION ALL
      SELECT 2  id
            ,0  val1
            ,'0a' val2
        FROM dual
      UNION ALL
      SELECT 2     Id
            ,2val1
            ,'0b'    val2
        FROM dual)
    SELECT * FROM input;
    
    !-[CodeBlockEnd:ae52826b-04c5-4aa4-a6c0-1d0405656e55]-->

    Output:

    ID val1 val2 assigned_number
    100a0
    110 b0
    120c2
    200a0
    220 b1

    The dense numbering sequence must be assigned to each line based on the column id and val1.

    For an identifier given, the numbering begins only after val1 > 1 until then the assigned_number will be zero.

    WITH the entry INTO

    (SELECT 1 id)

    0 val1

    '0' has val2

    OF the double

    UNION ALL

    SELECT 1 id

    1 val1

    b '0' val2

    OF the double

    UNION ALL

    SELECT 1 id

    2 val1

    , 0'c ' val2

    OF the double

    UNION ALL

    SELECT 2 id

    0 val1

    '0' has val2

    OF the double

    UNION ALL

    SELECT the Id 2

    2val1

    b '0' val2

    THE DOUBLE)

    SELECT id, val1, val2,

    Rank() over (partition by order of case when val1 > 1 then 0 otherwise end val1) dr-1

    SINCE the entry;

    ID VAL1 IS DR

    ---------- ---------- -- ----------

    1          0 0a          0

    1          1 0b          0

    1          2 0c          2

    2          0 0a          0

    2          2 0b          1

  • Analytical functions: FIRST vs FIRST_VALUE

    Hello

    Can someone please help me understand the difference between PRIME and FIRST_VALUE in Anaytic functions.

    I tried below 2 queries, but I see the same output. The only difference I see is that the field of the SAL is ordered FIRST_VALUE, but not the FIRST.

    SELECT ename,

    DEPTNO,

    SAL,

    MIN (SAL) keep (dense_rank FIRST

    ORDER BY sal) by (deptno partition) FIRST

    EMP;

    SELECT ename,

    DEPTNO,

    SAL,

    FIRST_VALUE (SAL) over (partition BY deptno arrested by sal) FIRST

    EMP;

    With the help of: Windows 8.1

    Database Oracle 12 c Enterprise Edition Release 12.1.0.1.0 - 64 bit Production

    PL/SQL Release 12.1.0.1.0 - Production

    "CORE 12.1.0.1.0 Production."

    AMT for 64-bit Windows: Version 12.1.0.1.0 - Production

    NLSRTL Version 12.1.0.1.0 - Production

    Hello

    Here is an example of when you can use the FIRST analytic function.

    Say you want the average sal for each Department, but only for the first year (taken from the hiredate column) in the Department (i.e., the column called f in the query below).

    WITH got_hireyear AS

    (

    SELECT deptno and ename, sal, hiredate

    EXTRACT (YEAR FROM hiredate) AS hireyear

    FROM scott.emp

    )

    SELECT deptno, hireyear, hiredate, ename, sal

    AVG (sal) DUNGEON (DENSE_RANK FIRST ORDER BY hireyear)

    COURSES (PARTITION BY deptno

    ) In the FORM f

    FIRST_VALUE (sal) over (PARTITION BY deptno

    ORDER BY hireyear

    ) AS fv

    AVG (sal) over (PARTITION BY deptno

    hireyear

    ), A

    OF got_hireyear

    ORDER BY deptno

    hireyear

    ename

    ;

    Output:

    HIREYEAR ENAME SAL HIREDATE DEPTNO F FV HAS
    ------ ---------- ----------- ---------- ------ --------- ------ ---------
    10 1981 9 June 1981 CLARK 2450 2450 3725,00 3725.00
    10 1981 17 November 1981 KING 5000 3725,00 2450 3725.00
    10 1982 23 January 1982 MILLER 1300 3725,00 2450 1300.00

    20, 1980, 17 December 1980 SMITH 800 800.00 800.00 800
    20, 1981, 3 December 1981 FORD 3000 800.00 800 2987.50
    20, 1981, 2 April 1981 JONES 2975 800.00 800 2987.50
    20, 1987, 23 May 1987 ADAMS 1100 800.00 800 2050.00
    20, 1987, 19 April 1987 SCOTT 3000 800.00 800 2050.00

    30 1981 20 February 1981 ALLEN 1600 1566.67 950 1566.67
    May 30 1981 1st 1981 BLAKE 2850 1566.67 950 1566.67
    December 30 1981 3 1981 JAMES 950 1566.67 950 1566.67
    30 1981 28 - sep - 1981 MARTIN 1250 1566.67 950 1566.67
    30-08 - sep - 1981 1981 TURNER 1500 1566.67 950 1566.67
    30 1981 22 February 1981 WARD 1250 1566.67 950 1566.67

    The analytical FIRST_VALUE function can do (except in the very special case where only 1 row has the lowest hireyear, as in deptno = 20).  AVG analysis can do (except in the very special case that all lines have the same hireyear as in deptno = 30).

  • "MORE FIRST_VALUE() (vs MAX() DENSE_RANK FIRST OVER())

    I am trying to determine the differences between the use of the function analytic first_value vs using the analytical function of the DENSE_RANK FIRST OVER() style.

    In particular, when is it appropriate to use one against the other? In truth the DENSE_RANK OVER() FIRST seems to be a much more flexible version of the first_value function.

    All illumination is very appreciated.

    Hello

    Claytonian wrote:
    To clarify,

    There is not difference between the analytical FIRST_VALUE function, the FIRST analytical function and it comes down to coding preference/maintainability?

    I just guess that there is no performance difference. I saw not all studies or experiments to back up.

    The only difference between value FIRST and FIRST_VALUE analytic functions is how you call them. You were very careful to mention that you're talking about analytic functions. Ok.
    There is a big difference between the FIRST and FIRST_VALUE value of aggregate functions: the FIRST aggregate function exists, but there is no aggregate FIRST_VALUE function. If you want to see the x that is associated with the lowest y in an aggregate query, use FIRST.

  • Numbering of the lines based on two columns

    Hello world

    I´d would like to know if there is a way to achieve the numbering shown in the second table below indicating only Oracle native functions, like ROW_COUNT() on the partition, etc.

    I m using Oracle 10 g.

    The logic used is:
    From 1, increment one each time that the ORIGIN is identical to the FIRST ORIGIN of the line (ID) group.
    ID    ORIGIN    DESTINATION    ORDER
    ------------------------------------
    1     A         B              1
    1     B         A              2
    1     A         B              3
    1     B         C              4
    1     C         A              5
     
    ID     ORIGIN    DESTINATION    ORDER    NUMBERING
    --------------------------------------------------
    1      A         B              1        1
    1      B         A              2        1
    1      A         B              3        2
    1      B         C              4        2
    1      C         A              5        2
    In order to compare the ORIGIN of each line with the FIRST ORIGIN of the group, I used the function LAG to create a column that will be the FIRST ORIGIN of the value in the group.

    However, I was not able to number the lines as shown above (column NUMBERING).

    Any help will be much appreciated.

    --------------------------------------------------------------------------------------------------------------

    Test query:
    WITH T AS
    (
      SELECT 1 ID, 'A' ORIGIN, 'B' DESTINATION, 1 ORDERING FROM DUAL UNION ALL
      SELECT 1 ID, 'B' ORIGIN, 'A' DESTINATION, 2 ORDERING FROM DUAL UNION ALL
      SELECT 1 ID, 'A' ORIGIN, 'B' DESTINATION, 3 ORDERING FROM DUAL UNION ALL
      SELECT 1 ID, 'B' ORIGIN, 'C' DESTINATION, 4 ORDERING FROM DUAL UNION ALL
      SELECT 1 ID, 'C' ORIGIN, 'A' DESTINATION, 5 ORDERING FROM DUAL
    )
      SELECT T.ID
           , T.ORIGIN
           , T.DESTINATION
           , T.ORDERING
           , LAG (T.ORIGIN, T.ORDERING -1, 0) OVER (PARTITION BY T.ID
                                                        ORDER BY T.ID
                                                               , T.ORDERING) FIRST_ORIGIN_OF_GROUP
        FROM T
    ORDER BY T.ID
           , T.ORDERING

    Hello

    Here's one way:

    WITH     got_first_origin     AS
    (
         SELECT     id, origin, destination, ordering
         ,     FIRST_VALUE (origin) OVER ( PARTITION BY  id
                                          ORDER BY         ordering
                                     ) AS first_origin
         FROM    t
    )
    SELECT     id, origin, destination, ordering
    ,     COUNT ( CASE
                        WHEN  origin = first_origin
                  THEN  1
                    END
               )     OVER ( PARTITION BY  id
                           ORDER BY      ordering
                   ) AS numbering
    FROM     got_first_origin
    ;
    

    This assumes that the combination of id and order is unique. Within an id, you place your order does not have to be consecutive integers, or something like that.

    Analytical functions cannot be nested (the argument of the function of COUNTY anlytic can not call the analytical FIRST_VALUE function); The subquery is necessary.
    You could do something with a LAG, as you have tried, rather than FIRST_VALUE, but you would still need a subquery, for the same reason.

  • FIRST_VALUE() and LAST_VALUE Analytic Functions

    Hi all

    May be that it is a fundamental issue. But I'm having a hard time understanding the difference between FIRST_VALUE() and LAST_VALUE() of analytical functions.

    As much as what I read the FIRST_VALUE function picks up the first record after the partition and order by and he returned after all calculation. And the LAST_VALUE does the opposite. But the result of the second query as I expected, are not (last value of the partition). It would be useful that someone could throw some light on it.
    select empno
         , ename
         , sal
         , first_value(ename) over(order by sal desc)
      from emp;
    
    empno  ename      sal       first_value 
    ------ ---------- --------- ----------- 
    7839   KING       5000.00   KING        
    7902   FORD       3000.00   KING        
    7788   SCOTT      3000.00   KING        
    7566   JONES      2975.00   KING        
    7698   BLAKE      2850.00   KING        
    7782   CLARK      2450.00   KING        
    7499   ALLEN      1600.00   KING        
    7844   TURNER     1500.00   KING        
    7934   MILLER     1300.00   KING        
    7654   MARTIN     1250.00   KING        
    7521   WARD       1250.00   KING        
    7876   ADAMS      1100.00   KING        
    7900   JAMES      950.00    KING        
    7369   SMITH      800.00    KING        
    
    14 Row(s) affected
    select empno
         , ename
         , sal
         , last_value(ename) over(order by sal desc)
      from emp;
    
    empno  ename      sal       last_value 
    ------ ---------- --------- ---------- 
    7839   KING       5000.00   KING       
    7902   FORD       3000.00   SCOTT      
    7788   SCOTT      3000.00   SCOTT      
    7566   JONES      2975.00   JONES      
    7698   BLAKE      2850.00   BLAKE      
    7782   CLARK      2450.00   CLARK      
    7499   ALLEN      1600.00   ALLEN      
    7844   TURNER     1500.00   TURNER     
    7934   MILLER     1300.00   MILLER     
    7521   WARD       1250.00   MARTIN     
    7654   MARTIN     1250.00   MARTIN     
    7876   ADAMS      1100.00   ADAMS      
    7900   JAMES      950.00    JAMES      
    7369   SMITH      800.00    SMITH      
    
    14 Row(s) affected
    Thank you
    Vincent

    Hey, Vincent,.

    When you use an analytic function with an ORDER BY clause, the results will be based on a window, which is a subset of the partition.
    If you do not specify a window (using the keywords LINE or LINES) the window everything will be in order by the ORDER BY clause, until and including the current line, including links.

    For example, in your second query:

    select empno
         , ename
         , sal
         , last_value(ename) over(order by sal desc)
      from emp;
    
    empno  ename      sal       last_value
    ------ ---------- --------- ----------
    7839   KING       5000.00   KING
    7902   FORD       3000.00   SCOTT
    7788   SCOTT      3000.00   SCOTT
    7566   JONES      2975.00   JONES
    7698   BLAKE      2850.00   BLAKE
    7782   CLARK      2450.00   CLARK
    7499   ALLEN      1600.00   ALLEN
    7844   TURNER     1500.00   TURNER
    7934   MILLER     1300.00   MILLER
    7521   WARD       1250.00   MARTIN
    7654   MARTIN     1250.00   MARTIN
    7876   ADAMS      1100.00   ADAMS
    7900   JAMES      950.00    JAMES
    7369   SMITH      800.00    SMITH    
    

    The analytic function

    last_value(ename) over(order by sal desc)
    

    Returns the last ename, not of the entire table, but the window starting with the highest sal (since you say "ORDER BY sal DESC") and including the current line and all the other lines that have the same sal.

    So consider the 1st row, ename = 'KING '. It has the most sal, so that a single line in the window, 'KING' IS THE LAST VALUE WINDOW.

    Now consider the 2nd row, where ename = 'FORD' and sal = 3000. The window includes now everybody with a sal of 3000 and more, which means the 3 rows 'KING', 'FORD' and 'SCOTT '. The last of them (in descending order of sal) is 'SCOTT '. (In fact, there is a tie, you could just as well say that "JONES" is changed, because there is a tie between the two rows where sal = 3000) When this happens, one of the lines will arbitrarily designate the "last" line don't expect not to be always the same line.)

    Because of this, LAST_VALUE is alwmost always used with an explicit windowing clause, beginning with the BEACH or LINES.

    If you want a request as your first request, but it contains the name of the lowest paid employee (that is, he always says 'SMITH' in the last column instead of 'KING'), then use FIRST_VALUE, but reverse the sort order:

    first_value(ename) over(order by sal ASC)
    
  • Need help with the analytic function

    I want to get the highest employee details and the 2nd highest employee for a particular service. But also the Department should have more than 1 employee.
    I tried the query and it gave me the correct results. But I wonder if there is another solution than to use the subquery.

    Here is the table and the query result:
    with t as
    (
    select 1 emp_id,3 mgr_id,'Rajesh' emp_name,3999 salary,677 bonus,'HR' dpt_nme from dual union
    select 2 ,3 ,'Gangz',4500,800,'Finance' from dual  union
    select 3 ,4 ,'Sid',8000,12000,'IT' from dual  union
    select 4 ,null,'Ram',5000,677,'HR' from dual  union
    select 5 ,4,'Shyam',6000,677,'IT' from dual union
    select 6 ,4 ,'Ravi',9000,12000,'IT' from dual   
    )
    select * from 
    (select emp_id, mgr_id, emp_name, dpt_nme, salary, row_number() over (partition by dpt_nme order by salary desc) rn from t where dpt_nme in 
    (select dpt_nme from t group by dpt_nme having count(*) > 1)) where rn < 3

    Hello

    You need a subquery, but you don't need more than that.
    Here's a way to eliminate the additional subquery:

    WITH     got_analytics     AS
    (
         SELECT  emp_id,     mgr_id,     emp_name, dpt_nme, salary
         ,     ROW_NUMBER () OVER ( PARTITION BY  dpt_nme
                                   ORDER BY          salary     DESC
                           )         AS rn
         ,     COUNT (*)     OVER ( PARTITION BY  dpt_nme
                                       )         AS dpt_cnt
         FROM     t
    )
    SELECT  emp_id,     mgr_id,     emp_name, dpt_nme, salary
    ,     rn
    FROM     got_analytics
    WHERE     rn     < 3
    AND     dpt_cnt     > 1
    ;
    

    Analytical functions are calculated after the clause WHERE is applied. Since we need to use the results of the analytical ROW_NUMBER function in a WHERE clause, which means that we have to calculate ROW_NUMBER in a subquery and use the results in the WHERE clause of the main query. We can call the COUNT function analytical in the same auxiliary request and use the results in the same WHERE clause of the main query.

    Would what results you if there is a link for the 2nd highest salary in some Department? For example, if you add this line to your sample data:

    select 7 ,3 ,'Sunil',8000,12000,'IT' from dual  union
    

    ? You can use RANK rather than ROW_NUMBER.

  • Analytic function can support this requirement?

    As a result of some Qry, I get the following result set.
    
    Column1 Column2 
    A       100    
    A       200
    A       200
    A       100
    B       200
    B       200
    B       200 
    C       100
    C       200
    D       200
    D       200
    E       200
    
    With this as input i had to take some decision like, For a particular Column1 value, if all the avaiable value of column2 is 200 (B, D & E in this case), i need to do one set of operations, if atleast one of the value for Column2 is non 200 (A & C in this case), i need to do another set of operation. How to frame the If clause or any other approach?
    
    
    By using Analytical count(*) function, is it possible to generate something like
    
    Column1 Column2   Column3(200_count)
    A       100       2
    A       200       2
    A       200       2
    A       100       2
    B       200       3
    B       200       3
    B       200       3
    C       100       1
    C       200       1
    D       200       3
    D       200       3
    E       200       3

    Jin
    Something lilke this?

    with data as (
    select 'A' column1,       100     column2 from dual union all
    select 'A' column1,       200 from dual union all
    select 'A' column1,       200 from dual union all
    select 'A' column1,       100 from dual union all
    select 'B' column1,       200 from dual union all
    select 'B' column1,       200 from dual union all
    select 'B' column1,       200  from dual union all
    select 'C' column1,       100 from dual union all
    select 'C' column1,       200 from dual union all
    select 'D' column1,       200 from dual union all
    select 'D' column1,       200 from dual union all
    select 'E' column1,       200 from dual
    )
    select
    column1,column2,count(0) over (partition by column1,column2) cnt
    
     from data
     order by column1
    

    The query above is considered the occuerence for each Column1 Column2.
    If you want to count only 200 something like can help you.

    with data as (
    select 'A' column1,       100     column2 from dual union all
    select 'A' column1,       200 from dual union all
    select 'A' column1,       200 from dual union all
    select 'A' column1,       100 from dual union all
    select 'B' column1,       200 from dual union all
    select 'B' column1,       200 from dual union all
    select 'B' column1,       200  from dual union all
    select 'C' column1,       100 from dual union all
    select 'C' column1,       200 from dual union all
    select 'D' column1,       200 from dual union all
    select 'D' column1,       200 from dual union all
    select 'E' column1,       200 from dual
    )
    select
    column1,column2,sum(
    case when column2=200 then
    1
    else
    0
    end
    
    ) over (partition by column1) cnt
    
     from data
     order by column1
    

    Kind regards
    Bobin

    Published by: Buga added second query

  • A job for the analytical function "PARTION OF?

    Hello

    I'm still a little fuzzy on the use of partitions, but this looks like a possible candidate for me.

    I need to count the number of different customers who visit an office in one day. If a customer visits an office more than once in a single day that counts for 1.



    Entry
    OFFICE CLIENT TRAN_DATE
    1-11-1 April 09
    1-11-1 April 09
    1-11-1 April 09

    1 11 2 April 09

    2 22 2 April 09
    2 22 2 April 09
    2 33 2 April 09

    Select a.office as 'OFFICE', a.customer AS 'CUSTOMER', a.tran_date AS 'TRAN_DATE', COUNT (*)
    Of
    (SELECT 1 AS 'OFFICE', AS A 'CUSTOMER' 11, APRIL 1, 2009 "AS"TRAN_DATE"OF THE DOUBLE
    UNION ALL
    SELECT 1, 11, APRIL 1, 2009 "OF THE DOUBLE
    UNION ALL
    SELECT 1, 11, APRIL 1, 2009 "OF THE DOUBLE
    UNION ALL
    SELECT 1: 11, 2 APRIL 2009 "OF THE DOUBLE
    UNION ALL
    SELECT 2: 22, APRIL 2, 2009 "OF THE DOUBLE
    UNION ALL
    SELECT 2: 22, APRIL 2, 2009 "OF THE DOUBLE
    UNION ALL
    SELECT 2: 33, APRIL 2, 2009 "OF THE DOUBLE
    ) one;


    Desired result
    1 1 April 09 1
    1-2 April 09 1
    2 2 April 09 2


    Is this possible with partitions, do I have to use subqueries, or some other methid?

    Thanks in advance for your help,

    Lou

    Published by: wind in the face on April 15, 2009 13:34

    Hey, Lou,

    PARTITION BY is not a function.
    COUNT is a function. There is an aggregate COUNT function and also an analytical function of COUNTY. (Almost all aggregate functions have analytical counterparts).

    How can you tell if a function is used as an aggregate function or Analytics? The analytic form will be "OVER ( )" after his altercation; the overall shape will not be.
    PARTITION BY is one of the elements that may form part of the analytical clause.
    "PARTITION BY x, y ' in an analuytic function corresponds to" GROUP BY x, y "when using functions aggreggate.

    You can get the same results for a large number of problems using either global or analytical of a function versions.
    For example, both versions global and analytical County can tell you that vistied office only 1 customer 1 April 1, but 2 clients visited the office 2 April 2.
    If you use the aggregation function ACCOUNT and ' GROUP BY Office, tran_date ', as John suggested, you will get only one line for each distinct combination of office and tran_date. In other words, even if there are 3 rows of your table where office = 1 and tran_date = April 1, the result set will have onely a row where office = 1 and tran_date = 1 April.
    Because it is exactly what you want, you can use the aggregate COUNT fucntion, as shown in John.

    If you use the analytical ACCOUNT function, there will be a line of output for each row in your table.
    So with the sample data you posted, this query:

    SELECT  office
    ,     tran_date
    ,     COUNT (DISTINCT customer) OVER ( PARTITION BY  office
                                           ,            tran_date
                               )  AS cnt
    FROM     table_x;
    

    will these results:

    .   OFFICE TRAN_DATE          CNT
    ---------- ----------- ----------
             1 01-APR-2009          1
             1 01-APR-2009          1
             1 01-APR-2009          1
             1 02-APR-2009          1
             2 02-APR-2009          2
             2 02-APR-2009          2
             2 02-APR-2009          2
    

    To get the exact results you want, you can use SELECT DISTINCT, like this:

    SELECT DISTINCT
            office
    ,     COUNT (DISTINCT customer) OVER  ...
    
  • Help SQL function

    Hi all

    I have a table which includes

    ID, first_name, last name and date of birth

    I want to retrieve all the records that have the same name and DOB

    for example.

    ID, first_name, last name, DOB

    1 xyz abc 01/01/2012

    hij 2 efg 15/05/2012

    3 xyz abc 01/01/2012

    4 xyz abc 01/01/2012

    so in the output of 1, 3 and 4 rows will appear only.

    can someone advise please on the appropriate SQL function

    Thanks in advance

    Hello

    One way is to use the analytical COUNT function:

    WITH got_num_rows AS

    (

    SELECT id, first_name, last_name, dob

    , COUNT (*) OVER (PARTITION BY first name

    last_name

    ,             dob

    ) AS num_rows

    FROM table_x

    )

    SELECT id, first_name, last_name, dob

    OF got_num_rows

    WHERE num_rows > 1

    ;

    The subquery is needed here, because the analytical functions are calculated after the WHERE clause has been applied.  To use the results of an anlytic function in a WHERE clause, you must calculate the function in a subquery, then you can use the results where you want (including the WHERE clause) of a Super query.

  • ITS POSSIBLE TO CALL A FUNCTION WHEN THE LINES ARE ALREADY MET?

    Hello, I'm new in pl sql and I learn.
    My requirment is:

    I made a function for calculating the values of cumulative of the account period.

    My problem is:

    I have this data

    amount of the account
    12 100
    12 50
    13 200

    and I have this simple query

    SELECT flat, account, acumulated_amount (period)
    THE F1
    GROUP account, the period

    I get

    amount of the account
    12 150
    13 200

    I want to add is to add a column that is calculated by a function. This function calculates the cumulative amount of previous years of account.
    If I insert this select statement so that it will calculate the cumulative amount each online account and what I want is show the amount acumullated after the grouped data

    For example: my accumulated amount of the 12 is 1000 and based on my request I will receive

    account amount acumullated
    12 150 2000
    13 200

    because the cumulative amount in each line and I need perform the calculation only when data are collected. Something like this:


    account amount acumullated
    12-150-1000
    13 200

    Someone has an idea how to do this?

    Thanks in advance

    Paulo Duarte

    Hi, Paulo,

    user4256563 wrote:
    Hello, I'm new in pl sql and I learn.
    My requirment is:

    I made a function for calculating the values of cumulative of the account period.

    My problem is:

    I have this data

    amount of the account
    12 100
    12 50
    13 200

    Whenever you have a problem, please psot of CREATE TABLE and INSERT statements for your sample data, even if it's only 3 rows.
    Always say what version of Oracle you are using (for example, 11.2.0.1.0).

    and I have this simple query

    SELECT flat, account, acumulated_amount (period)
    THE F1
    GROUP account, the period

    I get

    amount of the account
    12 150
    13 200

    You have 3 columns in your SELECT statement, but only 2 columns in the output. Is one of the output NULL columns?

    I want to add is to add a column that is calculated by a function. This function calculates the cumulative amount of previous years of account.
    If I insert this select statement so that it will calculate the cumulative amount each online account and what I want is show the amount acumullated after the grouped data

    For example: my accumulated amount of the 12 is 1000 and based on my request I will receive

    account amount acumullated
    12 150 2000
    13 200

    Sorry, I don't see how you get 1000 or 2000 for examples of data that you said that you have. Can you explain, step by step, how to get this figure?

    because the cumulative amount in each line and I need perform the calculation only when data are collected. Something like this:

    account amount acumullated
    12-150-1000
    13 200

    That's what you want, or you want the results given just before her, with accumulated = 2000?
    Whatever it is, I still don't see how you get 1000 or 2000 of 100, 50 and 200.

    Someone has an idea how to do this?

    Analytical functions can do what you want. When you use analytical functions and aggregation in the same query, the GROUP BY clause is applied and aggregate functions are calculated before the analytical functions are started.

    You can write (or analytical) global functions defined by the user. For a simple (and very useful) example, called STRAGG, see
    http://asktom.Oracle.com/pls/asktom/f?p=100:11:0:P11_QUESTION_ID:2196162600402

  • using the function min() inside the instruction box

    I have a problem with the following select statement

    Select
    patient_id
    , sum (case when ch.cancer_site_id in ('3', ' 39 ', ' 12') and min (ch.diagnosis_age) < 40 0' then '1' other ' end) in breast cancer
    Of...
    Patient_id group

    I get an error "not a single group group function.


    The main table, that I work with is so implemented.

    PatientID | diagnosis_age | cancer_site_id

    12345678 | 35. 4
    12345678 | 40. 4
    12345678 | 42. 12
    12345678 | 34. 31
    87654321 | 50. 12

    cancer_site_ids 4 and 31 must get grouped together and called breast cancer. cancer_site_id 12 (and others) is cancer of the colon.

    Finally I need the output to look like this

    PatientID | min (breast_diagnosis_age) < 40 | min (breast_diagnosis_age) > 40 | min (colon_diagnosis_age) > 40
    -------------------------------------------------------------------------------
    12345678 | 1. 0 | 1
    87654321 | 0 | 0 | 1

    My final request is much more complicated than that, but it's the last part that I can't understand.

    Hello

    Welcome to the forum!

    You can use the analytic MIN function to get the earlier diagnosis_age.
    Analytical functions are calculated after aggregation functions. If you use the aggregate functions to rotate the data, this means that you need to calculate the minimum age in a subquery and do all aggregates in the main query.
    I mean, it is something like this:

    WITH     got_min_diagnosis_age     AS
    (
         SELECT     patiendid
         ,     MIN (diagnosis_age) OVER ( PARTITION BY CASE
                                            WHEN  cancer_site  IN (4, 31)
                                            THEN  'breast'
                                                WHEN  cancer_site  IN (3, 12, 39)
                                            THEN  'colon'
                                                       END
                              )     AS diagnosis_age
         ,     CASE
                  WHEN  cancer_site  IN (4, 31)     THEN  'breast'
                  WHEN  cancer_site  IN (3, 12, 39)     THEN  'colon'
              END     AS type
         FROM    table_x
    )
    SELECT       patientid
    ,       COUNT ( CASE
                   WHEN  type = 'breast'
                   AND   min_diagnosis_age <= 40
                   THEN  1
                  END
                )     AS breast_up_to_40_cnt
    ,       COUNT ( CASE
                   WHEN  type = 'breast'
                   AND   min_diagnosis_age >  40
                   THEN  1
                  END
                )     AS breast_over_40_cnt
    ,       COUNT ( CASE
                   WHEN  type = 'colon'
                   AND   min_diagnosis_age >  40
                   THEN  1
                  END
                )     AS colon_over_40_cnt
    FROM      got_min_diagnosis_age
    GROUP BY  patientid
    ORDER BY  patientid
    ;
    

    You can also calculate type in a subquery, then use it to calculate the min_diagnosis_age for the type in a second subquery. If the expression to get type is much more complicated in reality that it is in this small sample, which can be better.

    Published by: Frank Kulash, November 3, 2010 15:00

    You have a cancer_site table, that is, a table that has one line for each valid value of cancer_site (3, 4, 12,...)?
    If so, you need to add a column to this table to indicate what kind of cancer, each site is associated. You could join this table in the subquery, rather than using CASE expressions. The fact that 4 of the site is associated with breast cancer is the type of information that belongs to a table, not hardcoded in a query.
    If you do not have a cancer_siote table, thus creating one can be a good idea.

  • [8i] help with function with parameters (for the calculation of the work)

    Let me start by saying, I've never written a function before, and I do not have access to create a feature in my database (that is, I can't test this feature). I am trying to achieve a function I can ask my IT Department to add for me. I hope that someone can take a look at what I wrote and tell me if this should work or not, and if it's the right way to go to solve my problem.

    I'm creating a function to make a very simple calculation of work (add/subtract a number of days to a date in the calendar).

    The database, I work with has a table with the schedule of work. Here is a sample table and sample data, representative of what is in my work table calendar:
    CREATE TABLE caln
    (     clndr_dt     DATE,
         shop_days     NUMBER(5)
         CONSTRAINT caln_pk PRIMARY KEY (clndr_dt)
    );
    
    INSERT INTO     caln
    VALUES (To_Date('01/01/1980','mm/dd/yyyy'),0);
    INSERT INTO     caln
    VALUES (To_Date('01/02/1980','mm/dd/yyyy'),1);
    INSERT INTO     caln
    VALUES (To_Date('01/03/1980','mm/dd/yyyy'),2);
    INSERT INTO     caln
    VALUES (To_Date('01/04/1980','mm/dd/yyyy'),3);
    INSERT INTO     caln
    VALUES (To_Date('01/05/1980','mm/dd/yyyy'),3);
    INSERT INTO     caln
    VALUES (To_Date('01/06/1980','mm/dd/yyyy'),3);
    INSERT INTO     caln
    VALUES (To_Date('01/07/1980','mm/dd/yyyy'),4);
    INSERT INTO     caln
    VALUES (To_Date('01/08/1980','mm/dd/yyyy'),5);
    INSERT INTO     caln
    VALUES (To_Date('01/09/1980','mm/dd/yyyy'),6);
    INSERT INTO     caln
    VALUES (To_Date('01/10/1980','mm/dd/yyyy'),7);
    INSERT INTO     caln
    VALUES (To_Date('01/11/1980','mm/dd/yyyy'),8);
    INSERT INTO     caln
    VALUES (To_Date('01/12/1980','mm/dd/yyyy'),8);
    INSERT INTO     caln
    VALUES (To_Date('01/13/1980','mm/dd/yyyy'),8);
    INSERT INTO     caln
    VALUES (To_Date('01/14/1980','mm/dd/yyyy'),9);
    The table includes since 01/01/1980 but 31/12/2015.

    I have written (and validated) this parameter query that performs the calculation of my working day (mday):
    SELECT     cal.clndr_dt
    FROM     CALN cal
    ,     (
         SELECT     cal.shop_days+:mdays     AS new_shop_days
         FROM     CALN cal
         WHERE     cal.clndr_dt     =:start_date
         ) a
    WHERE     cal.shop_days     = a.new_shop_days
    AND     ROWNUM          =1
    ORDER BY     cal.clndr_dt;
    Based on this request, I created the following function (and I have no idea if it works or if the syntax is right, etc..):
    CREATE OR REPLACE FUNCTION add_mdays 
         (start_date     IN DATE,
         mdays          IN NUMBER(5))
    RETURN     DATE 
    IS
         new_date DATE;
    BEGIN
    
         SELECT     cal.clndr_dt
         FROM     CALN cal
         ,     (
              SELECT     cal.shop_days+mdays     AS new_shop_days
              FROM     CALN cal
              WHERE     cal.clndr_dt     =start_date
              ) a
         WHERE     cal.shop_days     = a.new_shop_days
         AND     ROWNUM          =1
         ORDER BY     cal.clndr_dt;
    
         RETURN     new_date;
    
    END add_mdays;  //edit 9:31 AM - noticed I left off this bit
    I'm also not sure how to do to have the function handle results that would return a date outside the range of dates that appear in the table (prior to 01/01/1980 or after until 31/12/2015 - or, another way to look at what was, before the caln.clndr_dt or the caln.clndr_dt MAX value MIN value).

    My goal is to be able to use the function in a situation similar to the following:

    First of all, here is a sample table and data:
    CREATE TABLE orders
    (     ord_no          NUMBER(5),
         plan_start_dt     DATE,
         CONSTRAINT orders_pk PRIMARY KEY (ord_no)
    );
    
    INSERT INTO orders
    VALUES (1,To_Date('01/08/1980','mm/dd/yyyy'));
    INSERT INTO orders
    VALUES (2,To_Date('01/09/1980','mm/dd/yyyy'));
    INSERT INTO orders
    VALUES (3,To_Date('01/10/1980','mm/dd/yyyy'));
    And here's how I would use my function:
    SELECT     orders.ord_no
    ,     orders.plan_start_dt
    ,     add_mdays(orders.plan_start_dt, -3) AS prep_date
    FROM     orders
    Thus, the function would allow me to come back, for each command in my table of orders, the date is 3 days working (mdays) before the start of the plan of each order.

    I go about it the right way? I have to create a function to do this, or is there a way for me to integrate my request (which makes my mday calculation) in the example query above (eliminating the need to create a function)?

    Thank you very much in advance!

    Published by: user11033437 on February 2, 2010 08:55
    Fixed some typos in the last insert statements

    Published by: user11033437 on February 2, 2010 09:31 (fixed some syntax in the function)

    Hello

    Ah, referring to Oracle 8 and is not not able to test your own code makes me nostalgic for the good old days, when you have entered your cards and led to a window to the computer center and waited an hour for the work to be performed and then seen printing to find that you had made a typo.

    If you write functions, you should really test yourself. Like all codes, functions forge be written small not: write a line or two (or sometimes just a part of what would later become a single line), test, make sure it is running properly and repeat.
    Ideally, your employer must create a pattern of development in a development database that you can use.
    You can legally download your own instance of Oracle Express Edition free; just be careful not to use features that are not available in the database where the code will be deployed.

    You need a function to get the desired results:

    SELECT       o.ord_no
    ,       o.plan_start_dt
    ,       MIN (e.clndr_dt)     AS prep_date
    FROM       orders     o
    ,       caln          l
    ,       caln          e
    WHERE       l.clndr_dt     = o.plan_start_dt
    AND       e.shop_days     = l.shop_days - 3
    GROUP BY  o.ord_no
    ,            o.plan_start_dt
    ;
    

    It would be more effective (and somewhat simpler) If you've added a column (let's call it work_day) identified whether each line represents a work_day or not.
    For each value of shop_days, exactly 1 row will be considered as a working day.
    Then, the query may be something like:

    SELECT       o.ord_no
    ,       o.plan_start_dt
    ,       e.clndr_dt          AS prep_date
    FROM       orders     o
    ,       caln          l
    ,       caln          e
    WHERE       l.clndr_dt     = o.plan_start_dt
    AND       e.shop_days     = l.shop_days - 3
    AND       e.work_day     = 1
    ;
    

    You can use the analytic LAG function to populate the work_day column.

    A function would certainly be useful, although perhaps slower.

    The function you have posted has some errors:
    an argument can be stated under NUMBER (5); Just NUMBER.
    (b) when you SELECT in PL/SQL, as you do, you must SELECT a variable to store the results.
    (c) ROWNUM is arbitrary (making it useless in this problem) unless you draw a neat subquery. I don't think you can use ORDER BY in subqueries in Oracle 8. Use the ROW_NUMBER analytic function.
    (d) the service must end with an END statement.

    Given your current caln table, here's how I would write the function:

    CREATE OR REPLACE FUNCTION add_mdays
         ( start_date     IN           DATE          DEFAULT     SYSDATE,
           mdays          IN           NUMBER          DEFAULT     1
         )
    RETURN     DATE
    DETERMINISTIC
    IS
         --     add_mdays returns the DATE that is mdays working days
         --     after start_date.  (If mdays < 0, the DATE returned
         --     will be before start_date).
         --     Work days do not include Saturdays, Sundays or holidays
         --     as indicated in the caln table.
    
         new_date     DATE;          -- to be returned
    BEGIN
    
         SELECT     MIN (t.clndr_dt)
         INTO     new_date
         FROM     caln     f     -- f stands for "from"
         ,     caln     t     -- t stands for "to"
         WHERE     f.clndr_dt     = TRUNC (start_date)
         AND     t.shop_days     = f.shop_days + TRUNC (mdays)
         ;
    
         RETURN     new_date;
    END     add_mdays;
    /
    SHOW ERRORS
    

    Production code forge be robust (which includes "fool-proofing").
    Try to anticipate what people errors might appeal to your function and correct for them where possible.
    For example, if it only makes sense for start_date at midnight, mdays to be an integer, use TRUNC in the function where soembody passes a good value.
    Allow default arguments.
    Comment of your function. Put all comments within the service (i.e. after CREATION and before the END) so that they will remain in the data dictionary.
    If, given the same arguments, the function always returns the same value, mark it as DETERMINISTIC, for efficiency. This means that the system will remember the values transmitted rather than to call the function whenever it is said to.

    I wish I could score questions such as 'Correct' or 'useful '; you get 10 points for sure.
    You posted CREATE TABLE and INSERT statements (without even be begged).
    You gave a clear description of the problem, including the expected results.
    The code is well formatted and easy to read.
    All around, one of the more thoughtful and well written questions I've seen.
    Play well! Keep up the good work!

    Published by: Frank Kulash, February 2, 2010 13:10
    Added to my own version of the function.

  • What makes this deterministic query?

    copy paste everything here, from oradoc. It's a short read. "The following example shows how the FIRST_VALUE function deterministic by ordering on a unique key.' '.

    Orders only complementary criteria is:

    order of salary desc, hire_date

    vs

    salary desc order (other examples).

    Basically could someone please explain to me how the last example of query/is deterministic.

    Goal

    FIRST_VALUEis an analytic function. It returns the first value in an ordered set of values. If the first value of the game is null, the function returns NULL unless you specify IGNORE NULLS . This setting is useful for data densification. If you specify IGNORE NULLS , then FIRST_VALUE returns non-null of punch in the game, or NULL If all values are null. See "using partitioned outer joins: examples ' for an example of data densification.

    You cannot nest analytic functions using FIRST_VALUE or any other analytic function for expr . However, you can use other built-in function expressions expr . Refer to "about the SQL Expressions" for more information about the valid forms of expr .

    Examples

    For each employee in the Department 90, the following example selects the name of the employee with the lowest wages.

    image.png

    The example illustrates the nondeterministic nature of the FIRST_VALUE function. Kochhar and DeHaan have the same salary, are stowed adjacent. Kochhar appears first because the rows returned by the subquery are ordered by employee_id . However, if the rows returned by the subquery are sorted by employee_id by descending order, as in the following example, the function then returns a different value:image.png

    The following example shows how the FIRST_VALUE function deterministic by ordering on a unique key.

    image.png

    Hello

    I agree with your first reaction: looks like a bad example for me, too.  In the hr.employees table, the combination [wages, hire_date] lies be unique, so, you place your order by the two columns only arrives to give consistent results.  As long as no 2 employees have both the same pay and same hire_date, the query will produce the same results.  But I wouldn't say that deterministic unless there was a constraint to ensure that the combination is necessarily unique.  It would have been better if they had used employee_id (which is unique) instead of the hire_date as the tiebreaker.

  • Presentation of the results help

    I came across a weird result when you use the analytical LAST_VALUE function which did not work as expected. I install a simple test and it is not yet worked as I expect:

    create the table first_test (col1, col2, col3 date number number);

    Insert Into first_test VALUES(1,100,'01-Jan-11');
    Insert Into first_test VALUES(1,101,'02-Jan-11');
    Insert Into first_test VALUES(1,100,'03-Jan-11');
    Insert Into first_test VALUES(2,100,'01-Jan-11');
    Insert Into first_test VALUES(2,101,'02-Jan-11');
    Insert Into first_test VALUES(2,100,'03-Jan-11');

    I then run the following query:

    SELECT col1,
    col2,
    col3,
    LAST_VALUE (col2) OVER (PARTITION BY col1 ORDER BY col3) as test
    OF first_test;

    All the documentation, I find, I expect that the value of the "test" column would be 100 for each record, because it should partition by col1, col3 control and then get the last value in the ordered list (100). My results look like this:


    "COL1", "COL2", "COL3" 'TEST '.
    1 100 1 JANUARY 11 100
    1 101 2 JANUARY 11 101
    1 100 100 3 JANUARY 11
    2 100 1 JANUARY 11 100
    2 101 2 JANUARY 11 101
    2 100 100 3 JANUARY 11

    I've also tested this using the FIRST_VALUE function:

    SELECT col1,
    col2,
    col3,
    FIRST_VALUE (col2) OVER (PARTITION BY col1 ORDER BY col3) as test
    OF first_test;


    "COL1", "COL2", "COL3" 'TEST '.
    1 100 1 JANUARY 11 100
    1 101 2 JANUARY 11 100
    1 100 100 3 JANUARY 11
    2 100 1 JANUARY 11 100
    2 101 2 JANUARY 11 100
    2 100 100 3 JANUARY 11


    It is the result that I expect that the first value in the sorted list is 100. My DB is Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64 bit.

    Did I miss something in the way it should work?

    Hello

    Welcome to the forum!

    It's a very intuitive feature LAST_VALUE.
    The best way to get the desired results is to use the FIRST_VALUE order and descending, like this:

    SELECT  col1,
         col2,
         col3,
         FIRST_VALUE (col2) OVER ( PARTITION BY  col1
                                 ORDER BY       col3     DESC
                        ) AS test
    FROM    first_test;
    

    The reason why LAST_VALUE didn't work as expected is to the windowing clause (or lack thereof). With any analytic function, when you use an ORDER BY clause, you can also specify a window clause, using the keyword LINE or LINES. If you do not specify a window clause, then the default value is RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. So, if you use the default windowing clause, LAST_VALUE means the last until and including the current line , then, indeed, LAST_VALUE (col2) is just the same as col2.
    With the help of FIRST_VALUE, the default windowing clause works the way you want.

    To get the results you want using LAST_VALUE, you must explicitly give a windowing clause, like this:

    SELECT  col1,
         col2,
         col3,
            LAST_VALUE (col2)  OVER ( PARTITION BY  col1
                                ORDER BY       col3
                          ROWS BETWEEN     CURRENT ROW
                               AND     UNBOUNDED FOLLOWING
                        ) AS test
    FROM    first_test;
    

    Published by: Frank Kulash, August 18, 2011 15:43
    Additional explanation

Maybe you are looking for