SQL로 고유 한 레코드를 선택하는 방법


87

"SELECT * FROM table"을 수행하면 다음과 같은 결과가 나타납니다.

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

보시다시피 column2의 dup 레코드가 있습니다 (item1은 dupped). 그래서 어떻게하면 다음과 같은 결과를 얻을 수 있습니까?

1 item1 data1
2 item2 data3
3 item3 data4

나머지 고유 레코드와 함께 중복에서 하나의 레코드 만 반환됩니다.


항목 1은 기술적으로 중복되지 않습니다. 표시된대로 1 행과 2 행은 고유 한 관측치입니다. 행 1이 아닌 행 2를 유지하려면 어떻게해야합니까?
사이버 네틱

답변:


105

distinct단일 및 다중 열 이름 이있는 키워드를 사용하면 고유 한 레코드를 얻을 수 있습니다.

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

14
대답이 실제로 잘못되었을 수 있습니까? DISTINCT는 선택한 모든 열 (적어도 DB2에서)에 적용되며 개별 열에서 중복 값을 계속 반환합니다.
Konstantin

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. ROW_NUMBER ()를 사용하는 CTE (공통 테이블 식)

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 : DISTINCT 선택

이것은 가장 간단하고 간단하지만 가장 제한적인 방법이기도합니다.

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 (Common Table Expression)에서 그룹 열로 분할되고 원하는 순서로 정렬 된 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;

그건 아마도, 태그해야 하나 다른 질문에 대한 답변입니다 가장 큰-N 당 그룹
a_horse_with_no_name

이것과 Dave Baker의 솔루션은 SO 질문에 대한 올바른 솔루션입니다. 이 솔루션의 장점은 일부 지정된 고유 열만있는 행을 선택할 수 있고 여러 지정된 열 중 하나만 선택하려면 하나의 열 MIN (id) AS id를 정의해야한다는 것입니다.
giordano

1

어떤 이유로 든 DISTINCT를 사용할 수 없으면 GROUP BY가 작동합니다.


1

결과의 모든 열을 얻으려면 다음과 같이 배치해야합니다.

SELECT distinct a, Table.* FROM Table

a 를 첫 번째 열로 배치 하고 나머지는 정의와 동일한 순서로 모든 열이됩니다. 즉, 열 a 가 반복됩니다.


1
이거 확실하니? 나는 w3schools에서 이것을 시도했고 그것은 SELECT *와 같은 것을 반환했다. 단, a는 첫 번째 열이었다
Freakishly

@Freakishly yes 그리고 그것이 내 대답에서 할 것이라고 정확히 말한 것입니다 : /
htafoya

작동하지 않습니다. *를 선택할 수 없습니다 (1064 오류-SQL 구문에 오류가 발생합니다)
tim.baker

@Mohsinkhan 잘 나는 당신이 테이블 이름을 쓸 필요가 있다는 것을 잊었다. 어떻게 든 내가 이것을 썼을 때 그것은 효과가 있었지만 지금은 방금 테스트했고 * 앞에 테이블 이름이 없었습니다.
htafoya

2
이 정확히 동일하다select distinct * from ...
a_horse_with_no_name

-4

Eff_st from (select EFF_ST, ROW_NUMBER () over (PARTITION BY eff_st) XYZ-from ABC.CODE_DIM

) 여기서 XYZ = EFF_ST에 의한 1 주문은 처음 5 개 행만 가져옵니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.