Home > other >  How to subtract two specific rows and create custom column with answer
How to subtract two specific rows and create custom column with answer

Time:10-28

Im trying to show how many users are each level versus how many total users have completed a level. I need the Unique User column to be a subtraction of two columns except at the Appr level I just need it to be a repeat of the user column because it's the highest level,

CPNT_ID Users Unique Users
Trainee 44662 11563 (which is 44662-33099)
SvcTech 33099 12420 (33099-20679)
CrewChief 20679 5079 (20679-15600)
SvcCoord 15600 6010 (15600-9590)
Appr 9590 9590 (this is the highest so no subtraction)
select 
cpnt.cpnt_id 
,count ( distinct pc.stud_id ) users
from 
pa_stud_program sp,
        pa_program p,
        pa_student s,
        pa_stud_cpnt pc,
        ps_program_type pt,
        pa_cpnt cpnt
WHERE p.PROGRAM_SYS_GUID = sp.PROGRAM_SYS_GUID
    and pc.compl_dte is not null
    and cpnt.cpnt_id in ('Trainee','SvcTech','CrewChief','SvcCoord','Appr')
    and s.jp_id in ('1801','1805','1810','1811')
    and s.EMP_STAT_ID = 'Active'
    AND cpnt.CPNT_TYP_ID     = p.CPNT_TYP_ID
    AND cpnt.CPNT_ID         = p.CPNT_ID
    AND cpnt.REV_DTE         = p.REV_DTE
    AND pc.STUD_ID           = sp.STUD_ID
    AND sp.stud_id           = s.STUD_ID
    AND pc.CPNT_ID           = sp.CPNT_ID
    AND pc.CPNT_TYP_ID       = sp.CPNT_TYP_ID
    AND pc.REV_DTE           = sp.REV_DTE
    AND pc.seq_num           = sp.seq_num
    AND pt.PROGRAM_TYPE_ID   = p.PROGRAM_TYPE   
    /** and s.PERSON_ID_EXTERNAL  in [UserSearch]*/ 
group by cpnt.cpnt_id
order by users desc

CodePudding user response:

Looks like a candidate for the lag analytic function.

SQL> with test as
  2    -- sample data
  3    (select 'Trainee'  cpnt_id, 44662 users from dual union all
  4     select 'SvcTech'         , 33099       from dual union all
  5     select 'CrewChief'       , 20679       from dual union all
  6     select 'SvcCoord'        , 15600       from dual union all
  7     select 'Appr'            ,  9590       from dual
  8    )
  9  -- subquery return "previous" CPNT_ID value which is then concatenated to its "pair"
 10  -- joined on USERS value (as there's no other, at least not in your example)
 11  select a.cpnt_id,
 12         a.users,
 13         a.cpnt_id || case when b.l_cpnt_id is not null then ' - '|| b.l_cpnt_id end
 14           unique_users
 15  from test a join (select cpnt_id,
 16                           users,
 17                           lag(cpnt_id) over (order by users) l_cpnt_id
 18                    from test
 19                   ) b on a.users = b.users
 20  order by a.users desc;

CPNT_ID        USERS UNIQUE_USERS
--------- ---------- ---------------------
Trainee        44662 Trainee - SvcTech
SvcTech        33099 SvcTech - CrewChief
CrewChief      20679 CrewChief - SvcCoord
SvcCoord       15600 SvcCoord - Appr
Appr            9590 Appr

SQL>

[EDIT, after you changed the requirement]

That's even simpler:

<snip>
 11  select a.cpnt_id,
 12         a.users,
 13         a.users -  nvl(b.l_users, 0) as unique_users
 14  from test a join (select cpnt_id,
 15                           users,
 16                           lag(users) over (order by users) l_users
 17                    from test
 18                   ) b on a.users = b.users
 19  order by a.users desc;

CPNT_ID        USERS UNIQUE_USERS
--------- ---------- ------------
Trainee        44662        11563
SvcTech        33099        12420
CrewChief      20679         5079
SvcCoord       15600         6010
Appr            9590         9590

SQL>

Implementing that into your query: use a CTE:

with your_query as
  (select 
        cpnt.cpnt_id 
        ,count ( distinct pc.stud_id ) users
   from 
        pa_stud_program sp,
        pa_program p,
        pa_student s,
        pa_stud_cpnt pc,
        ps_program_type pt,
        pa_cpnt cpnt
WHERE p.PROGRAM_SYS_GUID = sp.PROGRAM_SYS_GUID
    and pc.compl_dte is not null
    and cpnt.cpnt_id in ('Trainee','SvcTech','CrewChief','SvcCoord','Appr')
    and s.jp_id in ('1801','1805','1810','1811')
    and s.EMP_STAT_ID = 'Active'
    AND cpnt.CPNT_TYP_ID     = p.CPNT_TYP_ID
    AND cpnt.CPNT_ID         = p.CPNT_ID
    AND cpnt.REV_DTE         = p.REV_DTE
    AND pc.STUD_ID           = sp.STUD_ID
    AND sp.stud_id           = s.STUD_ID
    AND pc.CPNT_ID           = sp.CPNT_ID
    AND pc.CPNT_TYP_ID       = sp.CPNT_TYP_ID
    AND pc.REV_DTE           = sp.REV_DTE
    AND pc.seq_num           = sp.seq_num
    AND pt.PROGRAM_TYPE_ID   = p.PROGRAM_TYPE   
group by cpnt.cpnt_id
)
select a.cpnt_id,
       a.users,
       a.users -  nvl(b.l_users, 0) as unique_users
from your_query a join (select cpnt_id,
                         users,
                         lag(users) over (order by users) l_users
                  from your_query
                 ) b on a.users = b.users
order by a.users desc;
  • Related