Как ограничить набор результатов SQL не слишком распространенными элементами

Problem: I have a list of names and addresses. Some names (persons) have the same address (street, zip code, town) like others. I want to select all those names with addresses with no more than three occurrences and from the rest the first three names each of a bunch pointing to the same address. Example:

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

The result set should be

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

Дональд отсутствует, потому что он четвертый в группе с таким же адресом. Можно ли добиться такого результата с помощью 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)

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

Я просмотрел запрос SQL с ограничением на количество строк из одной таблицы, а не на набор результатов, но это не отражает мою ситуацию - или это так?


person Alex Monthy    schedule 28.01.2010    source источник
comment
как вы узнали, что Дональд - четвертый участник группы? как сортируются эти данные?   -  person Beatles1692    schedule 28.01.2010
comment
Порядок сортировки значения не имеет. Это должны быть любые 3 адреса из более чем 3. Сервер MySQL 5.1.   -  person Alex Monthy    schedule 28.01.2010


Ответы (2)


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

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
person Adriaan Stander    schedule 28.01.2010
comment
Очень изобретательно. Большое спасибо. - person Alex Monthy; 28.01.2010

person    schedule
comment
Это работает в SQL Server, а Oracle и DB2 также поддерживают предложение OVER. Я не думаю, что mysql еще не догнал эту часть стандарта, точно так же, как SQL Server еще не требует точки с запятой. - person Rob Farley; 28.01.2010
comment
Это не поддерживается MySQL. Решение указало мне на explainextended. com/2009/09/14/, где рассматривается аналогичная проблема и эмулируется функциональность решения Робса. - person Alex Monthy; 28.01.2010