2010-06-21 4 views
0

나는 (있는 것 같다) 아주 쉬운 문제이지만 몇 시간 동안 검색 한 후에 도움이되는 것을 찾을 수 없다."그룹화"쿼리에서 그룹당 전체 행을 하나만 선택하는 방법은 무엇입니까?

가 여기에 문제의 : 마이크로 소프트 SQL에서

, 나는 테이블이 경우 열 저장 일부 데이터를. 이 데이터는 중복을 포함 할 수 있습니다 (즉, 두 개 이상의 행은 열 에 대해 동일한 값을가집니다).

내가 쉽게 중복 by doing 찾을 수 있습니다

select A, count(A) as CountDuplicates 
from TableName 
group by A having (count(A) > 1) 

지금, 내가 다른 컬럼의 값을 검색하려면, 이제 BC을 가정 해 봅시다. 물론 B 및 값은 동일한 값을 공유하는 행에 대해서도 다를 수 있지만 나에게는 아무런 문제가되지 않습니다. 나는 단지 B 값과 어떤 C 하나, 첫 번째, 마지막 또는 임의의 것을 원한다. , 문제는 내가 얻을 수있는 더 많은 행을 가지고 있고, 테이블이 매우 큰 것입니다

select A, count(A) as CountDuplicates, (
    select top 1 child.B from TableName as child where child.A = base.A) as B 
) 
from TableName as base group by A having (count(A) > 1) 

:

나는 내가 좋아하는 일을 할 것, 검색 할 수있는 작은 테이블 하나 또는 두 개의 열이 있다면 그래서 몇몇 아이들을 선택하는 것은 높은 성능 비용을 가질 것입니다.

그래서이 작업을 수행하는 추악한 순수 SQL 솔루션이 있습니까?


내 질문에 충분히 분명하다, 그래서 의 AdventureWorks 데이터베이스를 기반으로 예를 들어 줄 경우 확실하지. 가용 상태를 나열하고 각 주마다 코드, 도시 (도시) 및 주소 (주소)를 나열하고자한다고 가정 해 봅시다. LINQ - 투 - SQL에서

var q = from c in data.StateProvinces select new { c.StateProvinceCode, c.Addresses.First().City, c.Addresses.First().AddressLine1 }; 

181 개 국가의 각각에 대해 두 가지 선택, 그래서 363 선택을 할 것입니다 : 가장 쉬운, 그리고 할 수있는 가장 비효율적 인 방법이 될 것이다. 저의 경우, 최대 182 개의 선택을하는 방법을 찾고 있습니다.

답변

0

당신은

select id,b,c from tablename 
inner join 
(
select id, count(A) as CountDuplicates 
from TableName as base group by A,id having (count(A) > 1) 
)d on tablename.id= d.id 
+0

Downvote - 나는 당신이 처음부터 대답을 총으로 쏜 것에 유죄라고 생각합니다. 분명히이 코드는 "form"과 "innet join"이라고 말하기 때문에 테스트하지 않았습니다. 또한, A가 고유 한 키 (그러나 기본 키가 아니라)에 의존한다는 사실은 그것을 나쁜 일반적인 해결책으로 만듭니다. –

+0

ans updated now ... 정보 주셔서 감사합니다 –

4

필드 b 및 c에 대한 이전 값을 원한다고 걱정됩니다. 그들이 무의미하다면 왜 당신은 그들을 돌려 보내고 있습니까?

진정으로 중요하지 않은 경우 (솔직히 내가 원하는 것을 상상할 수는 없지만 당신이 말한 것이지만) b 및 c의 값은 동일한 기록, 그룹은 월 또는 최대의 사용과 함께 갈 방법입니다. 모든 필드에 대해 특정 레코드의 값을 원하면 더 복잡합니다. 당신이 당신의 테이블에 기본 키 ID가있는 경우

select A, count(A) as CountDuplicates, min(B) as B , min(C) as C 
from TableName as base 
group by A 
having (count(A) > 1) 
+0

좋아, 작동 할 수도 있습니다. 그건 그렇고, 무의미하다고 말하고 싶었던 것은 동일한 행 그룹 내에서는 중요하지 않다는 것입니다. 이 데이터를 사용하여 * 중복 된 내용과 얼마나 많은 양의 * 힌트 *를 갖습니다. –

+1

올바르지 않을 수 있습니다. 반환 된 B와 C는 잠재적으로 서로 관련이 없습니다. 서로 다른 레코드에서 올 수 있습니다. A 중 하나를 나타내는 임의의 레코드를 반환하지 않았지만 두 개의 다른 A의 파편을 반환했습니다. –

+0

그리고 나는 그 대답에 그렇게 할 것이라고 말했습니다. 포스터 그 자신은 값이 중요하지 않다고 말했다. – HLGEM

10

CTE를의 ROW_NUMBER 기능이 작업을 수행 할 수있는 방법은 다음과 같이 몇 가지 일을 할 수 있습니다.예를 들면 : 나는 HLGEM 필립 켈리, 반드시 각 그룹에 대해 하나의 "고체"레코드를 반환하지 않습니다 집계 함수의 자신의 간단한 사용에 대한 내 댓글에서 언급 한 바와 같이

DECLARE @mytab TABLE (A INT, B INT, C INT) 
INSERT INTO @mytab (A, B, C) VALUES (1, 1, 1) 
INSERT INTO @mytab (A, B, C) VALUES (1, 1, 2) 
INSERT INTO @mytab (A, B, C) VALUES (1, 2, 1) 
INSERT INTO @mytab (A, B, C) VALUES (1, 3, 1) 
INSERT INTO @mytab (A, B, C) VALUES (2, 2, 2) 
INSERT INTO @mytab (A, B, C) VALUES (3, 3, 1) 
INSERT INTO @mytab (A, B, C) VALUES (3, 3, 2) 
INSERT INTO @mytab (A, B, C) VALUES (3, 3, 3) 
;WITH numbered AS 
(
    SELECT *, rn=ROW_NUMBER() OVER (PARTITION BY A ORDER BY B, C) 
     FROM @mytab AS m 
) 
SELECT * 
    FROM numbered 
    WHERE rn=1 

; 대신, 많은 개별 행에서 열 값을 반환 할 수 있으며, 모두 단일 레코드 인 것처럼 연결됩니다. 예를 들어 PersonID가 "A"열이고 별개의 연락처 레코드 (예 : 집 및 단어) 인 PERSON 테이블 인 경우 사람의 집 도시는 반환하지만 사무실 우편 번호는 - 그리고 그것은 분명히 문제를 요구하고 있습니다.

여기에서 CTE와 함께 ROW_NUMBER를 사용하면 구문이 어색하기 때문에 처음에는 익숙해지기가 약간 어려울 수 있습니다. 그러나 꽤 일반적인 패턴이되어 가고 있기 때문에 잘 알고있는 것이 좋습니다.

필자는 A 열로 그룹화 한 테이블에 추가 열 rn ("행 번호"표시)을 추가하는 CTE를 정의했습니다. A 결과가 SELECT 인 경우 행 번호가 1 인 레코드 (즉, 해당 A 값에 대해 첫 번째 레코드가 발견됨)로 필터링하면 각 A 그룹에 대해 "솔리드"레코드가 반환됩니다. 위의 예에서 직장 또는 집 주소 중 하나를 가져오고 둘 다 함께 섞어서는 안됩니다.

+1

N 행을 사용할 수있는 모든 레코드를 선택하기 위해 하단의 where 절을 변경할 수 있으므로이 방법은 간단합니다. 즉 n = 3'WHERE rn = 3' – scaryman

관련 문제