2013-02-20 3 views
0

서버 측 코드에서 사용자 이름 필드의 대소 문자가 구분되어 실수로 데이터가 여러 번 저장된 데이터를 저장하는 테이블이 있습니다. 사용자 이름 필드는 대소 문자를 구분하지 않아야합니다. 표의 중요한 열과 데이터는 아래에서 확인할 수 있습니다.SQL 서버의 두 열을 기반으로 행 선택

내 요구 사항은 최근 저장된 데이터를 제외한 모든 데이터를 삭제하는 것입니다. 이를 위해 sql 스크립트를 작성하고 중복 된 모든 행을 식별하여 시작했습니다. 이 선택은 아래와 같은 테이블을 반환합니다.

각 행에 대해 가장 최근의 저장은 존재하는 경우 LASTUPDATEDDATE이고 그렇지 않은 경우 CREATEDDATE입니다. 이 예를 들어, 가장 최근은 행을 것 '사용자 이름'에 대한 저장 3.

 
ID CREATEDDATE LASTUPDATEDDATE USERNAME       
-- ----------- --------------- -------- 
1 11-NOV-11     USERNAME         
2 01-NOV-11 02-NOV-11  username        
3 8-JAN-12     USERname  

내 스크립트 (중복 된 이름이 나타납니다 모든 행을 선택하는)과 같이 보인다 : 지금


SELECT 
    id, createddate, lastupdateddate, username 
FROM 
    table 
WHERE 
    LOWER(username) 
IN 
    (
    SELECT 
     LOWER(username) 
    FROM 
     table 
    GROUP BY 
     LOWER(username) 
    HAVING 
     COUNT(*) > 1 
) 
ORDER BY 
    LOWER(username) 

내 질문 is : 행 3을 제외한 모든 것을 어떻게 선택합니까?이 질문에 대한 좋은 일치를 위해 Stack Overflow를 검색했지만 충분히 일치하는 항목이 없습니다. 나는 아마 어떤 종류의 조인을해야만한다는 것을 알지만, 정말로 그것에 대해 내 머리를 맞을 수는 없습니다. 올바른 방향으로 밀고 나가는 것에 정말로 감사 할 것입니다.

우리는 아마도 아주 새로운 버전의 SQL Server를 사용하고 있습니다.

답변

1

사용할 수있는 중복을 삭제하려면 :

with todelete as (
    select t.*, 
      row_number() over (partition by lower(username) order by createddate desc) as seqnum 
    from table 
    ) 
delete from t 
where seqnum > 1 

이 가장 최근의 1을 시작으로 각 행에 일련 번호를 지정합니다. 그런 다음 가장 최근의 것을 제외하고 모두 삭제합니다.

두 날짜를 들어, 사용할 수 있습니다

with todelete as (
    select t.*, 
      row_number() over (partition by lower(username) order by thedate desc) as seqnum 
    from (select t.*, 
        (case when createddate >= coalesdce(updateddate, createddate) 
         then createddate 
         else updateddate 
        end) as thedate 
      from table 
     ) t 
    ) 
delete from t 
where seqnum > 1 
1

몇 가지를주의하는 것이 - 귀하의 요청에 LOWER를 사용할 이유가 없다. SQL Server에서 A = a.

올바른 날짜를 얻으려면 COALESCE을 사용하여 LastUpdatedDate가 있는지 확인하고, 그렇다면 그 날짜별로 정렬하고, 그렇지 않으면 CreatedDate로 정렬 할 수 있습니다.

함께 그 퍼팅이 작동합니다 : 여기

DELETE T 
FROM YourTable T 
    JOIN (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY username 
        ORDER BY COALESCE(lastupdateddate, createddate) DESC) as RN 
    FROM YourTable 
    ) T2 ON T.Id = T2.Id 
WHERE T2.RN > 1 

이 샘플 바이올린입니다 : http://www.sqlfiddle.com/#!3/51f7c/1

@Gordon이 제대로 알 수 있듯이, 당신은 또한 CTE는 SQL Server의 버전에 따라 사용할 수 있습니다 당신 사용 (2005+) :

WITH CTE AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY username 
           ORDER BY COALESCE(lastupdateddate, createddate) DESC) as RN 
    FROM YourTable 
    ) 
DELETE FROM CTE WHERE RN > 1 
관련 문제