지정된 열의 값이 중복된 레코드 단위에서 첫 번째 항목만 추출합니다

페이지 업데이트 :
페이지 생성 날짜 :

일반적으로 중복 레코드를 하나만 추출 할 때 가장 먼저 떠오르 distinct 는 것은 다음과 같습니다. distinct 중복 열과 동시에 검색하려는 다른 열을 지정할 수 없습니다. 또한distinct 추출에 중복되지 않은 레코드가 포함되므로 이 요구 사항과 일치하지 않습니다.

제목만으로는 무엇을 하고 싶은지 알 수 없다고 생각하기 때문에, 샘플 레코드를 예로 들어 보겠습니다. 내가하고 싶은 것은 다음과 같은 추출 결과입니다.

ID 이름
1 이름 1
2 이름 2
3 이름 3
3 이름 3@example.com
4 이름 4 이름 4@example.com
4 이름 4@example.com
4 이름 4@example.com

다음과 같이 가져옵니다.

ID 이름
3 이름 3@example.com
4 이름 4@example.com

ID 1과 2는 중복되지 않으므로 포함되지 않습니다. ID 3과 4는 중복되므로 그 중 하나가 검색됩니다. 그러나 이번에는 DB 스토리지 순서에서 첫 번째 레코드를 가져오지 않습니다. 또한 "이름에 @ 표시가 포함되어 있음"및 "이름에 적은 수의 문자가 있음"이라는 조건에서 우선 순위에 따라 이름의 첫 번째 줄을 원한다고 가정합니다.

위의 조건은 다음 SQL을 사용하여 얻을 수 있습니다. 그러나 하위 쿼리를 사용하고 있으며 성능을 확인하지 않았습니다.

select
  *
from
  (select *, row_number() over(order by ID asc) as RowNum from SampleTable) tableMain
where tableMain.RowNum =
(
  select
    top(1) RowNum
  from
    (select *, row_number() over(order by ID asc) as RowNum from SampleTable) tableSub
  where
        tableMain.ID = tableSub.ID
    and exists ( 
      select
        *
      from
        SampleTable
      where
        tableSub.ID = ID
      having
        count(*) >= 2
    )
  order by
    case when charindex(N'@', Name) >= 1 then 0 else 1 end, len(Name)
)

중복 행은 및 count 로 확인됩니다having. group by 외부에서 확인해야 할 키 열, 여기서 ID 열은 로 좁혀집니다where.

첫 번째 행을 order by 검색하기 위한 우선 순위는 에 의해 지정됩니다. charindex len 여기에서 지정된 문자와 문자열의 길이가 포함되어 있는지 확인합니다. top 에서 각 중복 레코드의 첫 번째 행을 가져오기만 하면 됩니다.

원래는 괜찮지만 "ID: 4, Name: Name 4@example.com"와 같이 정확히 같은 값을 가진 레코드가 두 개 이상 있는 경우 필연적으로 두 개의 레코드를 얻게 됩니다. row_number 따라서 를 사용하여 각 행에 대해 식별할 수 있도록 추가되므로 정확히 동일한 값을 가진 하나의 레코드만 검색할 수 있습니다. 정확히 동일한 레코드가 존재하지 row_number 않는 것으로 알려진 경우 를 추가하지 않고 기존 레코드의 값을 확인하는 것이 더 낫다고 생각합니다.

중복 여부를 확인해야 할 키가 여러 개 있는 경우 각각에 대한 키 열 수를 늘릴 수 있습니다. 예를 들어 다음 레코드를 고려합니다. 중복 여부를 확인할 열은 "ID1"과 "ID2"입니다.

ID1 ID2 이름
1 1 이름 1
2 1 이름 2
3 1 이름 31
3 2 이름 32
4 1 이름41
4 2 이름42
4 2 이름 4@example.com
5 1 이름 555@example.com
5 1 이름 55@example.com
5 2 이름 5@example.com
6 1 이름 6
6 1 이름 66@example.com
6 2 이름 6
6 2 이름 6

취득 결과는 다음과 같습니다.

ID1 ID2 이름
4 2 이름 4@example.com
5 1 이름 55@example.com
6 1 이름 66@example.com
6 2 이름 6

SQL은 다음과 같습니다. 키 열이 지정된 부분을 간단히 늘릴 수 있습니다.

select
  *
from
  (select *, row_number() over(order by ID1 asc, ID2 asc) as RowNum from SampleTable) tableMain
where tableMain.RowNum =
(
  select
    top(1) RowNum
  from
    (select *, row_number() over(order by ID1 asc, ID2 asc) as RowNum from SampleTable) tableSub
  where
        tableMain.ID1 = tableSub.ID1
    and tableMain.ID2 = tableSub.ID2
    and exists ( 
      select
        *
      from
        SampleTable
      where
            tableSub.ID1 = ID1
        and tableSub.ID2 = ID2
      having
        count(*) >= 2
    )
  order by
    case when charindex(N'@', Name) >= 1 then 0 else 1 end, len(Name)
)