하나의 열에 대해서만 DISTINCT


155

다음과 같은 쿼리가 있다고 가정 해 봅시다.

SELECT ID, Email, ProductName, ProductModel FROM Products

중복 이메일을 반환하지 않도록 수정하려면 어떻게해야합니까?

즉, 여러 행에 동일한 전자 메일이 포함 된 경우 결과에 해당 행 중 하나만 (바람직하게는 마지막 행) 만 포함 시키려고합니다. 다른 열에는 중복이 허용되어야합니다.

절 은 전체 행에서 좋아 DISTINCT하고 GROUP BY작동하는 것으로 보입니다. 그래서 어떻게 접근 해야할지 모르겠습니다.


2
좋아, PARTITION을 사용하거나 두 개의 select 문을 사용해야합니까?
CarneyCode

이메일이 같지만 ProductName이 다른 두 개의 행이 있으면 어떻게 표시되어야합니까? (바람직 마지막은) 분명하지 않다. 어떤 순서로 마지막에?
ypercubeᵀᴹ

@ypercube 질문에 언급 된 바와 같이, 바람직하게는 마지막 것. 그러나 그것은 나에게 정말로 중요하지 않습니다. 나는 그들 중 하나를 원한다.
Jonathan Wood

1
question1 , question2 또는 question3 질문을 볼 수 있습니다 .
Marian

SELECT DISTINCT Email, ID, ProductName, ProductModel FROM Products를 사용할 수없는 이유는 무엇입니까?
Rick Henderson

답변:


186

SQL Server 2005 이상을 사용하는 경우 다음을 사용하십시오.

SELECT *
  FROM (
                SELECT  ID, 
                        Email, 
                        ProductName, 
                        ProductModel,
                        ROW_NUMBER() OVER(PARTITION BY Email ORDER BY ID DESC) rn
                    FROM Products
              ) a
WHERE rn = 1

편집 : where 절을 사용하는 예 :

SELECT *
  FROM (
                SELECT  ID, 
                        Email, 
                        ProductName, 
                        ProductModel,
                        ROW_NUMBER() OVER(PARTITION BY Email ORDER BY ID DESC) rn
                    FROM Products
                   WHERE ProductModel = 2
                     AND ProductName LIKE 'CYBER%'

              ) a
WHERE rn = 1

4
이 PARTITION 절을 조사해야하며 이전에는 실제로 본 적이 없습니다. 예를 들어 주셔서 감사합니다
LorenVS

@Cybernate 하나의 합병증 : 내 내부 SELECT에는 WHERE조건이 필요합니다 . 행 번호가 테이블의 모든 행에 할당 될 것이라고 생각합니다. 이 문법은 저를 약간 넘어선 것입니다. WHERE조건 을 충족하는 특정 전자 메일로 한 행을 보장하는 업데이트 기회가 있습니까?
Jonathan Wood

1
내부 SQL에 where 절을 추가 할 수 있습니다. 노트북에 액세스 할 수있게되면 게시물을 업데이트하겠습니다
Chandu

1
where 절을 사용하여 샘플로 게시물을 업데이트했습니다.
찬두

1
내 쿼리에 s 가 없을 때만 올바르게 작동합니다 JOIN. 즉시 나는이로 JOINROW_NUMBER반환 "1"보다 훨씬 높은 값.
Uwe Keim

10

이것은 SQL Server 2005+를 가정하고 "마지막"에 대한 정의는 주어진 전자 메일의 최대 PK입니다

WITH CTE AS
(
SELECT ID, 
       Email, 
       ProductName, 
       ProductModel, 
       ROW_NUMBER() OVER (PARTITION BY Email ORDER BY ID DESC) AS RowNumber 
FROM   Products
)
SELECT ID, 
       Email, 
       ProductName, 
       ProductModel
FROM CTE 
WHERE RowNumber = 1

6

사용할 때 DISTINCT열이 아닌 별도의 행으로 생각하십시오. 열이 정확히 일치하지 않는 행만 반환합니다.

SELECT DISTINCT ID, Email, ProductName, ProductModel
FROM Products

----------------------
1 | something@something.com | ProductName1 | ProductModel1
2 | something@something.com | ProductName1 | ProductModel1

쿼리는 두 행을 모두 반환하므로 ID열이 다르기 . 열이 증가 ID하는 IDENTITY열 이라고 가정 하고 마지막을 반환하려면 다음과 같이 권장합니다.

SELECT DISTINCT TOP 1 ID, Email, ProductName, ProductModel
FROM Products
ORDER BY ID DESC

TOP 1순서대로 정렬하여 첫 번째 레코드 만 반환합니다.ID 먼저 마지막 행으로 결과를 반환합니다 내림차순. 이것은 당신에게 마지막 기록을 줄 것입니다.


2
질문에서 언급했듯이 DISTINCT는 전체 행에서 작동합니다. 위에서 제안한 것처럼하고 싶지만 매번 이메일이 결과에 중복됩니다 (단 한 번이 아님).
Jonathan Wood

이 경우 @Cybernate 답변을 사용하는 것이 좋습니다. 그것은 당신이 원하는 것을 정확하게해야합니다.
jon3laze

4

GROUP BY 기능을 사용하여이를 극복 할 수 있습니다

SELECT ID, Email, ProductName, ProductModel FROM Products GROUP BY Email


16
'Products.ID'열은 집계 함수 또는 GROUP BY 절에 포함되지 않으므로 선택 목록에서 유효하지 않습니다.
palota

2
다른 열에 MAX (ID), MAX (ProductName), MAX (ProductModel)와 같은 것을 사용하지 않으면 작동하지 않습니다
avl_sweden

2
postgres에서는 group by 절에서 사용될 열에 집계 함수 만 필요합니다 (예 :) SELECT id, max(email) AS email FROM tbl GROUP by email. SQL Server에서 SELECT절의 모든 열 은 집계 함수에 있어야합니다. 내가 돌아갈 때마다 이것은 나를 물린다.
브루스 피어슨

이것은 작동하지 않습니다. 나쁜 해결책입니다
Dan AS

1

Access의 경우 여기에 표시된 SQL Select 쿼리를 사용할 수 있습니다.

예를 들어이 테이블이 있습니다.

클라이언트 || NOMBRES || 우편

888 || T800 아놀드 || t800.arnold@cyberdyne.com

123 || 존 코너 || s.connor@skynet.com

125 || SARAH CONNOR ||s.connor@skynet.com

그리고 다른 메일 만 선택해야합니다. 당신은 이것을 할 수 있습니다 :

SQL 선택 :

SELECT MAX(p.CLIENTE) AS ID_CLIENTE
, (SELECT TOP 1 x.NOMBRES 
    FROM Rep_Pre_Ene_MUESTRA AS x 
    WHERE x.MAIL=p.MAIL 
     AND x.CLIENTE=(SELECT MAX(l.CLIENTE) FROM Rep_Pre_Ene_MUESTRA AS l WHERE x.MAIL=l.MAIL)) AS NOMBRE, 
p.MAIL
FROM Rep_Pre_Ene_MUESTRA AS p
GROUP BY p.MAIL;

이를 사용하여 최대 ID를 선택하고 해당 최대 ID에 해당하는 이름을 선택하면 다른 속성을 추가 할 수 있습니다. 그런 다음 끝에 고유 열을 필터링하고 마지막 고유 열로만 그룹화합니다.

이렇게하면 해당 데이터가 포함 된 최대 ID가 표시되며 min 또는 다른 함수를 사용할 수 있으며 해당 함수를 하위 쿼리에 복제 할 수 있습니다.

이 선택은 다음을 반환합니다 :

클라이언트 || NOMBRES || 우편

888 || T800 아놀드 || t800.arnold@cyberdyne.com

125 || SARAH CONNOR ||s.connor@skynet.com

선택한 열을 인덱싱해야하며 고유 열에는 모두 대문자 나 소문자로 숫자 데이터가 없어야합니다. 그렇지 않으면 작동하지 않습니다. 이것은 하나의 등록 된 메일에서만 작동합니다. 행복한 코딩 !!!


0

이유 DISTINCTGROUP BY전체 행에 작업은 쿼리가 전체 행을 반환하기 때문입니다.

이해하기 쉽도록 : 쿼리가 리턴해야하는 내용을 손으로 작성해보십시오. 중복되지 않은 열에 넣을 내용이 모호하다는 것을 알 수 있습니다.

문자 그대로 다른 열의 내용을 신경 쓰지 않으면 반환하지 마십시오. 각 이메일 주소에 대해 임의의 행을 반환하면 약간 쓸모없는 것 같습니다.


@ JohnFix 전체 행을 반환하고 싶습니다. 결과에 전자 메일 열에 동일한 값을 가진 행이 이미 포함되어 있으면 행이 반환되는 것을 원하지 않습니다.
Jonathan Wood

그렇다면 어느 것을 돌려 줄지 어떻게 결정해야합니까? 각 전자 메일에 대해 임의의 행을 반환하는 쿼리를 원하십니까? 이것은 당신이 해결하려는 문제를 다시 생각해야 할 것 같은 냄새가납니다. 거의 내가이 질문을 받았을 때마다 (그리고 많이 나옵니다) 개발자 가이 행동에 대한 응용 프로그램의 결과를 생각하지 않았다는 것이 밝혀졌습니다.
JohnFx

6
나는 당신의 논리를 따르는 데 정말로 어려움을 겪고 있습니다. 질문에 명시된 바와 같이 마지막 ID를 선호합니다 (ID별로 정렬). 예, 임의의 행을 선택하면 괜찮습니다. 그리고 네, 그것에 대해 생각했습니다.
Jonathan Wood

0

이 시도

;With Tab AS (SELECT DISTINCT Email FROM  Products)
SELECT Email,ROW_NUMBER() OVER(ORDER BY Email ASC) AS  Id FROM Tab
ORDER BY Email ASC

-2

이 시도:

SELECT ID, Email, ProductName, ProductModel FROM Products WHERE ID IN (SELECT MAX(ID) FROM Products GROUP BY Email)

2
왜 이것을 시도해야합니까? 지난 8 년 동안 여기에 게시 된 다른 답변보다 더 나은 이유는 무엇입니까? 문제를 해결하는 더 좋은 방법을 공유하려면 권장 이유를 설명해야합니다.
Dharman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.