2010-01-28 3 views
3

Проблема: У меня есть список имен и адресов. Некоторые имена (лица) имеют одинаковый адрес (улица, почтовый индекс, город), как и другие. Я хочу выбрать все эти имена с адресами, имеющими не более трех вхождений, а остальные три первых имени каждой из групп, указывающих на один и тот же адрес. Пример: Как ограничить набор результатов SQL не слишком общими элементами

 
Albert | Adr1 
Berta | Adr1 
Cesar | Adr1 
Donald | Adr1 
Eric | Adr2 
Fritz | Adr2 
Gerd | Adr2 
Henry | Adr3

Набор результат должен быть

Albert | Adr1 
Berta | Adr1 
Cesar | Adr1 
Eric | Adr2 
Fritz | Adr2 
Gerd | Adr2 
Henry | Adr3

Дональда отсутствует, потому что он является 4 группы с тем же адресом. Можно ли добиться этого результата с помощью UNION и подзапросов? Что-то вроде

select * from addresses where address in 
(select address from addresses group by address having count(address) <= 3) 
UNION 
select * from addresses where address in 
(select address from addresses group by address having count(address) > 3 limit 3)

Я знаю, что этот запрос является неправильным, поскольку он ограничивает полный результирующий набор адресов с более чем 3 вхождений. Интересно, можно ли это сделать в одном SELECT с UNION и подзапросами. Я сделаю это теперь процедурно с PHP/MySQL, но просто для удовольствия будет интересоваться только SQL-решением.

Я посмотрел SQL query with limit on rows from one table, not the result set, но это не отражает мою ситуацию - или не так ли?

+0

, как вы можете признать, что Дональд является четвертым членом группы? как эти данные сортируются? – Beatles1692

+0

Является ли этот MySql или Sql-сервер? –

+0

Порядок сортировки не имеет значения. Это должно быть любые 3 адреса из более чем 3. Сервер MySQL 5.1 –

ответ

1

Вы можете попробовать что-то вроде

SELECT PersonName, 
     Address 
FROM (
      SELECT *, 
        (SELECT COUNT(1) FROM addresses WHERE Address = a.Address AND PersonName < a.PersonName) CountLess 
      FROM addresses a 
     ) sub 
WHERE sub.CountLess <= 2 
+0

Очень изобретательный. Большое спасибо. –

3
select name, address 
from 
(select *, row_number() over (partition by address order by name) as namenum 
    from yourTable 
) t 
where namenum <= 3; 
+1

Является ли это стандартом SQL? –

+0

Это работает в SQL Server, и Oracle и DB2 поддерживают также предложение OVER. Я не думаю, что mysql до сих пор догонял эту часть стандарта, точно так же, как SQL Server не требует полуколонков. –

+0

Это не поддерживается MySQL. Это решение указывало мне на http://explainextended.com/2009/09/14/mysql-emulating-row_number-with-multiple-order-by-conditions/, хотя, когда рассматривается аналогичная проблема и функциональность решения Robs эмулируется. –