If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

 
Go Back  dBforums > Database Server Software > DB2 > Need Help Averaging Highest Salaries

Reply
 
LinkBack Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old 03-01-11, 09:52
dvdaddict32 dvdaddict32 is offline
Registered User
 
Join Date: Mar 2010
Posts: 32
Need Help Averaging Highest Salaries

I am trying to come up with a query that will take an employee's three highest salaries in their history table, and then report the average of these amounts.

Unfortunately, our version of DB2 does not support RANK functions so I need an old school solution. I tried this query:


select avg(A.mbr_sal_amt) as "salary"


from

(


select mbr_ssn_nbr,
mbr_hist_svc_cr_dt,
mbr_sal_amt



from dsnp.pr01_t_mbr_hist

order by mbr_sal_amt desc
fetch first 3 rows only ) as A




But DB2 does not like the order by in my sub-query. I'm not sure if it would have even worked. I need to fetch the first 3 rows per SSN number, not the entire table.

I just really don't see a way to do this. Can anyone help? A sample of the history table looks like this:



mbr_ssn_nbr mbr_hist_svc_cr_dt mbr_sal_amt


123457575 2011-01-01 432.77
123457575 2011-02-01 233.11
123457575 2011-03-01 111.34
123666666 2011-01-01 234.66
123666666 2011-02-01 237.77
12366666 2011-03-01 123.55
Reply With Quote
  #2 (permalink)  
Old 03-01-11, 10:35
r937 r937 is offline
SQL Consultant
 
Join Date: Apr 2002
Location: Toronto, Canada
Posts: 19,524
Code:
SELECT mbr_ssn_nbr
     , AVG(mbr_sal_amt) AS salary
  FROM dsnp.pr01_t_mbr_hist AS t
 WHERE ( SELECT COUNT(*) 
           FROM dsnp.pr01_t_mbr_hist  
          WHERE mbr_ssn_nbr = t.mbr_ssn_nbr
            AND mbr_sal_amt > t.mbr_sal_amt ) < 3
GROUP
    BY mbr_ssn_nbr
untested
__________________
r937.com | rudy.ca
please visit Simply SQL and buy my book
Reply With Quote
  #3 (permalink)  
Old 03-01-11, 12:04
dvdaddict32 dvdaddict32 is offline
Registered User
 
Join Date: Mar 2010
Posts: 32
Quote:
Originally Posted by r937 View Post
Code:
SELECT mbr_ssn_nbr
     , AVG(mbr_sal_amt) AS salary
  FROM dsnp.pr01_t_mbr_hist AS t
 WHERE ( SELECT COUNT(*) 
           FROM dsnp.pr01_t_mbr_hist  
          WHERE mbr_ssn_nbr = t.mbr_ssn_nbr
            AND mbr_sal_amt > t.mbr_sal_amt ) < 3
GROUP
    BY mbr_ssn_nbr
untested
wow, that works. Would you mind explaining how this query works? I'm still a noob and not understanding it. Thanks for the help!
Reply With Quote
  #4 (permalink)  
Old 03-01-11, 12:22
r937 r937 is offline
SQL Consultant
 
Join Date: Apr 2002
Location: Toronto, Canada
Posts: 19,524
Quote:
Originally Posted by dvdaddict32 View Post
Would you mind explaining how this query works?
let's pretend you are standing in line at the bank

count the number of people ahead of you

if that number is less than three, then you are one of the first three people in line

make sense?
__________________
r937.com | rudy.ca
please visit Simply SQL and buy my book
Reply With Quote
  #5 (permalink)  
Old 03-01-11, 13:55
Marcus_A Marcus_A is offline
Registered User
 
Join Date: May 2003
Location: USA
Posts: 5,198
You need to test it with this salary data for a given employee and make sure it works:

2010 $76,000
2009 $75,000
2008 $74,000
2007 $74,000
2006 $73,000
2005 $72,000
__________________
M. A. Feldman
IBM Certified DBA on DB2 for Linux, UNIX, and Windows
IBM Certified DBA on DB2 for z/OS and OS/390
Reply With Quote
  #6 (permalink)  
Old 03-01-11, 14:04
tonkuma tonkuma is online now
Registered User
 
Join Date: Feb 2008
Location: Japan
Posts: 2,195
Quote:
our version of DB2 does not support RANK functions so I need an old school solution.
What are your DB2 version and platform?

By the way, RANK would be an solution. See Marcus's sample data.

Last edited by tonkuma; 03-01-11 at 14:08.
Reply With Quote
  #7 (permalink)  
Old 03-01-11, 14:15
tonkuma tonkuma is online now
Registered User
 
Join Date: Feb 2008
Location: Japan
Posts: 2,195
If you could find an answer using RANK for Marcus's sample data,
it would give a suggestion of an answer using an old solution.
Reply With Quote
  #8 (permalink)  
Old 03-01-11, 14:53
r937 r937 is offline
SQL Consultant
 
Join Date: Apr 2002
Location: Toronto, Canada
Posts: 19,524
Quote:
Originally Posted by tonkuma View Post
... it would give a suggestion of an answer using an old solution.
what, you don't think my solution is correct?

interesting sample data, by the way -- buddy got a raise from $74,000 to $74,000, an unlikely happenstance

are you suggesting that we now quibble over whether the correct answer is (76+75+74)/3 or (76+75+74+74)/4

by the way, which of these would dvdaddict be asking for? he wanted it based on "an employee's three highest salaries"
__________________
r937.com | rudy.ca
please visit Simply SQL and buy my book
Reply With Quote
  #9 (permalink)  
Old 03-01-11, 15:10
dvdaddict32 dvdaddict32 is offline
Registered User
 
Join Date: Mar 2010
Posts: 32
Quote:
Originally Posted by r937 View Post
what, you don't think my solution is correct?

interesting sample data, by the way -- buddy got a raise from $74,000 to $74,000, an unlikely happenstance

are you suggesting that we now quibble over whether the correct answer is (76+75+74)/3 or (76+75+74+74)/4

by the way, which of these would dvdaddict be asking for? he wanted it based on "an employee's three highest salaries"
There should only be three numbers to be averaged so (76+75+74)/3 would be the correct one
Reply With Quote
  #10 (permalink)  
Old 03-01-11, 15:12
dvdaddict32 dvdaddict32 is offline
Registered User
 
Join Date: Mar 2010
Posts: 32
Quote:
Originally Posted by tonkuma View Post
What are your DB2 version and platform?

By the way, RANK would be an solution. See Marcus's sample data.
Our programmer says we are on version 8. Oddly enough, I can do the FETCH function, but I get errors when I try to do RANK or DENSE_RANK. I tested the same RANK query on a SQL server, and it worked so I know it's not a syntax problem.
Reply With Quote
  #11 (permalink)  
Old 03-01-11, 16:03
tonkuma tonkuma is online now
Registered User
 
Join Date: Feb 2008
Location: Japan
Posts: 2,195
Quote:
If you could find an answer using RANK for Marcus's sample data,
it would give a suggestion of an answer using an old solution.
I was thinking as follwings...

If you want (76 + 75 + 74) / 3 for Macus's sample data(1.e. 76, 75, 74, 74, 73, 72)
and there was an answer using RANK on newer DB2 version or on anyother DBMS(like SQL server),
the answer should include additional column(s) to mbr_sal_amt in ORDER BY clause of RANK() OVER(...), like...
RANK() OVER(... ORDER BY mbr_sal_amt DESC, mbr_hist_svc_cr_dt)

Then you may want to modify R937's code like this...

Code:
SELECT mbr_ssn_nbr
     , AVG(mbr_sal_amt) AS salary
  FROM dsnp.pr01_t_mbr_hist AS t
 WHERE ( SELECT COUNT(*) 
           FROM dsnp.pr01_t_mbr_hist  
          WHERE mbr_ssn_nbr = t.mbr_ssn_nbr
            AND (mbr_sal_amt > t.mbr_sal_amt
                 OR
                 mbr_sal_amt = t.mbr_sal_amt
                 AND
                 mbr_hist_svc_cr_dt < t.mbr_hist_svc_cr_dt
                )) < 3
GROUP
    BY mbr_ssn_nbr

Last edited by tonkuma; 03-01-11 at 16:14.
Reply With Quote
  #12 (permalink)  
Old 03-01-11, 16:35
Marcus_A Marcus_A is offline
Registered User
 
Join Date: May 2003
Location: USA
Posts: 5,198
Quote:
Originally Posted by dvdaddict32 View Post
There should only be three numbers to be averaged so (76+75+74)/3 would be the correct one
Are you saying that there are no duplicate salary numbers for a given employee in the data you are given?
__________________
M. A. Feldman
IBM Certified DBA on DB2 for Linux, UNIX, and Windows
IBM Certified DBA on DB2 for z/OS and OS/390
Reply With Quote
  #13 (permalink)  
Old 03-01-11, 16:42
r937 r937 is offline
SQL Consultant
 
Join Date: Apr 2002
Location: Toronto, Canada
Posts: 19,524
Code:
SELECT mbr_ssn_nbr
     , AVG(distinctsalary) AS salary
  FROM ( SELECT mbr_ssn_nbr
              , mbr_sal_amt AS distinctsalary
           FROM dsnp.pr01_t_mbr_hist AS t
          WHERE ( SELECT COUNT(*) 
                    FROM dsnp.pr01_t_mbr_hist  
                   WHERE mbr_ssn_nbr = t.mbr_ssn_nbr
                     AND mbr_sal_amt > t.mbr_sal_amt ) < 3
         GROUP
             BY mbr_ssn_nbr
              , mbr_sal_amt ) AS d
GROUP
    BY mbr_ssn_nbr
__________________
r937.com | rudy.ca
please visit Simply SQL and buy my book
Reply With Quote
  #14 (permalink)  
Old 03-01-11, 17:00
dvdaddict32 dvdaddict32 is offline
Registered User
 
Join Date: Mar 2010
Posts: 32
Quote:
Originally Posted by Marcus_A View Post
Are you saying that there are no duplicate salary numbers for a given employee in the data you are given?
Sorry, yes there can be duplicate salary numbers. I would need the query to take the average of the top three highest distinct salaries. Doesn't matter what month they occur in.


I have one account with this history:


2009-12-31 3061
2010-07-31 3061
2010-12-31 3061
2011-01-31 2112
2010-08-31 2040
2010-09-30 2040
2010-10-31 2040

R937's query is giving me 3061 for the average, but I need it to average (3061, 2122, 2040)
Reply With Quote
  #15 (permalink)  
Old 03-01-11, 19:06
tonkuma tonkuma is online now
Registered User
 
Join Date: Feb 2008
Location: Japan
Posts: 2,195
Quote:
I have one account with this history:


2009-12-31 3061
2010-07-31 3061
2010-12-31 3061
2011-01-31 2112
2010-08-31 2040
2010-09-30 2040
2010-10-31 2040

R937's query is giving me 3061 for the average, but I need it to average (3061, 2122, 2040)
If I took values of sample data, answer must be
(3061 + 2112 + 2040) / 3 = 2404

(Added some data.)
Code:
------------------------------ Commands Entered ------------------------------
WITH
/****************************************
********* Start of sample data. *********
****************************************/
 pr01_t_mbr_hist
(mbr_ssn_nbr , mbr_hist_svc_cr_dt , mbr_sal_amt) AS (
VALUES
  (123457575 , '2009-12-31' , 3061)
, (123457575 , '2010-07-31' , 3061)
, (123457575 , '2010-12-31' , 3061)
, (123457575 , '2011-01-31' , 2112)
, (123457575 , '2010-08-31' , 2040)
, (123457575 , '2010-09-30' , 2040)
, (123457575 , '2010-10-31' , 2040)
, (123457575 , '2011-02-28' , 1900)
, (123457575 , '2010-05-31' , 1500)
, (123666666 , '2011-01-01' ,  234)
, (123666666 , '2011-02-01' ,  237)
, (123666666 , '2011-03-01' ,  123) 
)
/****************************************
*********   End of sample data. *********
****************************************/
SELECT mbr_ssn_nbr
     , AVG  (DISTINCT mbr_sal_amt) AS avg_salary
 FROM  pr01_t_mbr_hist t
 WHERE (SELECT COUNT(DISTINCT mbr_sal_amt)
         FROM  pr01_t_mbr_hist
         WHERE mbr_ssn_nbr = t.mbr_ssn_nbr
           AND mbr_sal_amt > t.mbr_sal_amt
       ) < 3
 GROUP BY
       mbr_ssn_nbr
;
------------------------------------------------------------------------------

MBR_SSN_NBR AVG_SALARY 
----------- -----------
  123457575        2404
  123666666         198

  2 record(s) selected.
Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On