Як вибрати унікальні записи за допомогою SQL


87

Коли я виконую "SELECT * FROM table", я отримую результати, як показано нижче:

1 item1 data1
2 item1 data2
3 item2 data3
4 item3 data4

Як бачите, є записи dup з стовпця2 (item1 дублюються). Тож як я міг просто отримати такий результат:

1 item1 data1
2 item2 data3
3 item3 data4

З дубліката повертається лише один запис разом з рештою унікальних записів.


Пункт 1 технічно не повторюється. Як показано, рядки 1 і 2 є унікальними спостереженнями. Що робити, якщо ви хочете зберегти рядок 2, а не рядок 1?
Кібернетичний

Відповіді:


105

За допомогою distinctключового слова з одним і кількома іменами стовпців ви отримуєте різні записи:

SELECT DISTINCT column 1, column 2, ...
FROM table_name;

14
Чи може бути, що відповідь насправді неправильна? DISTINCT застосовується до всіх вибраних стовпців (принаймні в DB2), які все одно повертатимуть повторювані значення в окремих стовпцях.
Костянтин


11

Це залежить від того, яку роуну ви хочете повернути за кожен унікальний предмет. Здається, ваші дані вказують мінімальне значення даних, тому в цьому випадку для SQL Server.

SELECT item, min(data)
FROM  table
GROUP BY item

10

Є 4 методи, якими ви можете скористатися:

  1. ВІДМІНЕННЯ
  2. ГРУПА ЗА
  3. Підзапит
  4. Загальний вираз таблиці (CTE) з ROW_NUMBER ()

Розглянемо наступний зразок TABLEіз даними тестів:

/** Create test table */
CREATE TEMPORARY TABLE dupes(word text, num int, id int);

/** Add test data with duplicates */
INSERT INTO dupes(word, num, id)
VALUES ('aaa', 100, 1)
      ,('bbb', 200, 2)
      ,('ccc', 300, 3)
      ,('bbb', 400, 4)
      ,('bbb', 200, 5)     -- duplicate
      ,('ccc', 300, 6)     -- duplicate
      ,('ddd', 400, 7)
      ,('bbb', 400, 8)     -- duplicate
      ,('aaa', 100, 9)     -- duplicate
      ,('ccc', 300, 10);   -- duplicate

Варіант 1: ВИБЕРІТЬ ВИЗНАЧЕННЯ

Це найпростіший і прямий вперед, але також і найбільш обмежений спосіб:

SELECT DISTINCT word, num 
FROM    dupes
ORDER BY word, num;

/*
word|num|
----|---|
aaa |100|
bbb |200|
bbb |400|
ccc |300|
ddd |400|
*/

Варіант 2: GROUP BY

Угруповання дозволяє додавати агреговані дані, як і min(id), max(id), count(*)і т.д .:

SELECT  word, num, min(id), max(id), count(*)
FROM    dupes
GROUP BY word, num
ORDER BY word, num;

/*
word|num|min|max|count|
----|---|---|---|-----|
aaa |100|  1|  9|    2|
bbb |200|  2|  5|    2|
bbb |400|  4|  8|    2|
ccc |300|  3| 10|    3|
ddd |400|  7|  7|    1|
*/

Варіант 3: Підзапит

Використовуючи підзапит, ви можете спочатку визначити повторювані рядки, які потрібно ігнорувати, а потім відфільтрувати їх у зовнішньому запиті за допомогою WHERE NOT IN (subquery)конструкції:

/** Find the higher id values of duplicates, distinct only added for clarity */
    SELECT  distinct d2.id
    FROM    dupes d1
        INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
    WHERE d2.id > d1.id

/*
id|
--|
 5|
 6|
 8|
 9|
10|
*/

/** Use the previous query in a subquery to exclude the dupliates with higher id values */
SELECT  *
FROM    dupes
WHERE   id NOT IN (
    SELECT  d2.id
    FROM    dupes d1
        INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
    WHERE d2.id > d1.id
)
ORDER BY word, num;

/*
word|num|id|
----|---|--|
aaa |100| 1|
bbb |200| 2|
bbb |400| 4|
ccc |300| 3|
ddd |400| 7|
*/

Варіант 4: Загальний вираз таблиці з ROW_NUMBER ()

У виразі загальної таблиці (CTE) виберіть РЯДОК НОМЕР (), розділений стовпцем групи та упорядкований у бажаному порядку. Потім ВИБЕРІТЬ лише ті записи, які містять ROW_NUMBER() = 1:

WITH CTE AS (
    SELECT  *
           ,row_number() OVER(PARTITION BY word, num ORDER BY id) AS row_num
    FROM    dupes
)
SELECT  word, num, id 
FROM    cte
WHERE   row_num = 1
ORDER BY word, num;

/*
word|num|id|
----|---|--|
aaa |100| 1|
bbb |200| 2|
bbb |400| 4|
ccc |300| 3|
ddd |400| 7|
*/

6

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

SELECT a.*
FROM yourtable a
INNER JOIN 
  (SELECT yourcolumn,
    MIN(id) as id
  FROM yourtable 
  GROUP BY yourcolumn
) AS b
  ON a.yourcolumn= b.yourcolumn
  AND a.id = b.id;

Це відповідь на інше запитання, мабуть, на те, яке слід позначити як
most

Це та рішення Дейва Бейкера є правильними рішеннями для питання SO. Перевага цього рішення полягає в тому, що воно дозволяє виділяти рядки лише з деякими визначеними окремими стовпцями, і один стовпець MIN (id) AS id повинен бути визначений, щоб вибрати лише один із декількох вказаних стовпців.
Джордано

1

Я вважаю, що якщо я не можу використовувати DISTINCT з будь-якої причини, тоді GROUP BY буде працювати.


1

Щоб отримати всі стовпці результату, потрібно розмістити щось на зразок:

SELECT distinct a, Table.* FROM Table

він розмістить а як перший стовпець, а решта - ВСІ стовпці в тому ж порядку, що і ваше визначення. Тобто стовпець а буде повторений.


1
Ви впевнені в цьому? Я спробував це на w3schools, і воно повернуло те саме, що і SELECT *, за винятком того, що це була перша колонка
Freakishly

@Freakishly так, і саме це говорить, що це буде робити у моїй відповіді: /
htafoya

Це не буде працювати, ви не можете вибрати * після такого відмінного (ви отримаєте помилку 1064 - Помилка у вашому синтаксисі SQL)
tim.baker

@Mohsinkhan ну, я забув помістити, що вам потрібно написати назву таблиці. Якось, коли я це написав, це спрацювало, але я щойно тестував, і це не обійшлося без назви таблиці до *
htafoya

2
Це точно так само, якselect distinct * from ...
a_horse_with_no_name

-4

Виберіть Eff_st з (виберіть EFF_ST, ROW_NUMBER () над (PARTITION BY eff_st) XYZ - з ABC.CODE_DIM

) де XYZ = 1 замовлення EFF_ST отримати лише перші 5 рядків

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