MySQL вибирає один стовпець DISTINCT з відповідними іншими стовпцями


193
ID   FirstName   LastName
1      John        Doe
2      Bugs        Bunny
3      John        Johnson

Я хочу вибрати DISTINCTрезультати з FirstNameстовпця, але мені потрібні відповідні IDта LastName.

Набір результатів повинен показувати лише один John, але з IDзначенням 1 і LastNameDoe.


1
Ви хочете, щоб прізвище належало до найнижчого ідентифікатора з чітким іменем?
Томас Ленґстон

3
Яка логіка повинна підходити до вибору верхнього? Я б подумав, що ви хочете, щоб і Джон До, і Джон Джонсон з'явились, оскільки вони є двома окремими Джонсами, але це тільки я.
судда

4
DISTINCTне є функцією. Усі відповіді з DISTINCT()невірними. Помилка з’явиться, коли ви не розміщуєте її після SELECT.
Переповнення запитань

1
ALL відповіді, використовуючи круглі дужки після виразного слова, дійсно помилкові. Розрізнення НЕ функція, тому вона не може прийняти параметр. Дужки, що слідують за думками, просто ігноруються. Якщо ви не використовуєте PostgreSQL, де дужки формуватимуть "складний тип даних"
Used_By_Already

Відповіді:


192

спробуйте цей запит

 SELECT ID, FirstName, LastName FROM table GROUP BY(FirstName)

15
Як ми можемо знати, який рядок буде повернуто?
Вільям Ентрікен

26
@ Повної гідності ви не можете, згідно з документацією на MySQL : "Сервер може вибирати будь-яке значення з кожної групи, тому, якщо вони не є однаковими, вибрані значення не визначені." На практиці я успішно використовував подібний тип запитів із пунктом ORDER BY, наприклад, ви можете додати ORDER BY id ASC / DESC, а MySQL повертає стійкі результати щоразу, коли ви виконуєте запит. Але я був би впевнений, чи повинен хтось використовувати недокументовані функції у виробничому середовищі.
Арунас Джунвічус

2
OP не згадує версію mysql.
diEcho

2
@sinaza дивіться мою оновлену відповідь на MySQL 5.7.5+за змінену GROUP BYобробку
fyrye

3
Це не працює в режимі only_full_group_by, оскільки ні ID, ні LastName не є ні агрегованою, ні частиною функції групування. Довідка!
ihodonald

63

DISTINCTКлючове слово на самому ділі не працює так , як ви очікуєте його. Під час використання SELECT DISTINCT col1, col2, col3ви фактично вибираєте всі унікальні {col1, col2, col3} кортежі.


14
Дякуємо, що вказали на це Брайана. Чи можете ви навести приклад того, як я міг використовувати GROUP BY для отримання однакових результатів?
Містер

59

Щоб уникнути потенційно несподіваних результатів при використанні GROUP BYбез сукупної функції, як це використовується у прийнятій відповіді , оскільки MySQL може отримати будь-яке значення в групі наборів даних, коли не використовується сукупна функція [sic] та проблеми з ONLY_FULL_GROUP_BY. Подумайте про приєднання до виключення.

Приєднання до виключення - Однозначні сутності

Якщо припустити, що ім’я та прізвище є однозначно індексованими (однозначно) , альтернативою GROUP BYє сортування за допомогою LEFT JOINфільтрувати набір результатів, інакше відомий як виключення ПРИЄДНАЙТЕСЬ.

Див. Демонстрацію

Зростання порядку (AZ)

Для отримання виразного імені, упорядкованого за прізвищем від AZ

Запит

SELECT t1.*
FROM table_name AS t1
LEFT JOIN table_name AS t2
ON t1.firstname = t2.firstname
AND t1.lastname > t2.lastname
WHERE t2.id IS NULL;

Результат

| id | firstname | lastname |
|----|-----------|----------|
|  2 |      Bugs |    Bunny |
|  1 |      John |      Doe |

У порядку зменшення (ZA)

Для отримання виразного імені, упорядкованого за прізвищем від ZA

Запит

SELECT t1.*
FROM table_name AS t1
LEFT JOIN table_name AS t2
ON t1.firstname = t2.firstname
AND t1.lastname < t2.lastname
WHERE t2.id IS NULL;

Результат

| id | firstname | lastname |
|----|-----------|----------|
|  2 |      Bugs |    Bunny |
|  3 |      John |  Johnson |

Потім можна замовити отримані дані за бажанням.


Приєднання до виключення - неоднозначні особи

Якщо комбінація імені та прізвища не є унікальною (неоднозначною) і у вас є кілька рядків однакових значень, ви можете відфільтрувати набір результатів, включивши умову АБО за критеріями JOIN, щоб також фільтрувати за id.

Див. Демонстрацію

дані_імен таблиці

(1, 'John', 'Doe'),
(2, 'Bugs', 'Bunny'),
(3, 'John', 'Johnson'),
(4, 'John', 'Doe'),
(5, 'John', 'Johnson')

Запит

SELECT t1.*
FROM table_name AS t1
LEFT JOIN table_name AS t2
ON t1.firstname = t2.firstname
AND (t1.lastname > t2.lastname
OR (t1.firstname = t1.firstname AND t1.lastname = t2.lastname AND t1.id > t2.id))
WHERE t2.id IS NULL;

Результат

| id | firstname | lastname |
|----|-----------|----------|
|  1 |      John |      Doe |
|  2 |      Bugs |    Bunny |

Замовлений запит

EDIT

Моя оригінальна відповідь за допомогою впорядкованого підзапиту була написана до MySQL 5.7.5 , який більше не застосовується через зміни в ONLY_FULL_GROUP_BY. Будь ласка, використовуйте приклади приєднання для виключення вище.

Важливо також зазначити; коли ONLY_FULL_GROUP_BYвін відключений (оригінальна поведінка до MySQL 5.7.5) , використання GROUP BYбез сукупної функції може призвести до несподіваних результатів, оскільки MySQL може обирати будь-яке значення у групі наборів даних [sic] .

Значення a IDабо lastnameзначення може бути отримано, яке не пов'язане з отриманим firstnameрядком.


УВАГА

З MySQL GROUP BYможе не дати очікуваних результатів при використанні зORDER BY

Див. Приклад тестового випадку

Найкращий спосіб реалізації, щоб забезпечити очікувані результати, - це фільтрувати область набору результатів за допомогою упорядкованого підзапиту.

дані_імен таблиці

(1, 'John', 'Doe'),
(2, 'Bugs', 'Bunny'),
(3, 'John', 'Johnson')

Запит

SELECT * FROM (
    SELECT * FROM table_name ORDER BY ID DESC
) AS t1
GROUP BY FirstName

Результат

| ID | first |    last |
|----|-------|---------|
|  2 |  Bugs |   Bunny |
|  3 |  John | Johnson |

Порівняння

Щоб продемонструвати несподівані результати при використанні GROUP BYв поєднанні зORDER BY

Запит

SELECT * FROM table_name GROUP BY FirstName ORDER BY ID DESC

Результат

| ID | first |  last |
|----|-------|-------|
|  2 |  Bugs | Bunny |
|  1 |  John |   Doe |

3
Найповніша відповідь на сьогоднішній день. Зміна "ID desc" на "ID asc" у першому запиті дозволяє нам отримати "John Doe" або "John Johnson". Зміна 'опису ідентифікатора' у другому запиті не має цього ефекту.
carla

На postgres вам потрібен ідентифікатор у групі, не впевнений у mysql.
Сахін Прасад

Чи завжди стовпець GROUP BY-колонка ORDER BY-колонка B в одному операторі SELECT правильно працює з останньою версією MyriaDB?
Ніл Девіс

@NealDavis Відповідно до посібника MariaDBOrdering is done after grouping. , так Ні, не в цьому випадку використання, крім того MariaDB ігнорує ORDER BY у підзапитах (відповідно до стандарту SQL) без а LIMIT. Ви хочете скористатися. Window FunctionДля більш детального роз'яснення вам слід задати своє запитання в зміні stackexchange DBA , оскільки це питання, що стосується MySQL
fyrye

1
@NateS Ні, GROUP BYможе вибрати будь-яке значення в згрупованому наборі даних, за винятком випадків, коли функція сукупності не використовується в цих стовпцях для примушування певного значення. Так lastnameабо idможе походити з будь-якого з упорядкованих рядів. Оригінальний приклад запиту був прийнятним за замовчуванням, MySQL <= 5.7.4але технічно все ще страждає від проблеми. Хоча ORDER BYдійсно допомагає запобігти випадковому вибору, це все ще теоретично можливо, але зі значно меншою ймовірністю, ніж без використання ORDER BYпідзапиту.
fyrye



3

Як щодо

`SELECT 
    my_distinct_column,
    max(col1),
    max(col2),
    max(col3)
    ...
 FROM
    my_table 
 GROUP BY 
    my_distinct_column`

2

Не впевнений, чи можна це зробити за допомогою MySQL, але ви можете використовувати CTE в T-SQL

; WITH tmpPeople AS (
 SELECT 
   DISTINCT(FirstName),
   MIN(Id)      
 FROM People
)
SELECT
 tP.Id,
 tP.FirstName,
 P.LastName
FROM tmpPeople tP
JOIN People P ON tP.Id = P.Id

Інакше вам може знадобитися використовувати тимчасову таблицю.


1

Як зазначає fyrye , прийнята відповідь стосується старих версій MySQL, в яких ONLY_FULL_GROUP_BYще не було введено. З MySQL 8.0.17 (використовується в цьому прикладі), якщо ви не відключите, ONLY_FULL_GROUP_BYви отримаєте таке повідомлення про помилку:

mysql> SELECT id, firstName, lastName FROM table_name GROUP BY firstName;

ПОМИЛКА 1055 (42000): Вираз №1 у списку SELECT відсутній у пункті GROUP BY і містить неагреговану колонку 'mydatabase.table_name.id', яка функціонально не залежить від стовпців у пункті GROUP BY; це несумісно з sql_mode = only_full_group_by

Один із способів подолати це, не згаданий fyrye , але описаний у https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html , - застосувати ANY_VALUE()функцію до стовпців, які не в GROUP BYпункті ( idі lastNameв цьому прикладі):

mysql> SELECT ANY_VALUE(id) as id, firstName, ANY_VALUE(lastName) as lastName FROM table_name GROUP BY firstName;
+----+-----------+----------+
| id | firstName | lastName |
+----+-----------+----------+
|  1 | John      | Doe      |
|  2 | Bugs      | Bunny    |
+----+-----------+----------+
2 rows in set (0.01 sec)

Як написано у вищезгаданих документах,

У цьому випадку MySQL ігнорує недетермінізацію значень адреси всередині кожної групи імен та приймає запит. Це може бути корисно, якщо вам просто все одно, яке значення неагрегованого стовпця обрано для кожної групи. ANY_VALUE()не є сукупною функцією на відміну від функцій, таких як SUM()або COUNT(). Це просто діє, щоб придушити тест на недетермінізм.


Для уточнення я спеціально не рекомендував пропонувати використовувати, ANY_VALUE()оскільки моя відповідь та коментарі зосереджені на запобіганні неоднозначних та непередбачуваних наборів результатів. Оскільки, як випливає з назви функції, це може призвести до отримання будь-якого значення з вибраних рядків. Я б запропонував використовувати MAXабо MINзамість цього.
fyrye

0

Майте на увазі, коли ви використовуєте групу за порядком і упорядкуванням за цим MySQL - це ТІЛЬКА база даних, яка дозволяє використовувати стовпці в групі та / або впорядкувати по частинах, які не є частиною оператора select.

Так, наприклад: виберіть колонку1 з таблиці таблиці за стовпцем2, порядок за стовпцем3

Це не буде літати в інших базах даних, таких як Postgres, Oracle, MSSQL тощо. Ви повинні зробити наступне в цих базах даних

виберіть стовпчик1, стовпчик2, стовпчик3 із групи таблиць за порядком2 у порядку стовпця3

Будь-яка інформація, якщо ви коли-небудь переміщаєте свій поточний код до іншої бази даних або починаєте працювати в іншій базі даних і намагаєтеся повторно використовувати код.


-2

Ви можете використовувати групу для відображення різних значень, а також відповідних полів.

select * from tabel_name group by FirstName

Тепер ви отримали такий результат:

ID    FirstName     LastName
2     Bugs          Bunny
1     John          Doe


Якщо ви хочете відповісти, як

ID    FirstName     LastName
1     John          Doe
2     Bugs          Bunny

потім використовуйте цей запит,

select * from table_name group by FirstName order by ID

2
Це не завжди дасть очікувані результати при групуванні із замовленням
fyrye


-4
SELECT DISTINCT (column1), column2
FROM table1
GROUP BY column1

1
DISTINCT()не є функцією. Також DISTINCT та GROUP BY роблять те саме, тому жодна причина не ставить їх обох.
Marki555

Це не ефективна заява, ви повинні використовувати або DISTINCT, або групу By, не обидва.
heshanlk
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.