SQL Group By — выберите оба столбца

У меня есть таблица пользователей, содержащая следующие столбцы:

| User_ID  (int) | Name (varchar) |   Age (int)  |  Experience_Level (int) |

Я хотел бы создать SQL-запрос для вывода всех идентификаторов людей, которые не уникальны по сочетанию возраста и опыта.

Мой код до сих пор:

SELECT Count(*), User_ID FROM Users 
GROUP BY Age,Experience_Level
HAVING Count(*) > 1

Очевидно, что это неполный текст. Это сгруппирует неуникальных пользователей, но не сообщит мне все их идентификаторы User_ID.

Заранее спасибо за помощь!


person pws5068    schedule 02.07.2010    source источник


Ответы (4)


Вот отрицательный логический запрос:

SELECT *
FROM Users
WHERE UserID not in
(
SELECT MIN(UserID)
FROM Users
GROUP BY Age, Experience_Level
HAVING COUNT(*) = 1
)
person Amy B    schedule 02.07.2010

Поскольку вам нужна информация о группах из нескольких пользователей, как вы хотите, чтобы эти данные возвращались? В строке, содержащей список значений user_id, разделенных запятыми?

Вы не указали в своем вопросе марку базы данных SQL, которую вы используете.

Если вы используете MySQL или SQLite, вы можете использовать встроенную функцию GROUP_CONCAT():

SELECT Count(*), GROUP_CONCAT(User_ID) AS User_List FROM Users 
GROUP BY Age,Experience_Level
HAVING Count(*) > 1

По умолчанию GROUP_CONCAT() разделяет значения запятыми. Обратитесь к руководству, если вы хотите отформатировать его по-другому.

Существуют и другие решения для других поставщиков SQL. Этот вопрос много раз поднимался в Stack Overflow:

person Bill Karwin    schedule 02.07.2010
comment
Из-за отсутствия user_id в GROUP BY только MySQL и SQLite поддерживают скрытые столбцы в группе (при условии, что OP не получает ошибку при выполнении запроса). - person OMG Ponies; 02.07.2010
comment
@OMG Ponies: Предполагая, что GROUP_CONCAT() является агрегатом (и в противном случае это не имело бы особого смысла), нет причин, по которым он не работал бы в других СУБД (при условии, что он или что-то подобное существует). - person Adam Robinson; 02.07.2010
comment
Извините, я должен был указать, я использую MySql. Я никогда не слышал о Group_Concat, но запрос работает. В итоге я использовал ответ Дэвида Б. для целей разделения, но я тоже кое-чему научился! Спасибо! - person pws5068; 02.07.2010
comment
@Adam Robinson: Мой комментарий Биллу был о запросе OP для определения поставщика базы данных. GROUP_CONCAT есть только в MySQL и SQLite — поиск генерации списка, разделенного запятыми, на SO. - person OMG Ponies; 02.07.2010

SELECT t.User_ID, t.Age, t.Experience_Level
FROM Users t INNER JOIN 
    (SELECT Age, Experience_Level
    FROM Users
    GROUP BY Age, Experience_Level
    HAVING Count(*) > 1) d ON t.Age = d.Age AND t.Experience_Level = d.Experience_Level

Тестовый сценарий:

create table Users (
User_ID int,
Name varchar(50),
Age int,
Experience_Level int
)

insert into Users (User_ID, Name, Age, Experience_Level) values (1, 'A', 33, 1)
insert into Users (User_ID, Name, Age, Experience_Level) values (2, 'B', 37, 1)
insert into Users (User_ID, Name, Age, Experience_Level) values (3, 'C', 33, 1)
insert into Users (User_ID, Name, Age, Experience_Level) values (4, 'D', 35, 2)
insert into Users (User_ID, Name, Age, Experience_Level) values (5, 'E', 33, 1)
insert into Users (User_ID, Name, Age, Experience_Level) values (6, 'F', 35, 2)
insert into Users (User_ID, Name, Age, Experience_Level) values (7, 'G', 18, 1)
person Tahbaza    schedule 02.07.2010

Теоретически вы хотите что-то вроде этого, но, к сожалению, SQL Server этого не позволяет:

SELECT * FROM Users 
WHERE (Age, Experience_Level) IN
(
    SELECT Age, Experience_Level
    FROM Users  
    GROUP BY Age,Experience_Level 
    HAVING Count(*) > 1 
)

Поэтому вместо этого вы должны согласиться на присоединение к подзапросу:

SELECT Users.* FROM Users 
INNER JOIN 
(
    SELECT Age, Experience_Level
    FROM Users  
    GROUP BY Age,Experience_Level 
    HAVING Count(*) > 1 
) subq 
    ON Users.Age = subq.Age
    AND Users.Experience_Level = subq.Experience_Level
person Mike Mooney    schedule 02.07.2010