Как выбрать уникальные записи по SQL


88

Когда я выполняю «SELECT * FROM table», я получаю такие результаты, как показано ниже:

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

Как видите, есть дублированные записи из столбца 2 (элемент 1 дублируется). Итак, как я мог просто получить такой результат:

1 item1 data1
2 item2 data3
3 item3 data4

Из дубликата возвращается только одна запись вместе с остальными уникальными записями.


Пункт 1 технически не дублируется. Как показано, строки 1 и 2 представляют собой уникальные наблюдения. Что, если вы хотите сохранить строку 2, а не строку 1?
Cybernetic,

Ответы:


105

С distinctключевым словом с одним или несколькими именами столбцов вы получаете отдельные записи:

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

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

26

Если вам нужно только удалить дубликаты, используйте DISTINCT. GROUP BYследует использовать для применения агрегатных операторов к каждой группе

GROUP BY v DISTINCT


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: ГРУППА ПО

Группировка позволяет добавлять агрегированные данные, как и 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 (), разделенный по столбцу группы и упорядоченный в желаемом порядке. Затем ВЫБЕРИТЕ только те записи, которые имеют 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;

Это ответ на другой вопрос, вероятно, тот, который следует пометить с наибольшим
числом

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

1

Я считаю, что если я не могу использовать DISTINCT по какой-либо причине, то GROUP BY будет работать.


1

Чтобы получить все столбцы в вашем результате, вам нужно разместить что-то как:

SELECT distinct a, Table.* FROM Table

он поместит a в качестве первого столбца, а остальные будут ВСЕ столбцы в том же порядке, что и ваше определение. То есть столбец а будет повторяться.


1
Ты уверен насчет этого? Я пробовал это на w3schools, и он вернул то же самое, что и SELECT *, за исключением того, что a был первым столбцом
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.