Case Statement in Analytic Function SUM(n) OVER(PARTITION BY x)

Hi Guys,
I have the following SQL that doesn't seem to consider the When clause I am using in the case staement inside the analytic function(SUM). Could somebody let me know why? and suggest the solution?
Select SUM(Case When (A.Flag = 'B' and B.Status != 'C') Then (NVL(A.Amount_Cr, 0) - (NVL(A.Amount_Dr,0))) Else 0 End) OVER (PARTITION BY A.Period_Year) Annual_amount
     , A.period_year
     , B.status
, A.Flag
from A, B, C
where A.period_year = 2006
and C.Account = '301010'
--and B.STATUS != 'C'
--and A.Flag = 'B'
and A.Col_x = B.Col_x
and A.Col_y = C.Col_y
When I use this SQL, I get
Annual_Amount Period_Year Status Flag
5721017.5 --------- 2006 ---------- C -------- B
5721017.5 --------- 2006 ---------- O -------- B
5721017.5 --------- 2006 ---------- NULL ----- A
And when I put the conditions in the where clause, I get
Annual_Amount Period_Year Status Flag
5721017.5 ---------- 2006 ---------- O -------- B

Here are some scripts,
create table testtable1 ( ColxID number(10), ColyID number(10) , Periodname varchar2(15), Flag varchar2(1), Periodyear number(15), debit number, credit number)
insert into testtable1 values(1, 1000, 'JAN-06', 'A', 2006, 7555523.71, 7647668)
insert into testtable1 values(2, 1001, 'FEB-06', 'B', 2006, 112710, 156047)
insert into testtable1 values(3, 1002, 'MAR-06', 'A', 2006, 200.57, 22376.43)
insert into testtable1 values(4, 1003, 'APR-06', 'B', 2006, 0, 53846)
insert into testtable1 values(5, 1004, 'MAY-06', 'A', 2006, 6349227.19, 6650278.03)
create table testtable2 ( ColxID number(10), Account number(10))
insert into testtable2 values(1, 300100)
insert into testtable2 values(2, 300200)
insert into testtable2 values(3, 300300)
insert into testtable2 values(4, 300400)
insert into testtable2 values(5, 300500)
create table apps.testtable3 ( ColyID number(10), Status varchar2(1))
insert into testtable3 values(1000, 'C')
insert into testtable3 values(1001, 'O')
insert into testtable3 values(1002, 'C')
My SQL:
select t1.periodyear
     , SUM(Case When (t1.Flag = 'B' and t3.Status != 'C') Then (NVL(t1.credit, 0) - (NVL(t1.debit,0))) Else 0 End) OVER (PARTITION BY t1.PeriodYear)
     Annual_amount
     , t1.flag
     , t3.status
     , t2.account
from testtable1 t1, testtable2 t2, testtable3 t3
where t1.colxid = t2.colxid
and t1.colyid = t3.colyid(+)
--and t1.Flag = 'B' and t3.Status != 'C'
Result:
PeriodYear ----- AnnualAmount ----- Flag ----- Status ----- Account
2006 ------------------ 43337 --------------- A ----------- C ---------- 300100
2006 ------------------ 43337 --------------- B ----------- O ---------- 300200
2006 ------------------ 43337 --------------- A ----------- C ---------- 300300
2006 ------------------ 43337 --------------- B ------------ ----------- 300400
2006 ------------------ 43337 --------------- A ------------ ----------- 300500
With condition "t1.Flag = 'B' and t3.Status != 'C'" in where clause instead of in Case statement, Result is (which is desired)
PeriodYear ----- AnnualAmount ----- Flag ----- Status ----- Account
2006 ------------------ 43337 --------------- B ----------- O ---------- 300200

Similar Messages

  • Analytical function SUM() OVER (PARTITION BY ) in Crosstab

    I am trying to resolve this from a very long time. I have an amount column that has to be grouped on Year, but all the other columns grouped by month. I am trying to achieve this using analytic function SUM(Case when (Condition1 and Condition2) then Sum(Amount) else 0 end) OVER ( PARTITION BY Account, Year), Where Account, Sub Account are the left axis columns. Now, column displays the values correctly, but at different rows. This is confusing.............
    For Ex: For Account 00001, there are 3 sub accounts 1000,2000,3000. For Sub account 3000, conditions 1 and 2 are satisfied, so it should display the Amount in the row corresponding to Sub account 3000, and 0 for remaining Sub Accounts. And the Total amount of all the sub accounts, which will be the same as amount for SubAccount 3000 should be displayed in the row corresponding to Account 00001.
    But I get blank rows for 1000 and 3000 Sub accounts and Amount displayed in 2000 Sub account, and blank for Account 00001 also.
    When I created the same workbook in Tabular form, the same amount is displayed for all the SubAccounts of a single Account.
    When I used this CASE statement in TOAD, I figured that this is due to the Analytic function. When I use a group by clause as shown below instead of partition by, I get the results I need.
    SELECT (Case when (Condition1 and Condition2) then Sum(Amount) else 0 end), Account, Sub Account FROM tables WHERE conditions GROUP BY Year, Account, Sub Account
    But I cannot use groupby for whole SQL of the workbook as I need the other columns with page item 'MONTH' not 'Year'.
    Could somebody please help me with this?

    Hi,
    In your tabular form do you get the correct total display against all you subaccounts and account? If this correct then you can use case to ensure that the total is displayed only for the single account.
    Once you have the correct totals working in a tabular form it is easier to re-produce what you want in a cross-tab.
    Rod West

  • Case statement and Decode function both are not working in Select cursor.

    I have tried both the Case statement and Decode function in Select cursor, but both the things are not working. On the other hand both the things work in just select statement.
    See the first column in select (PAR_FLAG), I need to have this evaluated along with other fields. Can you please suggest some thing to make this work. And also I would like to
    know the reason why decode is not working, I heard some where Case statement do not work with 8i.
    Author : Amit Juneja
    Date : 06/20/2011
    Description:
    Updates the Diamond MEMBER_MASTER table with the values from
    INC.MEM_NJ_HN_MEMBER_XREF table.
    declare
    rec_cnt number(12) := 0;
    commit_cnt number(4) := 0;
    cursor select_cur is
    Select DECODE(1,
    (Select 1
    from hsd_prov_contract R
    where R.seq_prov_id = PM.seq_prov_id
    and R.line_of_business = H.line_of_business
    and R.PCP_FLAG = 'Y'
    and R.participation_flag = 'P'
    and SYSDATE between R.EFFECTIVE_DATE AND
    NVL(R.TERM_DATE,
    TO_DATE('31-DEC-9999', 'DD-MON-YYYY'))),
    'Y',
    'N') PAR_FLAG,
    H.SEQ_ELIG_HIST,
    H.SEQ_MEMB_ID,
    H.SEQ_SUBS_ID,
    H.SUBSCRIBER_ID,
    H.PERSON_NUMBER,
    H.EFFECTIVE_DATE,
    H.TERM_DATE,
    H.TERM_REASON,
    H.RELATIONSHIP_CODE,
    H.SEQ_GROUP_ID,
    H.PLAN_CODE,
    H.LINE_OF_BUSINESS,
    H.RIDER_CODE_1,
    H.RIDER_CODE_2,
    H.RIDER_CODE_3,
    H.RIDER_CODE_4,
    H.RIDER_CODE_5,
    H.RIDER_CODE_6,
    H.RIDER_CODE_7,
    H.RIDER_CODE_8,
    H.MEDICARE_STATUS_FLG,
    H.OTHER_STATUS_FLAG,
    H.HIRE_DATE,
    H.ELIG_STATUS,
    H.PREM_OVERRIDE_STEP,
    H.PREM_OVERRIDE_AMT,
    H.PREM_OVERRIDE_CODE,
    H.SEQ_PROV_ID,
    H.IPA_ID,
    H.PANEL_ID,
    H.SEQ_PROV_2_ID,
    H.SECURITY_CODE,
    H.INSERT_DATETIME,
    H.INSERT_USER,
    H.INSERT_PROCESS,
    H.UPDATE_DATETIME,
    H.UPDATE_USER,
    H.UPDATE_PROCESS,
    H.USER_DEFINED_1,
    H.SALARY,
    H.PEC_END_DATE,
    H.REASON_CODE,
    H.PEC_WAIVED,
    H.BILL_EFFECTIVE_FROM_DATE,
    H.BILLED_THRU_DATE,
    H.PAID_THRU_DATE,
    H.SUBSC_DEPT,
    H.SUBSC_LOCATION,
    H.USE_EFT_FLG,
    H.BENEFIT_START_DATE,
    H.SEQ_ENROLLMENT_RULE,
    H.MCARE_RISK_ACCRETION_DATE,
    H.MCARE_RISK_DELETION_DATE,
    H.MCARE_RISK_REFUSED_DATE,
    H.COMMENTS,
    H.USER_DEFINED_2,
    H.USER_DEFINED_3,
    H.RATE_TYPE,
    H.PCPAA_OCCURRED,
    H.PRIVACY_ON,
    H.PCP_CHANGE_REASON,
    H.SITE_CODE,
    H.SEQ_SITE_ADDRESS_ID,
    PM.seq_prov_id rendered_prov
    from hsd_member_elig_history H,
    INC.PCP_REASSIGN_RPRT_DATA P,
    hsd_prov_master PM
    where P.subscriber_id = H.subscriber_id
    and P.rendered_pcp = PM.provider_ID
    and H.elig_status = 'Y'
    and (H.term_date is NULL or H.term_date >= last_day(sysdate))
    order by H.Seq_memb_id;
    begin
    for C in select_cur loop
    rec_cnt := rec_cnt + 1;
    update hsd_member_elig_history
    set term_date = TRUNC(SYSDATE - 1),
    term_reason = 'PCPTR',
    update_datetime = SYSDATE,
    update_user = USER,
    update_process = 'TD33615'
    where seq_elig_hist = C.seq_elig_hist
    and seq_memb_id = C.seq_memb_id;
    INSERT INTO HSD_MEMBER_ELIG_HISTORY
    (SEQ_ELIG_HIST,
    SEQ_MEMB_ID,
    SEQ_SUBS_ID,
    SUBSCRIBER_ID,
    PERSON_NUMBER,
    EFFECTIVE_DATE,
    TERM_DATE,
    TERM_REASON,
    RELATIONSHIP_CODE,
    SEQ_GROUP_ID,
    PLAN_CODE,
    LINE_OF_BUSINESS,
    RIDER_CODE_1,
    RIDER_CODE_2,
    RIDER_CODE_3,
    RIDER_CODE_4,
    RIDER_CODE_5,
    RIDER_CODE_6,
    RIDER_CODE_7,
    RIDER_CODE_8,
    MEDICARE_STATUS_FLG,
    OTHER_STATUS_FLAG,
    HIRE_DATE,
    ELIG_STATUS,
    PREM_OVERRIDE_STEP,
    PREM_OVERRIDE_AMT,
    PREM_OVERRIDE_CODE,
    SEQ_PROV_ID,
    IPA_ID,
    PANEL_ID,
    SEQ_PROV_2_ID,
    SECURITY_CODE,
    INSERT_DATETIME,
    INSERT_USER,
    INSERT_PROCESS,
    UPDATE_DATETIME,
    UPDATE_USER,
    UPDATE_PROCESS,
    USER_DEFINED_1,
    SALARY,
    PEC_END_DATE,
    REASON_CODE,
    PEC_WAIVED,
    BILL_EFFECTIVE_FROM_DATE,
    BILLED_THRU_DATE,
    PAID_THRU_DATE,
    SUBSC_DEPT,
    SUBSC_LOCATION,
    USE_EFT_FLG,
    BENEFIT_START_DATE,
    SEQ_ENROLLMENT_RULE,
    MCARE_RISK_ACCRETION_DATE,
    MCARE_RISK_DELETION_DATE,
    MCARE_RISK_REFUSED_DATE,
    COMMENTS,
    USER_DEFINED_2,
    USER_DEFINED_3,
    RATE_TYPE,
    PCPAA_OCCURRED,
    PRIVACY_ON,
    PCP_CHANGE_REASON,
    SITE_CODE,
    SEQ_SITE_ADDRESS_ID)
    values
    (hsd_seq_elig_hist.nextval,
    C.SEQ_MEMB_ID,
    C.SEQ_SUBS_ID,
    C.SUBSCRIBER_ID,
    C.PERSON_NUMBER,
    trunc(SYSDATE),
    C.TERM_DATE,
    C.TERM_REASON,
    C.RELATIONSHIP_CODE,
    C.SEQ_GROUP_ID,
    C.PLAN_CODE,
    C.LINE_OF_BUSINESS,
    C.RIDER_CODE_1,
    C.RIDER_CODE_2,
    C.RIDER_CODE_3,
    C.RIDER_CODE_4,
    C.RIDER_CODE_5,
    C.RIDER_CODE_6,
    C.RIDER_CODE_7,
    C.RIDER_CODE_8,
    C.MEDICARE_STATUS_FLG,
    C.OTHER_STATUS_FLAG,
    C.HIRE_DATE,
    C.ELIG_STATUS,
    C.PREM_OVERRIDE_STEP,
    C.PREM_OVERRIDE_AMT,
    C.PREM_OVERRIDE_CODE,
    C.SEQ_PROV_ID,
    C.IPA_ID,
    C.PANEL_ID,
    C.SEQ_PROV_2_ID,
    C.SECURITY_CODE,
    SYSDATE,
    USER,
    'TD33615',
    SYSDATE,
    USER,
    'TD33615',
    C.USER_DEFINED_1,
    C.SALARY,
    C.PEC_END_DATE,
    C.REASON_CODE,
    C.PEC_WAIVED,
    C.BILL_EFFECTIVE_FROM_DATE,
    C.BILLED_THRU_DATE,
    C.PAID_THRU_DATE,
    C.SUBSC_DEPT,
    C.SUBSC_LOCATION,
    C.USE_EFT_FLG,
    C.BENEFIT_START_DATE,
    C.SEQ_ENROLLMENT_RULE,
    C.MCARE_RISK_ACCRETION_DATE,
    C.MCARE_RISK_DELETION_DATE,
    C.MCARE_RISK_REFUSED_DATE,
    C.COMMENTS,
    C.USER_DEFINED_2,
    C.USER_DEFINED_3,
    C.RATE_TYPE,
    C.PCPAA_OCCURRED,
    C.PRIVACY_ON,
    C.PCP_CHANGE_REASON,
    C.SITE_CODE,
    C.SEQ_SITE_ADDRESS_ID);
    commit_cnt := commit_cnt + 1;
    if (commit_cnt = 1000) then
    dbms_output.put_line('Committed updates for 1000 records.');
    commit;
    commit_cnt := 0;
    end if;
    end loop;
    commit;
    dbms_output.put_line('Total number of MEMBER_ELIG_HISTROY records inserted : ' ||
    rec_cnt);
    exception
    when others then
    raise_application_error(-20001,
    'An error was encountered - ' || sqlcode ||
    ' -error- ' || sqlerrm);
    end;

    user10305724 wrote:
    I have tried both the Case statement and Decode function in Select cursor, but both the things are not working. Please define what you mean by not working even if your computer screen is near the internet we can't see it.
    You should also look at the FAQ about how to ask a question
    SQL and PL/SQL FAQ
    Particularly *9) Formatting with {noformat}{noformat} Tags* and posting your version.
    know the reason why decode is not working, I heard some where Case statement do not work with 8i.
    Does this mean you are using 8i? Then scalar sub queries - selects within the select list, are not supported, along with CASE in PL/SQL.
    Select DECODE(1,
    * (Select 1
    from hsd_prov_contract R
    where R.seq_prov_id = PM.seq_prov_id
    and R.line_of_business = H.line_of_business
    and R.PCP_FLAG = 'Y'
    and R.participation_flag = 'P'
    and SYSDATE between R.EFFECTIVE_DATE AND
    NVL(R.TERM_DATE,
    TO_DATE('31-DEC-9999', 'DD-MON-YYYY')))*,
    'Y',
    'N') PAR_FLAG,
    >
    exception
    when others then
    raise_application_error(-20001,
    'An error was encountered - ' || sqlcode ||
    ' -error- ' || sqlerrm);
    http://tkyte.blogspot.com/2008/01/why-do-people-do-this.html                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

  • Analytical function sum() ...for Till-date reporting

    Hi,
    I need help in forming an SQL with analytical function.
    Here is my scenario:
    create table a (name varchar2(10), qty_sold number,on_date date);
    insert into a values ('abc',10,'10-JAN-2007 00:01:00');
    insert into a values ('abc',01,'10-JUL-2007 00:01:00');
    insert into a values ('abc',05,'10-JUL-2007 08:11:00');
    insert into a values ('abc',17,'10-JUL-2007 09:11:00');
    insert into a values ('def',10,'10-JAN-2006 08:01:00');
    insert into a values ('def',01,'10-JUN-2006 10:01:00');
    insert into a values ('def',05,'10-JUL-2006 08:10:00');
    insert into a values ('pqr',17,'10-JUL-2006 09:11:00');
    Now I want to have a sql which displays the following:
    NAME--TOTAL_QTY_SOLD_IN_LAST_10_DAYS, TOTAL_QTY_SOLD_IN_LAST_20_DAYS...etc
    I know we can do it using sum(qty_sold) over (order on_date range interval '10' days and preceding) .... but I get too many rows for each "NAME" ....for each of the date in the database table a ... I want just one row for each "Name"...and sum() should be till SYSDATE ....
    Any help is highly appreciated.
    Thanks.

    SQL> select name
      2       , sum(case when sysdate - on_date <= 10 then qty_sold end) total_qty_last_10_days
      3       , sum(case when sysdate - on_date <= 100 then qty_sold end) total_qty_last_100_days
      4       , sum(case when sysdate - on_date <= 500 then qty_sold end) total_qty_last_500_days
      5    from a
      6   group by name
      7  /
    NAME          TOTAL_QTY_LAST_10_DAYS   TOTAL_QTY_LAST_100_DAYS   TOTAL_QTY_LAST_500_DAYS
    abc                                                         23                        33
    def                                                                                    6
    pqr                                                                                   17
    3 rijen zijn geselecteerd.Regards,
    Rob.

  • CASE Statement error in function -- Please help!

    Hi All,
    I created a function in my report.
    It has a SQL query similar to the one below. The query works fine in SQL plus.
    It has a CASE statement. I am getting error at line4 at the select statement. Error is: "Encountered symbol 'SELECT'....."
    Can we use CASE statements like this in reports that use SELECT statements for RETURN EXPRESSIONS. Do we have to do any special?
    Can someone help me out of this trouble?
    THanks in advance.
    SELECT PARENT_id,
         CASE WHEN EXISTS (SELECT PARENT_id FROM CHILD CH1 WHERE CH1.PARENT_id = PARENT.PARENT_id AND UPPER(CH1.description) LIKE '%ABC%') THEN
              (SELECT CH2.MOD_id FROM CHILD CH2 WHERE CH2.PARENT_id = PARENT.PARENT_id AND UPPER(CH2.description) LIKE '%ABC%')
         ELSE
              (SELECT MOD_id FROM
              (SELECT MOD_id,PARENT_id FROM CHILD CH3 ORDER BY started) MOD2 WHERE MOD2.PARENT_id = PARENT.PARENT_id AND ROWNUM = 1
         END
    ) MOD_ID
    FROM PARENT;

    take out the parentheses after the PARENT_ID and see
    like below
    SELECT parent_id,
           CASE
              WHEN EXISTS (
                     SELECT parent_id
                       FROM CHILD ch1
                      WHERE ch1.parent_id = PARENT.parent_id
                        AND UPPER (ch1.description) LIKE '%ABC%')
                 THEN (SELECT ch2.mod_id
                         FROM CHILD ch2
                        WHERE ch2.parent_id = PARENT.parent_id
                          AND UPPER (ch2.description) LIKE '%ABC%')
              ELSE (SELECT mod_id
                      FROM (SELECT   mod_id, parent_id
                                FROM CHILD ch3
                            ORDER BY started) mod2
                     WHERE mod2.parent_id = PARENT.parent_id AND ROWNUM = 1)
           END AS mod_id
      FROM PARENT;       

  • Turn a case statement into a function

    I have a case statement (from an earlier post - thank you) that works. I was wondering if it could be edited and change into a function instead. I think it would be cleaner. The variable is set in the Form Properties (pCounterA).
    switch (pCounterA.value)
        case "1":
        profileA__1image.rawValue = profileA_1image.value.image.value;
        pCounterA.value = "2";
        break;
        case "2":
        profileA__1image.rawValue = profileA_2image.value.image.value;
        pCounterA.value = "3";
        break;
        case "3":
        profileA__1image.rawValue = profileA_3image.value.image.value;
        pCounterA.value = "4";
        break;
        case "4":
        profileA__1image.rawValue = profileA_4image.value.image.value;
        pCounterA.value = "5";
        break;
        case "5":
        profileA__1image.rawValue = profileA_5image.value.image.value;
        pCounterA.value = "1"; // loops back to the first image
        break;

    Hi,
    If you insert a script object by right clicking on the root container (often "form1"). It will appear unnamed in the root / variables in the hierarchy.
    First of all you should name the script object, staying away from reserved names, eg "this". Say "myScripts"
    Script objects can only contain Javascript, so you would need to convert FormCalc scripts (not an issue in your case).
    When you go into the script object, you start off a function with "function" followed by its name and inputs in brackets. The extent of the function is given by curly brackets:
    function changeImage(vCounter)
         switch (vCounter)
             case "1":
             profileA__1image.rawValue = profileA_1image.value.image.value;
             pCounterA.value = "2";
             break;
         } // close switch statement
    } // close function
    Back in the form you can call the function by referencing the name of the script object and the name of the function.
    myScripts.changeImage(pCounterA.value);
    A couple of things to note:
    The input in the script can refer to an objects value or a global variable, but in the function you can assign it s different name. So above the input pCounterA.value is EQUAL to vCounter in the function;
    You can have several inputs in the call for the function separated by commas;
    Don't have the same name for the script object AND the function
    Hope that helps,
    Niall

  • Regarding case statement and decode function

    Hi Experts,
    I have question.....regarding case statement and decode statement....
    Can you please explain me that which one will be efficient,to place in insert statement...
    insert statement(
    (case when ........then
                         case when ....then
                         else
                         end)
      else
    end)
    or
    insert statement(
    case when.....then
    decode(....)
    else
    end)
    Can you people explain me which one is more efficient method?
    Thanks in advance.......

    The are major differences to talk about in case of CASE vs DECODE, but performance wise both are pretty much the same.
    Have a look at Tom's thread
    Ask Tom &amp;quot;better performance - case or decode&amp;quot;
    I would suggest to use CASE whenever possible. Don't worry about the performance part.

  • CASE statement (or similar functionality) in interactive report?

    Hello,
    I've written a report based on an anonymous block of PL/SQL that allows me to show a different colored icon on the report based on the value of one of the columns - show green if value is less than x, show yellow if value is between x and y, and show red if value is greater than y.
    Here is the code block:
    for i in (select proj_id, proj_name,
    CASE
    WHEN proj_cost < 10 THEN '<img src="#APP_IMAGES#green-circle.jpg">'
    WHEN proj_cost > 10 and proj_cost <15 THEN '<img src="#APP_IMAGES#yellow-circle.jpg">'
    WHEN proj_cost > 15 THEN '<img src="#APP_IMAGES#red-circle.jpg">'
    ELSE NULL
    END proj_cost
    from project)
    loop
    htp.p('<p>' || i.proj_id || ', ' || i.proj_name || i.proj_cost ||'</p>');
    end loop;
    Can I do something similar with an interactive report? I want the flexibility of the interactive report but the ability to still include this customer requirement in the report.
    Thanks!
    -melissa

    Hi,
    You can use your select as interactive report region source
    select proj_id,
    proj_name,
    CASE
    WHEN proj_cost < 10 THEN '<img src="#APP_IMAGES#green-circle.jpg">'
    WHEN proj_cost > 10 and proj_cost <15 THEN '<img src="#APP_IMAGES#yellow-circle.jpg">'
    WHEN proj_cost > 15 THEN '<img src="#APP_IMAGES#red-circle.jpg">'
    ELSE NULL
    END proj_cost
    from projecIt should work fine
    Just make sure that column where is image type is "Standard report column".
    If it is "Display as text" it will not show HTML
    Br,JAri
    Edited by: jarola on Mar 16, 2010 4:18 PM
    for substitution sting APP_IMAGES you need probably use &APP_IMAGES. instead of #APP_IMAGES#
    Other vise it should be fine

  • Analytic Function partition by

    I am almost where I want to be with this but lat steps are always killer.
    I have a query that returns a list of ETL mappings/packages. The Source package (first one) can be identified with an ‘@’ in the string and all packages related to that mapping will follow (sorted by time).
    I am stuck trying to propogate the name of this Source Mapping to all the packages below it until a change to the next Source.
    Here’s an example of what I want
    Source               Grp          Name
    “sales@source”     1          Sales
    salesa               0          Sales
    slsb               0          Sales
    “orders@hth”     1          Orders
    ordersa          0          Orders
    ordb               0          Orders
    ordersc          0          Orders
    “inventory@...     “ 1          Inventory
    So my sql is basically showing how I am using Lag but it’s coming up short since I have to pre-determine the offset, which won’t work in this case.
    SELECT source,
    CASE WHEN source LIKE '%@%' THEN 1 ELSE 0 END GRP,
    CASE WHEN
    (CASE WHEN source LIKE '%@%' THEN 1 ELSE 0 END) =1
    THEN substr (map_primary_source, 2, (instr(map_primary_source, '@')-3))
    ELSE
    lag(substr (map_primary_source, 2, (instr(map_primary_source, '@')-3)), 1,0)
    over (ORDER BY creation_date)
    END NAME,
    creation_date
    FROM table
    WHERE creation_date > SYSDATE -1
    ORDER BY creation_date
    I’ve been trying different flavors of analytical functions (first value, over partition by, etc) but am coming up short.
    By the way I am on 8.x

    Yes, it works for variable numbers of rows.
    Here is how to make your grp column and the solution all in one:
    CREATE TABLE test AS (
        SELECT 'THIS@DESC' description, 'SALES' group_name FROM DUAL
        UNION
        SELECT 'THISa' description, 'SALES' group_name FROM DUAL
        UNION
        SELECT 'THISb' description, 'SALES' group_name FROM DUAL
        UNION
        SELECT 'THISc' description, 'SALES' group_name FROM DUAL
        UNION
        SELECT 'THISd' description, 'SALES' group_name FROM DUAL
        UNION
        SELECT 'THISe' description, 'SALES' group_name FROM DUAL
        UNION
        SELECT 'DEMO@DESC' description, 'DEMO' group_name FROM DUAL
        UNION
        SELECT 'DEMOa' description, 'DEMO' group_name FROM DUAL
        UNION
        SELECT 'DEMOb' description, 'DEMO' group_name FROM DUAL
        UNION
        SELECT 'THAT@DESC' description, 'THAT' group_name FROM DUAL
        UNION
        SELECT 'THATa' description, 'THAT' group_name FROM DUAL
        UNION
        SELECT 'THATb' description, 'THAT' group_name FROM DUAL
        UNION
        SELECT 'THATc' description, 'THAT' group_name FROM DUAL
        UNION
        SELECT 'WHERE@DESC' description, 'WHERE' group_name FROM DUAL
        UNION
        SELECT 'WHEREa' description, 'WHERE' group_name FROM DUAL
    Table created.
    SELECT * FROM test
    DESCRIPTIO GROUP
    DEMO@DESC  DEMO
    DEMOa      DEMO
    DEMOb      DEMO
    THAT@DESC  THAT
    THATa      THAT
    THATb      THAT
    THATc      THAT
    THIS@DESC  SALES
    THISa      SALES
    THISb      SALES
    THISc      SALES
    THISd      SALES
    THISe      SALES
    WHERE@DESC WHERE
    WHEREa     WHERE
    SELECT
       FIRST_VALUE(description) OVER (PARTITION BY group_name ORDER BY group_num DESC) description,
       group_name
    FROM
        SELECT
           description,
           CASE
              WHEN
                 INSTR(description, '@') > 0
              THEN
                 1
              ELSE
                 0
           END group_num,
           group_name
        FROM
           test
    DESCRIPTIO GROUP
    DEMO@DESC  DEMO
    DEMO@DESC  DEMO
    DEMO@DESC  DEMO
    THIS@DESC  SALES
    THIS@DESC  SALES
    THIS@DESC  SALES
    THIS@DESC  SALES
    THIS@DESC  SALES
    THIS@DESC  SALES
    THAT@DESC  THAT
    THAT@DESC  THAT
    THAT@DESC  THAT
    THAT@DESC  THAT
    WHERE@DESC WHERE
    WHERE@DESC WHERE

  • SUM OVER PARTITION BY condition?

    I have a piece of SQL similar to:
    SELECT person,
    amount,
    type,
    SUM(amount) OVER (PARTITION BY person) sum_amount_person
    FROM table_a
    What I would like to be able to do is use a conditional PARTITION BY clause, so rather than partition and summing for each person I would like to be able to sum for each person where type = 'ABC'
    I would expect the syntax to be something like
    SELECT person,
    amount,
    type,
    SUM(amount) OVER (PARTITION BY person WHERE type = 'ABC') sum_amount_person
    FROM table_a
    Is this possible? Or am I missing a much simpler solution?
    Richard

    The proposed query does not compile on my Windows Oracle 9.2.0.5 or 10.1. This could be generated by the ambiguty introduced by DECODE in the evaluation of query (does it filter the selected rows, or the rows summarized for each selected row, or both?).
    I propose two alternatives. The requirements are not specific enough to allow me to choose between them.
    SQL> SELECT * FROM table_a ORDER BY 1, 3;
    PERSON         AMOUNT TYP
    john               12 abc
    john                8 abc
    john               20 def
    mike               15 abc
    mike               30 ghi
    steve              30 abc
    6 rows selected.
    SQL> SELECT person,
      2  amount,
      3  type,
      4  SUM(decode(type, 'ABC',amount, to_number(NULL)) OVER (PARTITION BY person) sum_amount_person
      5  FROM table_a;
    SUM(decode(type, 'ABC',amount, to_number(NULL)) OVER (PARTITION BY person) sum_amount_person
    ERROR at line 4:
    ORA-30483: window  functions are not allowed here
    SQL> SELECT person,
      2  amount,
      3  type,
      4  CASE type WHEN 'abc' THEN SUM(amount) OVER (PARTITION BY person) END sum_amount_person
      5  FROM table_a;
    PERSON         AMOUNT TYP SUM_AMOUNT_PERSON
    john               12 abc                40
    john               20 def
    john                8 abc                40
    mike               15 abc                45
    mike               30 ghi
    steve              30 abc                30
    6 rows selected.
    SQL> SELECT person,
      2  amount,
      3  type,
      4  CASE type WHEN 'abc' THEN SUM(amount) OVER (PARTITION BY person, type) END sum_amount_person
      5  FROM table_a;
    PERSON         AMOUNT TYP SUM_AMOUNT_PERSON
    john               12 abc                20
    john                8 abc                20
    john               20 def
    mike               15 abc                15
    mike               30 ghi
    steve              30 abc                30
    6 rows selected.

  • Problem with SUM () analytic function

    Dear all,
    Please have a look at my problem.
    SELECT CURR, DT, AMT, RATE,
    SUM(AMT) OVER (PARTITION BY CURR ORDER BY DT) SUMOVER,
    sum( amt * rate) over (PARTITION BY CURR ORDER BY DT) / SUM(AMT) OVER (PARTITION BY CURR ORDER BY DT) avgrt
    FROM
    select 'CHF' CURR, ADD_MONTHS(TO_DATE('01-DEC-07'), LEVEL -1) DT, 100 * LEVEL AMT, 1 +  ( 5* LEVEL/100) RATE
    FROM DUAL CONNECT BY LEVEL < 10
    SQL> /
    CUR DT               AMT       RATE    SUMOVER      AVGRT
    CHF 01-DEC-07        100       1.05        100       1.05
    CHF 01-JAN-08        200        1.1        300 1.08333333
    CHF 01-FEB-08        300       1.15        600 1.11666667
    CHF 01-MAR-08        400        1.2       1000       1.15
    CHF 01-APR-08        500       1.25       1500 1.18333333
    CHF 01-MAY-08        600        1.3       2100 1.21666667
    CHF 01-JUN-08        700       1.35       2800       1.25
    CHF 01-JUL-08        800        1.4       3600 1.28333333
    CHF 01-AUG-08        900       1.45       4500 1.31666667
    Table Revaluation
    select 'CHF' CURR1, '31-DEC-07' DT , 1.08 RATE FROM DUAL UNION ALL
    select 'CHF' CURR1, '31-MAR-08' DT , 1.22 RATE FROM DUAL UNION ALL
    select 'CHF' CURR1, '30-JUN-08' DT , 1.38 RATE FROM DUAL
    CUR DT              RATE
    CHF 31-DEC-07       1.08
    CHF 31-MAR-08       1.22
    CHF 30-JUN-08       1.38.
    Problem is with the calculation of average rate.
    I want to consider the data in the revaluation table to be used in the calculation of
    average rate.
    So average rate for Jan-08 will be
    (100 * 1.08(dec revaluation rate) + 200 * 1.1 ) / (300) = 1.093333333
    for Feb-08
    (100 * 1.08(dec revaluation rate) + 200 * 1.1 + 300 * 1.15) / (600) = 1.121666667
    for mar-08
    (100 * 1.08(dec revaluation rate) + 200 * 1.1 + 300 * 1.15 + 400 * 1.2) / (1000) = 1.153
    for Apr-08
    (1000 * 1.22(Apr revaluation rate) + 500 * 1.25) /1500 = 1.23
    for May-08
    (1000 * 1.22(Apr revaluation rate) + 500 * 1.25 + 600 * 1.30 ) /2100 = 1.25
    and so on..
    Kindly advice

    Hi,
    The main thing in this problem is that for every dt you want to compute the cumulative total from previous rows using the formula
    SUM (amt * rate)
    But rate can be either the rate from the revaluation table or the rate from the main table. For evaluating prior dates, you wnat to use the most recent rate.
    I'm not sure if you can do this using analytic functions. Like Damorgan said, you should use a self-join.
    The query below gives you the results you requested:
    WITH
    revaluation     AS
         SELECT 'CHF' curr1, TO_DATE ('31-DEC-07', 'DD-MON-RR') dt, 1.08 rate     FROM dual     UNION ALL
         SELECT 'CHF' curr1, TO_DATE ('31-MAR-08', 'DD-MON-RR') dt, 1.22 rate     FROM dual     UNION ALL
         SELECT 'CHF' curr1, TO_DATE ('30-JUN-08', 'DD-MON-RR') dt, 1.38 rate     FROM dual
    original_data     AS
         select     'CHF'                              curr
         ,     ADD_MONTHS(TO_DATE('01-DEC-07'), LEVEL -1)     dt
         ,     100 * LEVEL                         amt
         ,     1 + ( 5* LEVEL/100)                    rate
         FROM     dual
         CONNECT BY     LEVEL < 10
    two_rates     AS
         SELECT     od.*
              SELECT     MAX (dt)
              FROM     revaluation
              WHERE     curr1     = od.curr
              AND     dt     <= od.dt
              )          AS r_dt
              SELECT     AVG (rate) KEEP (DENSE_RANK LAST ORDER BY dt)
              FROM     revaluation
              WHERE     curr1     = od.curr
              AND     dt     <= od.dt
              )          AS r_rate
         FROM     original_data     od
    SELECT     c.curr
    ,     c.dt
    ,     c.amt
    ,     c.rate
    ,     SUM (p.amt)          AS sumover
    ,     SUM     ( p.amt
              * CASE
                   WHEN     p.dt <= c.r_dt
                   THEN     c.r_rate
                   ELSE     p.rate
                END
         / SUM (p.amt)          AS avgrt
    FROM     two_rates     c
    JOIN     original_data     p     ON     c.curr     = p.curr
                        AND     c.dt     >= p.dt
    GROUP BY     c.curr,     c.dt,     c.amt,     c.rate
    ORDER BY     c.curr,     c.dt
    ;

  • SUM analytical function

    Hi,
    I am using the SUM analytical function to accumulate some data from one record to the other record (data per month):
    TPS_MOI_CODE     PRD_PRD_CODE     PDV_PDV_CODE     RTTCAVCANV
    200510     01     9302     -8050
    200511     01     9302     -15500
    200512     01     9302     -16150
    200601     01     9302     -16150
    200602     01     9302     -16150
    200603     01     9302     -16150
    The result is correct. However, I also want to restart the sum from January, i.e every months contain the sum of all the previous month, and it must restart in January.
    How do I do that ?
    Thanks in advance for your answers.

    You should extract a year and use it as the partition in over() clause, for example:
    SQL> select * from t;
         DATE#        QTY
        200510          1
        200511          2
        200512          3
        200601          4
        200602          5
        200603          6
    6 rows selected.
    SQL> desc t;
    Name                                      Null?    Type
    DATE#                                              NUMBER
    QTY                                                NUMBER
    SQL> select date#, sum(qty) over(partition by substr(date#,1,4) order by date#) cum_sum
      2  from t;
         DATE#    CUM_SUM
        200510          1
        200511          3
        200512          6
        200601          4
        200602          9
        200603         15
    6 rows selected.Rgds.

  • How to use sum analytic function in adf

    Hi
    jdev 11.1.1.5
    oracle 11g r2
    I want to use analytic function (sum,count,avg and ...) .
    I see [url http://andrejusb.blogspot.co.uk/2013/02/oracle-analytic-functions-for-total-and.html]Oracle Analytic Functions for Total and Average Calculation in ADF BC
    and use it in my vo and jsf page,my vo have too much record and I want to have sum in table footer on demand (because of performance) and if user do not want to see the sum in footer of table it do not calculate sum,
    what is your idea?

    Before I read that blog I use another vo for sum but after that blog decide to use analytic fuction becuase we have some page that have to many dvt graph and table and know we use seperate vo for them and it has not good performance and too many query must run in database ,I want to have 1 vo with some analytic function for graph and tables

  • Analytic function to retrieve a value one year ago

    Hello,
    I'm trying to find an analytic function to get a value on another row by looking on a date with Oracle 11gR2.
    I have a table with a date_id (truncated date), a flag and a measure. For each date, I have at least one row (sometimes 2), so it is gapless.
    I would like to find analytic functions to show for each date :
    sum of the measure for that date
    sum of the measure one week ago
    sum of the measure one year ago
    As it is gapless I managed to do it the week doing a group by date in a subquery and using a LAG with offset set to 7 on top of it (see below).
    However I'm struggling on how to do that for the data one year ago as we might have leap years. I cannot simply set the offset to 365.
    Is it possible to do it with a RANGE BETWEEN window clause? I can't manage to have it working with dates.
    Week :LAG with offset 7
    SQL Fiddle
    or
    create table daily_counts
      date_id date,
      internal_flag number,
      measure1 number
    insert into daily_counts values ('01-Jan-2013', 0, 8014);
    insert into daily_counts values ('01-Jan-2013', 1, 2);
    insert into daily_counts values ('02-Jan-2013', 0, 1300);
    insert into daily_counts values ('02-Jan-2013', 1, 37);
    insert into daily_counts values ('03-Jan-2013', 0, 19);
    insert into daily_counts values ('03-Jan-2013', 1, 14);
    insert into daily_counts values ('04-Jan-2013', 0, 3);
    insert into daily_counts values ('05-Jan-2013', 0, 0);
    insert into daily_counts values ('05-Jan-2013', 1, 1);
    insert into daily_counts values ('06-Jan-2013', 0, 0);
    insert into daily_counts values ('07-Jan-2013', 1, 3);
    insert into daily_counts values ('08-Jan-2013', 0, 33);
    insert into daily_counts values ('08-Jan-2013', 1, 9);
    commit;
    select
        date_id,
        total1,
        LAG(total1, 7) OVER(ORDER BY date_id) total_one_week_ago
      from
          select
            date_id,
            SUM(measure1) total1
          from daily_counts
          group by date_id
    order by 1;
    Year : no idea?
    I can't give a gapless example, would be too long but if there is a solution with the date directly :
    SQL Fiddle
    or add this to the schema above :
    insert into daily_counts values ('07-Jan-2012', 0, 11);
    insert into daily_counts values ('07-Jan-2012', 1, 1);
    insert into daily_counts values ('08-Jan-2012', 1, 4);
    Thank you for your help.
    Floyd

    Hi,
    Sorry, I;m not sure I understand the problem.
    If you are certain that there is at least 1 row for every day, then you can be sure that the GROUP BY will produce exactly 1 row per day, and you can use LAG (total1, 365) just like you already use LAG (total1, 7).
    Are you concerned about leap years?  That is, when the day is March 1, 2016, do you want the total_one_year_ago column to reflect March 1, 2015, which was 366 days earlier?  If that case, use
    date_id - ADD_MONTHS (date_id, -12)
    instead of  365.
    LAG only works with an exact number, but you can use RANGE BETWEEN with other analytic functions, such as MIN or SUM:
    SELECT DISTINCT
              date_id
    ,         SUM (measure1) OVER (PARTITION BY date_id)    AS total1
    ,         SUM (measure1) OVER ( ORDER BY      date_id
                                    RANGE BETWEEN 7 PRECEDING
                                          AND     7 PRECEDING
                                  )                       AS total1_one_week_ago
    ,         SUM (measure1) OVER ( ORDER BY      date_id
                                    RANGE BETWEEN 365 PRECEDING
                                          AND     365 PRECEDING
                                  )                       AS total1_one_year_ago
    FROM      daily_counts
    ORDER BY  date_id
    Again, use date arithmetic instead of the hard-coded 365, if that's an issue.
    As Hoek said, it really helps to post the exact results you want from the given sample data.  You're miles ahead of the people who don't even post the sample data, though.
    You're right not to post hundreds of INSERT statements to get a year's data.  Here's one way to generate sample data for lots of rows at the same time:
    -- Put a 0 into the table for every day in 2012
    INSERT INTO daily_counts (date_id, measure1)
    SELECT  DATE '2011-12-31' + LEVEL
    ,       0
    FROM    dual
    CONNECT BY LEVEL <= 366

  • GROUP BY and analytical functions

    Hi all,
    I need your help with grouping my data.
    Below you can see sample of my data (in my case I have view where data is in almost same format).
    with test_data as(
    select '01' as code, 'SM' as abbreviation, 1010 as groupnum, 21 as pieces, 4.13 as volume, 3.186 as avgvolume from dual
    union
    select '01' as code, 'SM' as abbreviation, 2010 as groupnum, 21 as pieces, 0 as volume, 3.186 as avgvolume from dual
    union
    select '01' as code, 'SM' as abbreviation, 3000 as groupnum, 21 as pieces, 55 as volume, 3.186 as avgvolume from dual
    union
    select '01' as code, 'SM' as abbreviation, 3010 as groupnum, 21 as pieces, 7.77 as volume, 3.186 as avgvolume from dual
    union
    select '02' as code, 'SMP' as abbreviation, 1010 as groupnum, 30 as pieces, 2.99 as volume, 0.1 as avgvolume from dual
    union
    select '03' as code, 'SMC' as abbreviation, 1010 as groupnum, 10 as pieces, 4.59 as volume, 0.459 as avgvolume from dual
    union
    select '40' as code, 'DB' as abbreviation, 1010 as groupnum, 21 as pieces, 5.28 as avgvolume, 0.251 as avgvolume from dual
    select
    DECODE (GROUPING (code), 1, 'report total:', code)     as code,
    abbreviation as abbreviation,
    groupnum as pricelistgrp,
    sum(pieces) as pieces,
    sum(volume) as volume,
    sum(avgvolume) as avgvolume
    --sum(sum(distinct pieces)) over (partition by code,groupnum) as piecessum,
    --sum(volume) volume,
    --round(sum(volume) / 82,3) as avgvolume
    from test_data
    group by grouping sets((code,abbreviation,groupnum,pieces,volume,avgvolume),null)
    order by 1,3;Select statement which I have written returns the output below:
    CODE    ABBR    GRPOUP  PIECES   VOLUME  AVGVOL
    01     SM     1010     21     4.13     3.186
    01     SM     2010     21     0     3.186
    01     SM     3000     21     55     3.186
    01     SM     3010     21     7.77     3.186
    02     SMP     1010     30     2.99     0.1
    03     SMC     1010     10     4.59     0.459
    40     DB     1010     21     5.28     0.251
    report total:          145     79.76     13.554Number of pieces and avg volume is same for same codes (01 - pieces = 21, avgvolume = 3.186 etc.)
    What I need is to get output like below:
    CODE    ABBR    GRPOUP  PIECES   VOLUME  AVGVOL
    01     SM     1010     21     4.13     3.186
    01     SM     2010     21     0     3.186
    01     SM     3000     21     55     3.186
    01     SM     3010     21     7.77     3.186
    02     SMP     1010     30     2.99     0.1
    03     SMC     1010     10     4.59     0.459
    40     DB     1010     21     5.28     0.251
    report total:          82     79.76     0.973Where total number of pieces is computed as sum of distinct numbers of pieces for each code -> *82 = 21 + 30 + 10 +21*.
    Total volume is just sum of volumes in each row -> *79.76 = 4.13+0+55+7.77+2.99+4.59+5.28*.
    And Average volume is computed as total volume / total number of pieces -> *0.973 = 79.76 / 82*.
    I was trying to use analytical function (sum() over (partition by)) to get desired output, but without good results.
    Could anyone help me with this issue?
    Thanks in advance!
    Regards,
    Jiri

    Hi, Jiri,
    Jiri N. wrote:
    Hi all,
    I need your help with grouping my data.
    Below you can see sample of my data (in my case I have view where data is in almost same format).I assume the view guarantees that all rows with the same code (or the same code and groupnum) will always have the same pieces and the same avgvolume.
    with test_data as( ...Thanks for posting this; it's very helpful.
    What I need is to get output like below:
    CODE    ABBR    GRPOUP  PIECES   VOLUME  AVGVOL
    01     SM     1010     21     4.13     3.186
    01     SM     2010     21     0     3.186
    01     SM     3000     21     55     3.186
    01     SM     3010     21     7.77     3.186
    02     SMP     1010     30     2.99     0.1
    03     SMC     1010     10     4.59     0.459
    40     DB     1010     21     5.28     0.251
    report total:          82     79.76     0.973
    Except for the last row, you're just displaying data straight from the table (or view).
    It might be easier to get the results you want uisng a UNION. One branch of the UNION would get the"report total" row, and the other branch would get all the rest.
    >
    Where total number of pieces is computed as sum of distinct numbers of pieces for each code -> *82 = 21 + 30 + 10 +21*.It's not just distinct numbers. In this example, two different codes have pieces=21, so the total of distinct pieces is 61 = 21 + 30 + 10.
    >
    Total volume is just sum of volumes in each row -> *79.76 = 4.13+0+55+7.77+2.99+4.59+5.28*.
    And Average volume is computed as total volume / total number of pieces -> *0.973 = 79.76 / 82*.
    I was trying to use analytical function (sum() over (partition by)) to get desired output, but without good results. I would use nested aggregate functions to do that:
    SELECT    code
    ,       abbreviation
    ,       groupnum          AS pricelistgrp
    ,       pieces
    ,       volume
    ,       avgvolume
    FROM      test_data
         UNION ALL
    SELECT        'report total:'     AS code
    ,        NULL                  AS abbreviaion
    ,        NULL               AS pricelistgrp
    ,        SUM (MAX (pieces))     AS pieces
    ,        SUM (SUM (volume))     AS volume
    ,        SUM (SUM (volume))
          / SUM (MAX (pieces))     AS avgvolume
    FROM        test_data
    GROUP BY   code     -- , abbreviation?
    ORDER BY  code
    ,            pricelistgrp
    ;Output:
    CODE          ABB PRICELISTGRP     PIECES  VOLUME  AVGVOLUME
    01            SM          1010         21    4.13      3.186
    01            SM          2010         21    0.00      3.186
    01            SM          3000         21   55.00      3.186
    01            SM          3010         21    7.77      3.186
    02            SMP         1010         30    2.99       .100
    03            SMC         1010         10    4.59       .459
    40            DB          1010         21    5.28       .251
    report total:                          82   79.76       .973It's unclear if you want to GROUP BY just code (like I did above) or by both code and abbreviation.
    Given that this data is coming from a view, it might be simpler and/or more efficient to make separate version of the view, or to replicate most of the view in a query.

Maybe you are looking for