SQL - помощь по "топ 1 по группам" - PullRequest
1 голос
/ 13 января 2010

Соответствующие таблицы:
DepartmentPhone: Интервал DepartmentPhoneID, Int DepartmentID, PhoneID int
Phone: PhoneID int, PhoneType int

Есть 6 телефонов с PhoneType = 4, которые принадлежат DepartmentID = 2. Так что получается 6 записей:

select *
from DepartmentPhone
  join Phone on Phone.PhoneID = DepartmentPhone.PhoneID and Phone.PhoneType = 4
where DepartmentPhone.DepartmentID = 2

Обратите внимание, что DepartmentID = 2 предназначен для иллюстративных целей и что мой запрос объединит все отделы.
Чего я хочу добиться, так это выбрать первый телефон (тип = 4) для каждого отдела - только 1 строка на отдел. Я думал, что следующий запрос поможет, но он продолжает получать все 6 записей. Чего мне не хватает?

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)

Спасибо за вашу помощь !!!

Ответы [ 2 ]

2 голосов
/ 13 января 2010

Я бы хотел, чтобы было чистым синтаксисом для этого. Лучше всего использовать 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
0 голосов
/ 13 января 2010

Я не знаю вашу схему так же хорошо, как вы, но предположил бы, что вам нужно коррелировать ваши группировки по DepartmentID, а не 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);

Вот пара альтернативных запросов, которые должны получить тот же результат без использования коррелированного подзапроса. Первый использует производную таблицу:

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);

Второй вариант вообще не использует подзапрос, а само-соединение:

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;
...