Purpose of the ORDER BY clause in the analytic function Min Max

I was always using analytical functions like Min Max without ORDER BY clause. But today I used with the ORDER BY clause. The results are very different. I would like to know the purpose of the ORDER BY clause in Min, Max and analogues of analytical functions.

user10566312 wrote:
I was always using analytical functions like Min Max without ORDER BY clause. But today I used with the ORDER BY clause. The results are very different. I would like to know the purpose of the ORDER BY clause in Min, Max and analogues of analytical functions.

It is a good point that many developers are not so aware. As far as I understand it the way it works.

Some analytical functions do not need an order by or windowing clause (SUM, COUNT, MIN, etc.). If there is no specified window, then the full score is the window.
As soon as you add a command also add you a windowing clause. This window has the default value of 'rank ofrows between unbounded preceding and current_row. So as soon as you add an order by clause, you get a sliding window.

Documentation: http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions001.htm

windowing_clause
...
You cannot specify this clause unless you specified the order_by_clause. Window limits defined by the clause RANGE you can not specify only a single expression to the > order_by_clause. Please refer to 'Restrictions on the ORDER BY Clause'.

example of

with testdata as (select 10 numval, level lv from dual connect by level < 10)
select lv, numval, sum(numval) over () sum1, sum(numval) over (order by lv) sum2
from testdata;

LV NUMVAL SUM1 SUM2
-- ------ ---- ----
 1     10   90   10
 2     10   90   20
 3     10   90   30
 4     10   90   40
 5     10   90   50
 6     10   90   60
 7     10   90   70
 8     10   90   80
 9     10   90   90 

Published by: Sven w. on 25 Sep 2012 16:57 - default behavior has been corrected. Thanks to Chris

Tags: Database

Similar Questions

  • A question about the analytical function used with the GROUP BY clause in SHORT

    Hi all

    I created the following table named myenterprise
    CITY       STOREID    MONTH_NAME TOTAL_SALES            
    ---------- ---------- ---------- ---------------------- 
    paris      id1        January    1000                   
    paris      id1        March      7000                   
    paris      id1        April      2000                   
    paris      id2        November   2000                   
    paris      id3        January    5000                   
    london     id4        Janaury    3000                   
    london     id4        August     6000                   
    london     id5        September  500                    
    london     id5        November   1000
    If I want to find which is the total sales by city? I'll run the following query
    SELECT city, SUM(total_sales) AS TOTAL_SALES_PER_CITY
    FROM myenterprise
    GROUP BY city
    ORDER BY city, TOTAL_SALES_PER_CITY;
    that works very well and produces the expected result, i.e.
    CITY       TOTAL_SALES_PER_CITY   
    ---------- ---------------------- 
    london     10500                  
    paris      17000            
    Now in one of my books SQL (Mastering Oracle SQL) I found another method by using the SUM, but this time as an analytic function. Here's what the method of the book suggests as an alternative to the problem:
    SELECT city, 
           SUM(SUM(total_sales)) OVER (PARTITION BY city) AS TOTAL_SALES_PER_CITY
    FROM myenterprise
    GROUP BY city
    ORDER BY city, TOTAL_SALES_PER_CITY;
    I know that the analytic functions are executed after the GROUP BY clause has been transformed completely and Unlike regular aggregate functions, they return their result for each line belonging to the partitions specified in the partition clause (if there is a defined partition clause).

    Now my problem is that I do not understand what we have to use two functions SUM? If we only use one only, i.e.
    SELECT city, 
           SUM(total_sales) OVER (PARTITION BY city) AS TOTAL_SALES_PER_CITY
    FROM myenterprise
    GROUP BY city
    ORDER BY city, TOTAL_SALES_PER_CITY;
    This generates the following error:
    Error starting at line 2 in command:
    SELECT city, 
           SUM(total_sales) OVER (PARTITION BY city) AS TOTAL_SALES_PER_CITY
    FROM myenterprise
    GROUP BY city
    ORDER BY city, TOTAL_SALES_PER_CITY
    Error at Command Line:2 Column:11
    Error report:
    SQL Error: ORA-00979: not a GROUP BY expression
    00979. 00000 -  "not a GROUP BY expression"
    *Cause:    
    *Action:
    The error is generated for the line 2 column 11 which is, for the expression SUM (total_sales), well it's true that total_sales does not appear in the GROUP BY clause, but this should not be a problem, it has been used in an analytical function, so it is evaluated after the GROUP BY clause.

    So here's my question:

    Why use SUM (SUM (total_sales)) instead of SUM (total_sales)?


    Thanks in advance!
    :)





    In case you are interested, that's my definition of the table:
    DROP TABLE myenterprise;
    CREATE TABLE myenterprise(
    city VARCHAR2(10), 
    storeid VARCHAR2(10),
    month_name VARCHAR2(10),
    total_sales NUMBER);
    
    INSERT INTO myenterprise(city, storeid, month_name, total_sales)
      VALUES ('paris', 'id1', 'January', 1000);
    INSERT INTO myenterprise(city, storeid, month_name, total_sales)
      VALUES ('paris', 'id1', 'March', 7000);
    INSERT INTO myenterprise(city, storeid, month_name, total_sales)
      VALUES ('paris', 'id1', 'April', 2000);
    INSERT INTO myenterprise(city, storeid, month_name, total_sales)
      VALUES ('paris', 'id2', 'November', 2000);
    INSERT INTO myenterprise(city, storeid, month_name, total_sales)
      VALUES ('paris', 'id3', 'January', 5000);
    INSERT INTO myenterprise(city, storeid, month_name, total_sales)
      VALUES ('london', 'id4', 'Janaury', 3000);
    INSERT INTO myenterprise(city, storeid, month_name, total_sales)
      VALUES ('london', 'id4', 'August', 6000);
    INSERT INTO myenterprise(city, storeid, month_name, total_sales)
      VALUES ('london', 'id5', 'September', 500);
    INSERT INTO myenterprise(city, storeid, month_name, total_sales)
      VALUES ('london', 'id5', 'November', 1000);
    Edited by: dariyoosh on April 9, 2009 04:51

    It is clear that thet Analytics is reduntant here...
    You can even use AVG or any analytic function...

    SQL> SELECT city,
      2         avg(SUM(total_sales)) OVER (PARTITION BY city) AS TOTAL_SALES_PER_CITY
      3  FROM myenterprise
      4  GROUP BY city
      5  ORDER BY city, TOTAL_SALES_PER_CITY;
    
    CITY       TOTAL_SALES_PER_CITY
    ---------- --------------------
    london                    10500
    paris                     17000
    
  • SQL using the analytic function


    Hi all

    I want a help in the creation of my SQL query to retrieve the data described below:

    I have a test of sample table containing data as below:

    State ID Desc

    MICHAEL 1 T1

    ACTIVE 2 T2

    T3 3 SUCCESS

    DISABLE THE T4 4

    The thing I want to do is to select all the lines with an ACTIVE status in the table but is there is no ACTIVE status, my request will give me the last line with MICHAEL status.

    I can do this in a single request by using the analytical function for example, if yes can yiu help me on the request of unpacking.

    Kind regards

    Raluce

    Something like that?

    I had to fix it.

    with testdata until)
    Select 1 id, "T1" dsc "DISABLED" status of Union double all the
    Select 2 id, 'T2' dsc, the status "ACTIVE" of all the double union
    Select id 3, "T3" dsc, the status of 'SUCCESS' of all the double union
    Select 4 id, "T4" dsc "DISABLED" status of double
    )

    Select
    ID
    dsc
    status
    of testdata
    where
    status =
    -case when (select count (*) in testdata where status = 'ACTIVE') > 0
    then 'ACTIVE '.
    Another 'DISABLED '.
    end
    and)
    ID in (select id from testdata where status = ' ACTIVE')
    or
    ID = (select max (id) in testdata when status = 'DISABLED')
    )

    STATE ID DSC

    '2' 'T2' 'ACTIVE '.

    Maybe it's more efficient

    Select
    ID
    dsc
    status
    of testdata
    where
    status =
    -case when (select count (*) in testdata where status = 'ACTIVE') > 0
    then 'ACTIVE '.
    Another 'DISABLED '.
    end
    and
    ID =)
    -case when (select count (*) in testdata where status = 'ACTIVE') > 0
    then id
    on the other
    (select max (id) in testdata when status = 'DISABLED')
    end
    )

    Post edited by: correction of chris227

    Post edited by: chris227
    extended

  • Report Builder 6i do not recognize the analytical functions

    Hi all, in an attempt to speed up a slow query, I applied the analytical function to it. I can save the query in the generator without any problem, however, I can't create data between this request and other links. After I have comment on the analytical function, data bindings can be made. My colleague says Report Builder 6i is too old so he can recognize only the ANSI SQL syntax. Since our server DB uses Oracle 10 g 2, is there a way for the generator of reports to identify and compile syntax of Oracle 10 g?

    Thank you very much.

    Hello

    Your colleague is right. Even if the SQL query is executed by the DB server, reports must analyze the SQL query.

    The SQL parser included in reports 6i-based 8.0.6

    You can see this version using the report designer:

    Menu: Help-> on Report Builder...

    ORACLE Server Release 8.0.6.0.0

    Concerning

  • Understanding on the analytical function sum() (order of)

    Could you please explain Having_order_by of the calculation of values of below query column?
    I understand that No_Partition column was calculated on the full set of results
    select level
    ,sum(level) over(order by level) Having_order_by
    ,sum(level) over() No_Partition
    from dual 
    connect by level < 6

    Hello

    ActiveSomeTimes wrote:
    Could you please explain Having_order_by of the calculation of values of below query column?
    I understand that No_Partition column was calculated on the full set of results

    select level
    ,sum(level) over(order by level) Having_order_by
    ,sum(level) over() No_Partition
    from dual
    connect by level < 6
    

    When you have an ORDER BY clause, the function works only on a window, which is a subset of the result set, compared to the current line.
    When you say 'ORDER OF LEVEL', it only will work on levels less than or equal to its current LEVEL, etc.
    LEVEL = 1, the analytic fucntion will only look at the LEVEL<= 1,="" that="" is,="" just="" 1;="">
    LEVEL = 2, the analytic fucntion will only look at the LEVEL<= 2,="" that="" is,="" 1="" and="" 2;="">
    LEVEL = 3, the analytic fucntion will only look at the LEVEL<= 3,="" that="" is,="" 1,="" 2="" and="">
    ...
    LEVEL = 6, the analytic fucntion will only look at the LEVEL<= 6,="" that="" is,="" 1,="" 2,="" 3,="" 4,="" 5="" and="">

    In the call to function without the ORDER BY clause, the examines the entire results full regrdless of what value LEVEL has on the current line.

  • Get the date range min/max for consecutive events.

    Hi all...

    I am fairly new to the programming of the DB and is working on some examples I picked up a few places. The database version is 10g R2.

    I would like to configure the data here and I can explain my requirement.

    create table table_1
    (product_id varchar2(25),
    region_id  number,
    event_id number
    event_date date,
    event_status number(1))
    /
    
    
    

    Now the data because it is->

    insert into table_1 values ('Prod-1',10, null, to_date('01-feb-2014','dd-mon-yyyy'),null)
    /
    insert into table_1 values('Prod-1',10, 1001, to_date('10-mar-2014','dd-mon-yyyy'), 1)
    /
    insert into table_1 values('Prod-1',10, 1001, to_date('20-mar-2014','dd-mon-yyyy'), 3)
    /
    insert into table_1 values('Prod-1',10,1002, to_date('01-apr-2014','dd-mon-yyyy'), 1)
    /
    insert into table_1 values('Prod-1',10, 1002, to_date('10-apr-2014','dd-mon-yyyy'), 3)
    /
    commit
    /
    
    
    
    

    If the table now contains the following data

    select * from table_1; 
    
    
    

    PRODUCT_ID REGION_ID EVENT ID EVENT_DAT EVENT_STATUS

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

    Prod-1 10 1 February 14

    Prod-1 10 1001 10 March 14 1

    Prod-1 10 1001 20 March 14 3

    Prod-1 10 1002 1 April 14 1

    Prod-1 10 1002 April 10, 14 3

    Now, the condition is as follows:

    Above is the dates start and end for the tests on a product in a given region. The event_status column indicates the dates of beginning and end. Event_status = 1, for the date of beginning and the event_status = 3 of the end date.

    A new event is now coming from March 21 and ending on March 31.

    The power required is a product identifier / region; If there are events that are ending and then count the days, for example, 1001 to end on March 20, but now the new event begins on 21 March... and the new event ends on 31 March and event 1002 begins 01 - Apr... and so on.

    The output required for this is as follows:

    PRODUCT_ID REGION_ID EVENT_MIN_DATE EVENT_MAX_DATE

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

    Prod-1 10 10 14 March 10 April 14

    The output should give a product identifier / region, when events are immediately after the other, out the min date of beginning and end of max for all these manifestations of "back to back".

    Now I wrote the code for this, but it goes into a purely 'loop' for application in PLSQL... But my head tells me that if the results are correct. the PLSQL implementation is not the most efficient and effective way.

    Can someone help me to form the query? I tried to use functions analytical min/max but it gives me the start and end dates back even if my events are not "back to back" or previous/succeed each other... so my query result is not quite correct.

    Am reading on the TYPE clause but would be grateful if someone could help me with this query... or any other form better to implement this event so PLSQL can be used. The database version is 10g R2.

    Thank you

    K

    PS - The number of such events back to back is limited to 4 and the events could be created in any order. But if someone could help me with the scenario above; am sure I could make a request addressed to any change in the order. :-)

    No this isn't a recursive with clause, perhaps the UNION ALL you got confused. She will work with 10g.

    Since there are 2 tables that you said, the block all_data brings together only the lines of the two tables. table_1 start_date and end_date are built from the event_status (where the max in group by).

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

  • How to use Group by in the analytic function

    I need to write the Department that has the minimum wage in a row. She must be with analytical function, but I have problem in group by. I can't use min() without group by.

    Select * from (min (sal) select min_salary, deptno, RANK() ON RN (ORDER BY sal CSA, CSA rownum) of the Group of emp by deptno) < 20 WHERE RN order by deptno;

    Published by: senza on 6.11.2009 16:09

    Hello

    senza wrote:
    I need to write the Department that has the minimum wage in a row. She must be with analytic function

    Therefore with an analytic function? Looks like it is a duty.

    The best way to get these results is with an aggregate, not analysis, function:

    SELECT      MIN (deptno) KEEP (DENSE_RANK FIRST ORDER BY sal)     AS dept_with_lowest_sal
    FROM      scott.emp
    ;
    

    Note that you do not need a subquery.
    This can be modififed if, for example, you want the lowest Department with the sal for each job.

    But if your mission is to use an analytical function, that's what you have to do.

    but I have problem in group by. I can't use min() without group by.

    Of course, you can use MIN without GROUP BY. Almost all of the aggregate (including MIN) functions have analytical equivalents.
    However, in this issue, you don't need to. The best analytical approach RANK only, not use MIN. If you ORDER BY sal, the lines with rank = 1 will have the minimum wage.

    Select * from (min (sal) select min_salary, deptno, RANK() ON RN (ORDER BY sal CSA, CSA rownum) of the Group of emp by deptno) WHERE the RN< 20="" order="" by="">

    Try to select plain old sal instead of MIN (sal) and get reid of the GROUP BY clause.

    Add ROWNUM in the ORDER BY clause is to make RANK return the same result as ROW_NUMBER, every time that it is a tie for the sal, the output will still be distinct numbers. which line gets the lower number will be quite arbitrary, and not necessarily the same every time you run the query. For example, MARTIN and WARD have exactly the same salary, 1250. The query you posted would assign rn = 4 to one of them and rn = 5 to another. Who gets 4? It's a toss-up. It could be MARTIN the first time you try, and WARD the next. (In fact, in a very small table like scott.emp, it probably will be consistent, but always arbitrary.) If this is what you want, it would be clearer and simpler just to use ROW_NUMEBR instead of RANK.

  • SQL question, perhaps with the analytical functions?

    I have a small problem:

    I have a table with:

    DAY_ID, PAGE_ORDER, SID, TIME, CONTENT.

    I want only to the rank (min) of lines with the same content when there is more than

    the one with the same content that follows.

    The data are:

    DAY PAGE_ORDER SID TIMES CONTENT

    20150825 1 4711 25.08.15 06:38:43 / body/home

    4711 2 20150825 25.08.15 06:39:10 home, aufmacher, Home, 42303938

    20150825 3 4711 25.08.15 06:39:15 welcome, aufmacher, Home, 42303938

    20150825 4 4711 25.08.15 06:39:20 home, aufmacher, Home, 42303938

    20150825 5 4711 25.08.15 06:39:24 home, aufmacher, Home, 42303938

    20150825 6 4711 25.08.15 06:39:32 home, aufmacher, Home, 42303938

    20150825 7 4711 25.08.15 06:39:39 home/aufmacher/Home/42303938

    20150825 8 4711 25.08.15 06:39:46 welcome, aufmacher, Home, 42303938

    20150825 9 4711 25.08.15 06:39:49 home, aufmacher, Home, 42303938

    4711 10 20150825 25.08.15 06:39:51 home, aufmacher, Home, 42303938

    4711 11 20150825 25.08.15 06:41:17 pol/art/2015/08/24/paris

    20150825 12 4711 25.08.15 06:42:36 / body/home

    20150825 13 4711 25.08.15 07:06:09 / body/home

    20150825 14 4711 25.08.15 07:06:36 reg/article/memo

    I want as a result:

    20150825 1 4711 25.08.15 06:38:43 / body/home

    4711 2 20150825 25.08.15 06:39:10 home, aufmacher, Home, 42303938

    4711 11 20150825 25.08.15 06:41:17 pol/art/2015/08/24/paris

    20150825 12 4711 25.08.15 06:42:36 / body/home

    20150825 14 4711 25.08.15 07:06:36 reg/article/memo

    Who knows a good way?

    Thank you very much

    It sounds like a simple solution group. You group by content and maybe a few other columns such as the day and sid. So, you want to show some value of inside this group. Several different aggregate functions to do this.

    Not tested, because of lack of tabe create and insert scripts

    select day, sid, content
            ,min(page_order) as page_order
            ,min(times) as times -- if the first page_order also has the first time
            ,min(times) keep dense_rank first (order by page_order) as times2 -- this is needed in case the first page_order is at a later time
    from yourTable
    group by day, sid, content
    

    If Solomon is right, and several identical content may exist (the example data show that). Then we can use the Tabibitosan method to create the groups.

    with step1 as (select t1.*, row_number() over (partition by day, sid, content order by page_order) rn
                         from yourTable
                         )
    select  day, sid, content
             , page_order - rn as group_number
             , min(page_order) as page_order
             , min(times) as times -- if the first page_order also has the first time
             , min(times) keep dense_rank first (order by page_order) as times2 -- this is needed in case the first page_order is at a later time
    from step1
    group by day, sid, content, page_order - rn
    order by day, sid, content, group_number;
    
  • Nth salary using the analytic function

    I use under function to calculate second highest with empno and deptno salary.

    Is it possible to get the same result with another query without using Assembly only analytical functions condition.using and windows function is possible to get the desired output?

    SELECT e.empno,

    e.DEPTNO,

    tmp. SAL as second_higher_salary

    FROM emp e,.

    (SELECT Empno,

    DEPTNO,

    SAL,

    DENSE_RANK() (PARTITION BY deptno ORDER of sal) AS rnk

    WCP

    ) tmp

    WHERE tmp.deptno = e.deptno

    and tmp.rnk = 2

    EMPNO DEPTNO SAL

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

    7934 10 2450

    7782 10 2450

    7839 10 2450

    7876 20 1100

    7369 20 1100

    7902 20 1100

    7788 20 1100

    7566 20 1100

    7900 30 1250

    7844 30 1250

    7654 30 1250

    7521 30 1250

    7499 30 1250

    7698 30 1250

    7900 30 1250

    7844 30 1250

    7654 30 1250

    7521 30 1250

    7499 30 1250

    7698 30 1250

    Here's my solution:

    Select empno,

    DEPTNO,

    FIRST_VALUE (sal) (PARTITION BY deptno ORDER by sal desc)

    de)

    SELECT EmpNo,

    DEPTNO,

    Decode (DENSE_RANK () OVER (PARTITION BY deptno order by sal desc), 1,-sal, sal) sal

    WCP

    )

    /

    EMPNO DEPTNO FIRST_VALUE (SAL) OVER (PARTITIONBYDEPTNOORDERBYSALDESC)

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

      7782 10 2450
      7934 10 2450
      7839 10 2450
      7566 20 2975
      7876 20 2975
      7369 20 2975
      7788 20 2975
      7902 20 2975
      7499 30 1600
      7844 30 1600
      7654 30 1600
      7521 30 1600
      7900 30 1600
      7698 30 1600
  • Drive the analytic function


    Hello

    I have a doubt about this analytical function to lead,

    I have this table,

    create table test3 (no number, name varchar2 (30));


    Insert into TEST3 (NO, NAME) values (1, 'fen');
    Insert into TEST3 (NO, NAME) Values (3, 'DEN');
    Insert into TEST3 (NO, NAME) values (2, 'Sun');
    Insert into TEST3 (NO, NAME) values (2, 'sen');
    Insert into TEST3 (NO, NAME) values (1, 'end');
    COMMIT;

    I put like that with this request.


    Select lead don't (don't) over (partition by any order of name), name of test3.

    NO NAME

    1 fen
    end
    2 Sun
    Sen
    DEN

    But I need as below output, I am unable to get the third 'NO' that has a value, I get null for that, even if I partitioned
    by the 'NO '.

    NO NAME

    1 fen
    end
    2 Sun
    Sen
    3 DEN

    Please clear my doubt.

    Thanks in advance.

    Like this

    Select decode (NWR, 1, no, null) no

    name

    de)

    Select row_number() over (partition by any order by name) rno

    None

    name

    of test3

    )

  • Helps the analytic function

    Here is an example of the table data:
    ID    NAME             Start                  
    1     SARA             01-JAN-2006     
    2     SARA             03-FEB-2006     
    3     LAMBDA             21-MAR-2006     
    4     SARA             13-APR-2006     
    5     LAMBDA             01-JAN-2007     
    6     LAMBDA             01-SEP-2007     
    I would get this:
    Name        Start               Stop
    SARA        01-JAN-2006    20-MAR-2006
    LAMBDA      21-MAR-2006     12-APR-2006
    SARA        13-APR-2006     31-DEC-2006
    LAMBDA      01-JAN-2007      <null>
    I tried using partition and run the function but partition name combines all the lines of Sara and Lambda lines into a single group/partition that is not I am trying to get.
    Is there an analytic function or other means to achieve to combine date ranges only when the same person appeared conescutively?
    Thank you.

    This can be easily achieved using tabibitosan:

    First of all, you need to identify 'groups', that each name in the list belongs

    with sample_data as (select 1 id, 'SARA' name, to_date('01/01/2006', 'dd/mm/yyyy') start_date from dual union all
                         select 2 id, 'SARA' name, to_date('03/02/2006', 'dd/mm/yyyy') start_date from dual union all
                         select 3 id, 'LAMBDA' name, to_date('21/03/2006', 'dd/mm/yyyy') start_date from dual union all
                         select 4 id, 'SARA' name, to_date('13/04/2006', 'dd/mm/yyyy') start_date from dual union all
                         select 5 id, 'LAMBDA' name, to_date('01/01/2007', 'dd/mm/yyyy') start_date from dual union all
                         select 6 id, 'LAMBDA' name, to_date('01/09/2007', 'dd/mm/yyyy') start_date from dual)
    select id,
           name,
           start_date,
           lead(start_date, 1, to_date('31/12/9999', 'dd/mm/yyyy')) over (order by start_date) next_start_date,
           row_number() over (order by start_date)
             - row_number() over (partition by name order by start_date) grp
    from   sample_data;
    
            ID NAME   START_DATE NEXT_START_DATE        GRP
    ---------- ------ ---------- --------------- ----------
             1 SARA   01/01/2006 03/02/2006               0
             2 SARA   03/02/2006 21/03/2006               0
             3 LAMBDA 21/03/2006 13/04/2006               2
             4 SARA   13/04/2006 01/01/2007               1
             5 LAMBDA 01/01/2007 01/09/2007               3
             6 LAMBDA 01/09/2007 31/12/9999               3
    

    You can see the group number is generated by comparing the rownumber overall of all lines (in order) with the rownumber of the rowset by name (in the same order) - when there is a gap because another name appears between the two, the group number changes.

    Once you have identified the number of group for each set of rows, it is easy to find the min / max values in this group:

    
    with sample_data as (select 1 id, 'SARA' name, to_date('01/01/2006', 'dd/mm/yyyy') start_date from dual union all
                         select 2 id, 'SARA' name, to_date('03/02/2006', 'dd/mm/yyyy') start_date from dual union all
                         select 3 id, 'LAMBDA' name, to_date('21/03/2006', 'dd/mm/yyyy') start_date from dual union all
                         select 4 id, 'SARA' name, to_date('13/04/2006', 'dd/mm/yyyy') start_date from dual union all
                         select 5 id, 'LAMBDA' name, to_date('01/01/2007', 'dd/mm/yyyy') start_date from dual union all
                         select 6 id, 'LAMBDA' name, to_date('01/09/2007', 'dd/mm/yyyy') start_date from dual),
         tabibitosan as (select id,
                                name,
                                start_date,
                                lead(start_date, 1, to_date('31/12/9999', 'dd/mm/yyyy')) over (order by start_date) next_start_date,
                                row_number() over (order by start_date)
                                  - row_number() over (partition by name order by start_date) grp
                         from   sample_data)
    select name,
           min(start_date) start_date,
           max(next_start_date) stop_date
    from   tabibitosan
    group by name, grp
    order by start_date;
    
    NAME   START_DATE STOP_DATE
    ------ ---------- ----------
    SARA   01/01/2006 21/03/2006
    LAMBDA 21/03/2006 13/04/2006
    SARA   13/04/2006 01/01/2007
    LAMBDA 01/01/2007 31/12/9999
    

    If you want the date to appear as null max, you will need to use a cast or decode to change it - I'll leave that as an exercise for you to do! I'll also let you to find how to get the day before for the stop_date.

  • confusion with the analytical functions

    I created an example where I am right now with the help of analytical functions. However, I need the query below to return an additional column. I need to return the result from:-' factor_day_sales * max (sdus)'. Any ideas?

    If the first column is located and must have the following results

    777777, 5791, 10, 1.5, 15, 90, 135, 7050

    the 1350 is the result, I don't know how to do. (some how to multiply factored_day_sales max (sdus) 15 470 = 7050
    create table david_sales (
    pro_id number(38),
    salesidx number (38,6),
    tim_id number(38));
    
    truncate table david_sales
    
    create table david_compensations (
    pro_id number(38),
    tim_id number(38),
    factor number(38,6));
    
    
    insert into david_sales values
    (777777, 10.00, 5795);
    insert into david_sales values
    (777777,20.00, 5795);
    insert into david_sales values
    (777777, 30.00, 5794);
    insert into david_sales values
    (777777, 40.00, 5794);
    insert into david_sales values
    (777777, 100.00, 5793);
    insert into david_sales values
    (777777, 10.00, 5793);
    insert into david_sales values
    (777777,80.00, 5791);
    insert into david_sales values
    (777777, 10.00, 5791);
    
    insert into david_compensations values
    (777777, 5795, 1.5);
    insert into david_compensations values
    (777777, 5793, 2.0);
    insert into david_compensations values
    (777777, 5792, 1.0);
    insert into david_compensations values
    (777777, 5791, 1.5);
    
    
    
        SELECT  s.pro_id sales_pro
        ,       c.pro_id comp_pro
        ,       s.tim_id sales_tim
        ,       c.tim_id comp_tim
        ,       s.salesidx day_sales
        ,       NVL(c.factor, 1) factor
        ,       s.salesidx * NVL(c.factor, 1) factored_day_sales
        ,       sum(s.salesidx                   ) over (partition by s.pro_id order by s.pro_id, s.tim_id) Sdus
        ,       sum(s.salesidx * NVL(c.factor, 1)) over (partition by s.pro_id order by s.pro_id, s.tim_id) sumMjCj 
          FROM david_sales s
          ,    david_compensations c
          WHERE s.pro_id    = c.pro_id(+)
          AND s.tim_id      = c.tim_id(+)
          AND s.tim_id     BETWEEN 5791  AND 5795
    Thanks for looking

    Is that what you want?

        SELECT  s.pro_id sales_pro
        ,       c.pro_id comp_pro
        ,       s.tim_id sales_tim
        ,       c.tim_id comp_tim
        ,       s.salesidx day_sales
        ,       NVL(c.factor, 1) factor
        ,       s.salesidx * NVL(c.factor, 1) factored_day_sales
        ,       sum(s.salesidx                   ) over (partition by s.pro_id order by s.pro_id, s.tim_id) Sdus
        ,       sum(s.salesidx * NVL(c.factor, 1)) over (partition by s.pro_id order by s.pro_id, s.tim_id) sumMjCj
        , (s.salesidx * NVL(c.factor, 1) * sum(s.salesidx                   ) over (partition by s.pro_id order by s.pro_id, s.tim_id))
          FROM david_sales s
          ,    david_compensations c
          WHERE s.pro_id    = c.pro_id(+)
          AND s.tim_id      = c.tim_id(+)
          AND s.tim_id     BETWEEN 5791  AND 5795
    
    SALES_PRO              COMP_PRO               SALES_TIM              COMP_TIM               DAY_SALES              FACTOR                 FACTORED_DAY_SALES     SDUS                   SUMMJCJ                SUMMEDMULTI
    ---------------------- ---------------------- ---------------------- ---------------------- ---------------------- ---------------------- ---------------------- ---------------------- ---------------------- ----------------------
    777777                 777777                 5791                   5791                   80                     1.5                    120                    90                     135                    10800
    777777                 777777                 5791                   5791                   10                     1.5                    15                     90                     135                    1350  
    

    I get the 1350

    or did you mean:

        SELECT  s.pro_id sales_pro
        ,       c.pro_id comp_pro
        ,       s.tim_id sales_tim
        ,       c.tim_id comp_tim
        ,       s.salesidx day_sales
        ,       NVL(c.factor, 1) factor
        ,       s.salesidx * NVL(c.factor, 1) factored_day_sales
        ,       sum(s.salesidx                   ) over (partition by s.pro_id order by s.pro_id, s.tim_id) Sdus
        ,       sum(s.salesidx * NVL(c.factor, 1)) over (partition by s.pro_id order by s.pro_id, s.tim_id) sumMjCj
        ,  s.salesidx * NVL(c.factor, 1) * (sum(s.salesidx * NVL(c.factor, 1)) over (partition by s.pro_id order by s.pro_id, s.tim_id)) summedMulti
          FROM david_sales s
          ,    david_compensations c
          WHERE s.pro_id    = c.pro_id(+)
          AND s.tim_id      = c.tim_id(+)
          AND s.tim_id     BETWEEN 5791  AND 5795 
    
    SALES_PRO              COMP_PRO               SALES_TIM              COMP_TIM               DAY_SALES              FACTOR                 FACTORED_DAY_SALES     SDUS                   SUMMJCJ                SUMMEDMULTI
    777777                 777777                 5795                   5795                   10                     1.5                    15                     300                    470                    7050
    

    Note, in the second block, I changed it just to use sumMjCj instead of sDus which seems to correlate with what you wanted (15 * 470 = 7050) while sdus is 15 * 300 = 4500

    Published by: tanging on December 11, 2009 06:17

  • 2.1 EA Bug: AutoComplete group generates group by for the analytic function

    Hello

    When you use an analytic function in the sql text, sqldeveloper generates an automatic group by statement in the sql text.

    Kind regards
    Ingo

    Auto to produce group by can be disabled:

    In tools, preferences, Editor Code completion Insight you will find the option

    "Autogenerate GROUP BY clause"

    Concerning

    Ernst

  • Using the analytical function.

    Hello

    I have this scenario.
    with t as 
    (
    select 21009 item_id,9 primary_available,450 max_qty,100 bulk_available,12122 bulk_locator_id 
    from dual union all
    select 21009 item_id,9 primary_available,450 max_qty,2775 bulk_available,8704 bulk_locator_id 
    from dual union all
    select 21009 item_id,9 primary_available,450 max_qty,524 bulk_available,15614 bulk_locator_id 
    from dual union all
    select 21009 item_id,9 primary_available,450 max_qty,3300 bulk_available,15654 bulk_locator_id
    from dual)
    select  t.* from t;
    We have two locations for a given item_id. Primary and in bulk.

    I'm trying to get a select statement out of this point of view, where I will be restock the primary AMOUNT of sites in bulk, BUT the smaller bulk first. Once she gets up, I shouldn't take more product.

    There is an analytic function that would do this?

    That's the max I could come up with.
    with t as 
    (
    select 21009 item_id,9 primary_available,450 max_qty,100 bulk_available,12122 bulk_locator_id 
    from dual union all
    select 21009 item_id,9 primary_available,450 max_qty,2775 bulk_available,8704 bulk_locator_id 
    from dual union all
    select 21009 item_id,9 primary_available,450 max_qty,524 bulk_available,15614 bulk_locator_id 
    from dual union all
    select 21009 item_id,9 primary_available,450 max_qty,3300 bulk_available,15654 bulk_locator_id
    from dual)
    select  t.*, max_qty -
                   (primary_available + SUM(bulk_available)
                    over(PARTITION BY item_id ORDER BY bulk_available)) replen_this_much 
                    from t;
    So, in this scenario, I want to replen bulk_locator_id 100 ' 12122 'and ' 15614 bulk_locator_id 341'. That's all. ZERO of the other rentals (bulk_locator_id). If the question is not clear, please let me know.

    Published by: RPuttagunta on September 11, 2009 16:23

    Hello

    Thanks for posting the sample data.
    It would be useful that you also posted the output you want. Is this?

    .                                 BULK_         REPLEN_
    ITEM_ PRIMARY_   MAX_  BULK_      LOCATOR_        THIS_
    ID    AVAILABLE  QTY   AVAILABLE  ID               MUCH
    ----- ---------- ----- ---------- ---------- ----------
    21009 9          450   100        12122             100
    21009 9          450   524        15614             341
    21009 9          450   2775       8704                0
    21009 9          450   3300       15654               0
    

    If so, you can get to this:

    SELECT       t.*
    ,       GREATEST ( 0
                 , LEAST ( TO_NUMBER (bulk_available)
                         , TO_NUMBER (max_qty)
                        - ( TO_NUMBER (primary_available)
                          + NVL ( SUM (TO_NUMBER (bulk_available))
                                  OVER ( PARTITION BY  item_id
                                         ORDER BY      TO_NUMBER (bulk_available)
                                   ROWS BETWEEN  UNBOUNDED PRECEDING
                                     AND      1           PRECEDING
                                 )
                             , 0
                             )
                          )
                      )
                 ) AS replen_this_much
    FROM       t
    ORDER BY  item_id
    ,            TO_NUMBER (bulk_available)
    ;
    

    You should really store your numbers in NUMBER of columns.

    You essentially posted all what you need analytical functions. The problem was just wrapping this analytical function (or something very close to it) and LESS and more GRAND, so that the replen_this_much column is always between 0 and TO_NUMBER (bulk_available).

Maybe you are looking for