Display distinct record for each employee

北城余情 提交于 2019-12-25 07:58:18

问题


I have two tables appointment app and faculty fac. they are multiple record with same emp ids

  1. I need to join two tables by app.employeeid=fac.empid (here i will get duplicate records)
  2. and app.begindate<=now and app.enddate>=now and app.percent>.50 (here also i will get duplicate records because empid(multiple records with same id) can have same begindate,end date and >.50 )
  3. max(app.amt) (here also i will get duplicate records because there can be a chance where empid(multiple records with same id) have same amt) . Finally at the end i want to select distinct(max(app.amt)) to get only single record for empid.

I used the query:

select max(app.amt) ,fac.email,fac.employee_id,fac.empid,fac.first_name,fac.last_name,fac.department_id,fac.titlecode,app.begindate,app.enddate,app.percent,
app.title_name,app.department_name from faculty fac, appointment app where 
app.employeeid=fac.empid and app.begindate <= now() and app.enddate >= now() and app.percent>.50  group by fac.empid
/

i am having an issue i am getting max(app.amt) but corresponding column values are not properly matched with max amt record.the other column values are taking in random.I want the exact corresponding values to display.

sample date in appointment table for few fileds:

SELECT app.amt, fac.email, fac.employee_id, fac.empid, 
                 fac.first_name, fac.last_name, fac.department_id, fac.titlecode,
                 app.begindate, app.enddate, app.percent,
                 app.title_name, app.department_name 
FROM appointment app
LEFT JOIN appointment app2                                    -- self-join to locate  max
ON app.employee_id = app2.employee_id AND app.amt < app2.amt --  of app.amt
INNER JOIN faculty fac ON app.employee_id=fac.empid           -- join to fac
WHERE app2.amt IS NULL                                        -- isolate rows with     max(app.amt)
AND app.begindate <= NOW() 
AND app.enddate >= NOW() 
AND app.percent>.50 group by fac.empid


employee_id begindate enddate     amt        percent  department_name
5528        7/1/2011  9/30/2011   0          1        m1
5528        7/1/2011  9/30/2011   193100     1        m1
5528        10/1/2011 6/30/2013   79000      1        m1
5528        10/1/2011 6/30/2013   118500     1        m2
5528        10/1/2011 6/30/2013   0          1        m2

回答1:


To select not only a MAX(column) but the row corresponding to it, for each employee_id, you usually use a LEFT JOIN to join the table to itself. (This is also known as "greatest-n-per-group" and there are a number of questions in this vein on stackoverflow under this tag).

e.g. to select the max(app.amt) per employee_id with its corresponding row you would do:

SELECT app.*
FROM appointment app
LEFT JOIN appointment app2
 ON app.employee_id = app2.employee_id AND app.amt < app2.amt
WHERE app2.amt IS NULL;

Why does this work? In essence, this says "pick the row with the amt for which there is no higher amt for that employee", for each employee.

The LEFT JOIN appointment app2 ON app.employee_id=app2.employee_id joins app to itself on the employee_id (note this is what you wanted to GROUP BY). This produces a table of appointment with every possible pair of amt for each employee_id.

Then, we also specify that app.amt < app2.amt. So we only display rows where the (app.amt,app2.amt) pair has the former less than the latter. Since this is a LEFT JOIN, if we happen to find an app.amt for which we can't find a corresponding row in app2 with the same employee_id and a greater app2.amt, then app2.amt is set to NULL. This occurs precisely when we've found the greatest app.amt for that employee.

Solution

So, adapt your query using this "LEFT JOIN to myself to get the corresponding row" method:

SELECT app.amt, fac.email, fac.employee_id, fac.empid, 
                     fac.first_name, fac.last_name, fac.department_id, fac.titlecode,
                     app.begindate, app.enddate, app.percent,
                     app.title_name, app.department_name 
FROM appointment app
LEFT JOIN appointment app2                                    -- self-join to locate max
 ON app.employee_id = app2.employee_id AND app.amt < app2.amt --  of app.amt
INNER JOIN faculty fac ON app.employee_id=fac.empid           -- join to fac
WHERE app2.amt IS NULL                                        -- isolate rows with max(app.amt)
  AND app.begindate <= NOW() 
  AND app.enddate >= NOW() 
  AND app.percent>.50

So, the only things that have changed are:

  • added a LEFT JOIN appointment app2 ... WHERE app2.amt IS NULL to locate the row with the max app.amt for each employeeid.
  • changed your FROM app, fac .. WHERE app.employeeid=fac.empid into a JOIN (see note below)
  • no need for the GROUP BY or MAX(app.amt) -- the INNER JOIN takes care of that.

Note on converting the FROM app, fac ... WHERE join_condition to FROM app LEFT JOIN fac ON join_condition: a join tends to be more efficient than selecting from multiple tables and joining in the WHERE.

What type of join you use (app to fac) may make a difference to your results; to recover your former behaviour use INNER JOIN. This will only display rows where the employee exists in both the app table and the fac table.

Using a LEFT JOIN is slightly more efficient than the INNER JOIN, and the results will be identical unless there is an employee in your appointments table who does not have an entry in the faculty table. Then they will be displayed in the results list with NULL for all the fac.xxx fields.

Using a RIGHT JOIN will show every employee from the faculty table regardless of whether they have appointments or not -- if they have no appointments they'll still be shown in your results, just with NULL for all their appointment-related fields.

Just subtle differences in the JOINs (ahh, but that's another question).



来源:https://stackoverflow.com/questions/8980972/display-distinct-record-for-each-employee

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!