2009-12-23 3 views
15

Я ищу способ обработки следующего сценария. У меня есть таблица базы данных, в которой мне нужно вернуть только одну запись для каждого «идентификатора группы», который содержится в таблице, кроме того, запись, выбранная в каждой группе, должна быть самым старым лицом в семье.SQL-запрос для возврата только 1 записи на группу ID

ID Group ID Name    Age 
1 134  John Bowers  37 
2 134  Kerri Bowers  33 
3 135  John Bowers  44 
4 135  Shannon Bowers  42 

Таким образом, в выборочных данных, приведенных выше I потребуется ID 1 и 3 возвращается, так как они являются древнейшими людьми в пределах каждой группы ид.

Это запрос к базе данных SQL Server 2005.

+0

Если вы хотите получить имя, у вас все еще будет возможность выбрать> 1 строку, если у вас есть> 1 человек со старейшим возрастом. Вы также должны установить критерии того, какое имя выбрать в этом случае. –

+0

Хорошая точка Крис. Я пытался немного упростить вопрос, но это оставляет такие дыры :-) У меня на самом деле есть другое поле для пола, поэтому я ищу, чтобы выбрать самого старого мужчину в семье. если есть мужчина, то самая старая женщина. В случае, если в одном домохозяйстве с одним и тем же возрастом есть два самца, тогда мне нужно выбрать только одну запись. Это может быть основано на чем-то таком же простом, как человек с наименьшим идентификационным номером для тай-брейкера. –

+1

Существует хорошая дискуссия по этой проблеме в разделе 21.4 «Экстремальные функции» превосходной книги Джо Селко «SQL for Smarties». Если вы собираетесь столкнуться с чем-то более сложным, чем простые SELECT и INSERT, я настоятельно рекомендую эту книгу. – shoover

ответ

21
SELECT t.* 
FROM (
     SELECT DISTINCT groupid 
     FROM mytable 
     ) mo 
CROSS APPLY 
     (
     SELECT TOP 1 * 
     FROM mytable mi 
     WHERE mi.groupid = mo.groupid 
     ORDER BY 
       age DESC 
     ) t 

или это:

SELECT * 
FROM (
     SELECT *, ROW_NUMBER() OVER (PARTITION BY groupid ORDER BY age DESC) rn 
     FROM mytable 
     ) 
WHERE rn = 1 

Это вернет более одной записи в каждой группе даже в случае связей.

Смотрите эту статью в своем блоге для сравнения производительности обоих методов:

+0

+1: Да, забыл мое заявление об ограничении связи. Слишком заняты боевыми огнями. –

+0

Спасибо Quassnoi. Я смог добавить столбец gender в дополнение к столбцу возраста в предложении ORDER BY и получить результаты, которые я искал! (Гендерный столбец обсуждался только в комментарии после моего первоначального вопроса). Ваше решение идеально и адаптируется! –

+0

Последующий вопрос. Они будут работать против 175 миллионов записей. Является ли один или другой запрос более эффективным? –

0
SELECT GroupID, Name, Age 
FROM table 
INNER JOIN 
(
SELECT GroupID, MAX(Age) AS OLDEST 
FROM table 
) AS OLDESTPEOPLE 
ON 
table.GroupID = OLDESTPEOPLE.GroupID 
AND 
table.Age = OLDESTPEOPLE.OLDEST 
3

Использование:

SELECT DISTINCT 
     t.groupid, 
     t.name 
    FROM TABLE t 
    JOIN (SELECT t.groupid, 
       MAX(t.age) 'max_age' 
      FROM TABLE t 
     GROUP BY t.groupid) x ON x.groupid = t.groupid 
          AND x.max_age = t.age 

Так что, если есть 2+ людей с того же возраста для группы? Было бы лучше сохранить дату рождения, а не возраст - вы всегда можете рассчитать дату рождения для презентации.

+0

Остерегайтесь связей! – Quassnoi

0

Попробуйте это (при условии, Group является синонимом бытовой)

Select * From Table t 
Where Age = (Select Max(Age) 
      From Table 
      Where GroupId = t.GroupId) 

Если два или более «старые» люди в какой-то домохозяйстве (все они ровесники и есть никто другой старше), то это вернет все из них, а не только случайным образом.

Если это проблема, вам нужно добавить еще один подзапрос, чтобы вернуть произвольное значение ключа для одного человека в этом наборе.

Select * From Table t 
Where Id = 
    (Select Max(Id) Fom Table 
    Where GroupId = t.GroupId 
     And Age = 
     (Select(Max(Age) From Table 
      Where GroupId = t.GroupId))