开发者

SQL - help on "top 1 by group"

Relevant tables:

DepartmentPhone: DepartmentPhoneID int, DepartmentID int, PhoneID int

Phone: PhoneID int, PhoneType int

There are 6 phones with PhoneType=4 that belong to DepartmentID=2. So this produces 6 records:

se开发者_JS百科lect *
from DepartmentPhone
  join Phone on Phone.PhoneID = DepartmentPhone.PhoneID and Phone.PhoneType = 4
where DepartmentPhone.DepartmentID = 2

Note that DepartmentID=2 is for illustration purposes and that my query will bring all departments.

What I want to achieve is select the first Phone (type=4) for each Department - only 1 row per department. I thought the following query would do the trick but it keeps retrieving all 6 records. What am i missing?

select x.*
from DepartmentPhone x
where 
  x.DepartmentID = 2
  and x.PhoneID = (select max(y.PhoneID)
                   from departmentphone y 
                     join Phone on y.PhoneID = Phone.PhoneID and Phone.PhoneType = 4
                   where x.DepartmentPhoneID = y.DepartmentPhoneID)

Thanks for your help!!!


I wish there were a clean syntax for this. The best is to use ROW_NUMBER:

;WITH DepartmentPhone_CTE AS
(
    SELECT p.*, 
        ROW_NUMBER() OVER
            (PARTITION BY dp.DepartmentID ORDER BY dp.PhoneID) AS RowNum
    FROM DepartmentPhone dp
    INNER JOIN Phone p
        ON p.PhoneID = dp.PhoneID
    WHERE p.PhoneType = 4
)
SELECT dp.*
FROM DepartmentPhone_CTE
WHERE RowNum = 1


I don't know your schema as well as you do, but would guess you need to correlate your groupings by DepartmentID, not DepartmentPhoneID.

select x.*
from DepartmentPhone x
where 
  x.DepartmentID = 2
  and x.PhoneID = (select max(y.PhoneID)
                   from departmentphone y 
                     join Phone on y.PhoneID = Phone.PhoneID and Phone.PhoneType = 4
                   where x.DepartmentID = y.DepartmentID);

Here's a couple of alternative queries that should get the same result without using a correlated subquery. The first uses a derived table:

select *
from DepartmentPhone x
join (select d.DepartmentID, max(d.PhoneID) as maxPhoneID
      from DpartmentPhone d join Phone p using (PhoneID)
      where p.PhoneType = 4
      group by d.DepartmentID) y
  using (DepartmentID);

The second alternative uses no subquery at all, but a self-join:

select d1.*
from DepartmentPhone d1
join Phone p1 on d1.PhoneID = p1.PhoneID and p1.PhoneType = 4
left outer join (DepartmentPhone d2 join Phone p2 
    on d2.PhoneID = p2.PhoneID and p2.PhoneType = 4)
  on d1.DepartmentID = d2.DepartmentID and d1.PhoneID < d2.PhoneID
where d2.DepartmentID is NULL;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜