问题
I have two tables appointment app and faculty fac. they are multiple record with same emp ids
- I need to join two tables by
app.employeeid=fac.empid
(here i will get duplicate records) - 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 ) 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 maxapp.amt
for eachemployeeid
. - changed your
FROM app, fac .. WHERE app.employeeid=fac.empid
into aJOIN
(see note below) - no need for the
GROUP BY
orMAX(app.amt)
-- theINNER 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