중복 행을 어떻게 제거합니까?


1285

상당히 큰 SQL Server테이블 에서 중복 행을 제거하는 가장 좋은 방법은 무엇입니까 (예 : 300,000+ 행)?

물론 행은 RowIDID 필드 의 존재로 인해 완벽한 복제본이 아닙니다 .

MyTable

RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null

13
PostgreSQL 사용자 가이 정보를 읽는 빠른 팁 (많은 빈도로 연결됨) : Pg는 CTE 용어를 업데이트 가능한 뷰로 표시하지 않으므로 DELETE FROMCTE 용어를 직접 사용할 수 없습니다 . stackoverflow.com/q/18439054/398670
Craig Ringer

동일 마찬가지입니다 @CraigRinger 베이스 - 내가 여기 남아있는 솔루션을 수집 (도, PG 및 다른 사람을위한 유효해야합니다 : stackoverflow.com/q/19544489/1855801 (단지 대체 ROWID()어떤 경우 ROWID 컬럼에 의해 기능)
maf-soft

12
여기에 경고를 추가하십시오. 중복 제거 프로세스를 실행할 때는 항상 먼저 무엇을 삭제하고 있는지 다시 확인하십시오! 우연히 좋은 데이터를 삭제하는 것이 매우 일반적인 영역 중 하나입니다.
Jeff Davis

답변:


1142

더 널 (null)을 가정하지, 당신 GROUP BY고유의 열 및 행 등의 RowId는 유지합니다. 그런 다음 행 ID가없는 모든 것을 삭제하십시오.SELECTMIN (or MAX)

DELETE FROM MyTable
LEFT OUTER JOIN (
   SELECT MIN(RowId) as RowId, Col1, Col2, Col3 
   FROM MyTable 
   GROUP BY Col1, Col2, Col3
) as KeepRows ON
   MyTable.RowId = KeepRows.RowId
WHERE
   KeepRows.RowId IS NULL

정수 대신 GUID가있는 경우 바꿀 수 있습니다

MIN(RowId)

CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))

327
이것도 효과가 있습니까? DELETE FROM MyTable WHERE RowId NOT IN (SELECT MIN(RowId) FROM MyTable GROUP BY Col1, Col2, Col3);
Georg Schölly

10
@Andriy -에서 SQL Server는 LEFT JOIN보다 덜 효율적이다 NOT EXISTS sqlinthewild.co.za/index.php/2010/03/23/... 같은 사이트도 비교 NOT INNOT EXISTS. sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in 3 가지NOT EXISTS가장 좋은 것 같습니다. 세 가지 모두 피할 수는 있지만 자체 참여 계획을 생성합니다.
Martin Smith

12
@Martin, @Georg : 작은 테스트를했습니다. 여기에 설명 된대로 큰 테이블이 만들어지고 채워졌습니다. sqlinthewild.co.za/index.php/2010/03/23/… 두 개의 SELECT가 생성되었습니다. 하나는 LEFT JOIN + WHERE IS NULL 기술을 사용하고 다른 하나는 NOT을 사용하여 생성되었습니다. 하나의. 그런 다음 실행 계획을 진행했는데 무엇을 추측합니까? 쿼리 비용은 왼쪽에 18 %가 NOT IN, A의 82 %에 가입했다 나에게 놀라운. 내가하지 말아야 할 일을했을 수도 있고, 그 반대도 마찬가지입니다. 사실이라면 정말로 알고 싶습니다.
Andriy M

16
@ GeorgSchölly는 우아한 답변을 제공했습니다. 필자는 PHP 버그가 중복 행을 생성 한 테이블에서 사용했습니다.
Philip Kearns

12
죄송하지만 DELETE MyTable FROM MyTable구문 이 올바른 이유는 무엇입니까? 여기DELETE 문서의 옵션으로 테이블 이름을 넣는 것을 볼 수 없습니다 . 이것이 다른 사람들에게 명백한 경우 죄송합니다. 나는 단지 배우려고하는 SQL의 초보자입니다. 왜 작동하는지보다 더 중요합니다. 테이블 이름을 포함시키는 것의 차이점은 무엇입니까?
levininja

760

이 작업을 수행하는 또 다른 방법은

; 

--Ensure that any immediately preceding statement is terminated with a semicolon above
WITH cte
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3 
                                       ORDER BY ( SELECT 0)) RN
         FROM   #MyTable)
DELETE FROM cte
WHERE  RN > 1;

ORDER BY (SELECT 0)넥타이의 경우 보존 할 행이 임의이므로 위의 내용을 사용 하고 있습니다.

RowID예를 들어 최신을 유지하려면 다음을 사용할 수 있습니다.ORDER BY RowID DESC

실행 계획

이를위한 실행 계획은 자체 참여가 필요하지 않기 때문에 승인 된 답변보다 간단하고 효율적입니다.

실행 계획

그러나 항상 그런 것은 아닙니다. 한 곳에서 GROUP BY솔루션을 선호 될 수는 상황이다 해시 집계는 스트림 집계에 우선하여 선택 될 것이다.

ROW_NUMBER반면 솔루션은 항상 거의 같은 계획을 줄 것이다 GROUP BY전략이 더 유연합니다.

실행 계획

해시 집계 방식을 선호하는 요소는 다음과 같습니다.

  • 분할 열에 유용한 인덱스가 없습니다.
  • 각 그룹에서 상대적으로 더 많은 중복을 가진 상대적으로 적은 그룹

이 두 번째 경우의 극단적 인 버전 (각각에 중복이 많은 그룹이 거의없는 경우)은 단순히 새 테이블에 보관하기 위해 행을 삽입 한 다음 TRUNCATE원본을 복사하고 다시 복사하여 삭제와 비교하여 로깅을 최소화 하는 것을 고려할 수 있습니다 매우 높은 비율의 행.


28
내가 추가 할 수있는 경우 : 허용 된 답변이를 사용하는 테이블에서 작동하지 않습니다 uniqueidentifier. 이것은 훨씬 간단하고 모든 테이블에서 완벽하게 작동합니다. 고마워 마틴
BrunoLM

15
정말 대단한 답변입니다! 중복 된 부분이 있음을 깨닫기 전에 이전 PK를 제거했을 때 이벤트가 발생했습니다. +100
Mikael Eliasson

12
DBA.SE 에서이 질문 (이 답변과 함께)을 묻고 대답하는 것이 좋습니다. 그런 다음 정식 답변 목록에 추가 할 수 있습니다 .
Nick Chammas 2016 년

16
허용 된 답변과 달리 이것은 키 ( RowId) 가없는 테이블에서도 작동했습니다 .
vossad01

8
반면에 이것은 모든 SQL Server 버전에서 작동하지 않습니다
David

150

Microsoft 지원 사이트에서 중복제거 하는 방법에 대한 좋은 기사가 있습니다. 꽤 보수적입니다. 모든 단계를 별도의 단계로 수행해야하지만 큰 테이블에 대해서는 잘 작동합니다.

과거에이 작업을 수행하기 위해 자체 조인을 사용했지만 HAVING 절로 예쁘게 보일 수 있습니다.

DELETE dupes
FROM MyTable dupes, MyTable fullTable
WHERE dupes.dupField = fullTable.dupField 
AND dupes.secondDupField = fullTable.secondDupField 
AND dupes.uniqueField > fullTable.uniqueField

완전한! 이것이 이전 mariadb 버전 10.1.xx에서 중복 행을 제거하는 가장 효율적인 방법이라는 것을 알았습니다. 감사합니다!
Drunken M

훨씬 간단하고 이해하기 쉽습니다!
마크

98

다음 쿼리는 중복 행을 삭제하는 데 유용합니다. 이 예에서 표 갖는 IDID 열로 중복 데이터를 열은 Column1, Column2Column3.

DELETE FROM TableName
WHERE  ID NOT IN (SELECT MAX(ID)
                  FROM   TableName
                  GROUP  BY Column1,
                            Column2,
                            Column3
                  /*Even if ID is not null-able SQL Server treats MAX(ID) as potentially
                    nullable. Because of semantics of NOT IN (NULL) including the clause
                    below can simplify the plan*/
                  HAVING MAX(ID) IS NOT NULL) 

다음과 같은 스크립트 프로그램 사용 GROUP BY, HAVING, ORDER BY하나 개의 쿼리 및 반환 중복 된 컬럼과 그 카운트 결과를한다.

SELECT YourColumnName,
       COUNT(*) TotalCount
FROM   YourTableName
GROUP  BY YourColumnName
HAVING COUNT(*) > 1
ORDER  BY COUNT(*) DESC 

1
'FROM 절에 업데이트'TABLENAME '당신은 목표 테이블을 지정할 수 없습니다'최초의 스크립트 MySQL의 오류
D.Rosado

D.Rosado가 이미보고 한 오류 외에도 첫 번째 쿼리도 매우 느립니다. 해당 SELECT 쿼리가 허용되는 답변보다 + -20 배 더 긴 설정을 취했습니다.
parvus

8
@parvus-질문은 MySQL이 아닌 SQL Server로 태그됩니다. 구문은 SQL Server에서 좋습니다. 또한 MySQL은 하위 쿼리 최적화에 악명이 높습니다 ( 예 : 여기 참조) . 이 대답은 SQL Server에서 좋습니다. 실제로 NOT IN종종보다 성능이 우수합니다 OUTER JOIN ... NULL. HAVING MAX(ID) IS NOT NULL비록 의미 론적으로 비록 그것의 계획 예제를
Martin Smith

2
PostgreSQL 8.4에서 잘 작동합니다.
nortally

63
delete t1
from table t1, table t2
where t1.columnA = t2.columnA
and t1.rowid>t2.rowid

Postgres :

delete
from table t1
using table t2
where t1.columnA = t2.columnA
and t1.rowid > t2.rowid

왜 SQL Server 질문에 Postgres 솔루션을 게시해야합니까?
Lankymart

2
@Lankymart postgres 사용자도 이곳에옵니다. 이 답변의 점수를보십시오.
Gabriel

2
here , herehere 과 같이 인기있는 SQL 질문에서 이것을 보았습니다 . OP는 그의 대답을 얻었고 다른 사람들도 도움을 받았습니다. 문제 없습니다.
Gabriel

44
DELETE LU 
FROM   (SELECT *, 
               Row_number() 
                 OVER ( 
                   partition BY col1, col1, col3 
                   ORDER BY rowid DESC) [Row] 
        FROM   mytable) LU 
WHERE  [row] > 1 

1
이 메시지는 azure SQL DW에서 나타납니다. FROM 절은 현재 DELETE 문에서 지원되지 않습니다.
아 미트

40

첫 번째 행을 제외하고 중복 행이 삭제됩니다.

DELETE
FROM
    Mytable
WHERE
    RowID NOT IN (
        SELECT
            MIN(RowID)
        FROM
            Mytable
        GROUP BY
            Col1,
            Col2,
            Col3
    )

참조 ( http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server )


10
mysql의 경우 오류 : 오류 코드 : 1093이 표시됩니다. FROM 절에서 업데이트 할 대상 테이블 'Mytable'을 지정할 수 없습니다. 하지만이 작은 변화가 mysql을 위해 작동합니다 MYTABLE FROM DELETE WHERE ROWID NOT IN (TEMP AS MYTABLE GROUP BY COL1 FROM (SELECT MIN (ROWID) AS ID, Col2의, 열 3) FROM SELECT ID)
Ritesh

35

SQL Server 테이블에서 중복 행을 삭제하는 데 CTE를 선호합니다.

이 기사를 따르는 것이 좋습니다 :: http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/

독창성을 유지함으로써

WITH CTE AS
(
SELECT *,ROW_NUMBER() OVER (PARTITION BY col1,col2,col3 ORDER BY col1,col2,col3) AS RN
FROM MyTable
)

DELETE FROM CTE WHERE RN<>1

원본을 유지하지 않고

WITH CTE AS
(SELECT *,R=RANK() OVER (ORDER BY col1,col2,col3)
FROM MyTable)
 
DELETE CTE
WHERE R IN (SELECT R FROM CTE GROUP BY R HAVING COUNT(*)>1)

24

중복 행을 가져 오려면 :

SELECT
name, email, COUNT(*)
FROM 
users
GROUP BY
name, email
HAVING COUNT(*) > 1

중복 행을 삭제하려면

DELETE users 
WHERE rowid NOT IN 
(SELECT MIN(rowid)
FROM users
GROUP BY name, email);      

MySQL 사용자의 경우 우선 동일한 테이블에서 DELETE FROM가져올 수 없으므로 작동하지 않습니다 . MySQL에서 이것은 폭발했다 . SELECTDELETEMySQL error 1093
Íhor Mé

23

정확하고 중복 된 행을 삭제하기위한 빠르고 더티 (작은 테이블의 경우) :

select  distinct * into t2 from t1;
delete from t1;
insert into t1 select *  from t2;
drop table t2;

3
질문은 실제로 부정확하지 않은 복제 (dueto row id)를 지정합니다.
데니스 Jaheruddin

21

내부 조인에 대한 subquery \ having count (*)> 1 솔루션을 선호합니다. 읽기 쉽기 때문에 SELECT 문으로 전환하여 실행하기 전에 삭제할 내용을 확인하는 것이 매우 쉽기 때문입니다.

--DELETE FROM table1 
--WHERE id IN ( 
     SELECT MIN(id) FROM table1 
     GROUP BY col1, col2, col3 
     -- could add a WHERE clause here to further filter
     HAVING count(*) > 1
--)

내부 쿼리에 표시되는 모든 레코드를 삭제하지는 않습니다. 복제본 만 제거하고 원본을 보존해야합니다.
Sandy

3
select 절의 min (id)를 기반으로 ID가 가장 낮은 것을 반환합니다.
James Errico

2
쿼리의 첫 번째, 두 번째 및 마지막 줄을 주석 해제하십시오.
James Errico

7
모든 복제본이 정리되지는 않습니다. 중복 된 3 개의 행이있는 경우 MIN (id)가있는 행만 선택하고 그 중 하나를 삭제하고 두 개의 행은 중복 된 채로 둡니다.
클로이

2
그럼에도 불구하고 나는이 문을 반복해서 반복해서 사용하여 연결 시간이 초과되거나 컴퓨터가 절전 모드로 전환되는 대신 실제로 진행되도록했습니다. MAX(id)후자의 중복을 제거하도록 변경 LIMIT 1000000하고 내부 쿼리에 추가 하여 전체 테이블을 스캔 할 필요가 없었습니다. 이것은 다른 답변보다 훨씬 빨리 진행되었음을 보여주었습니다. 테이블을 관리 가능한 크기로 정리 한 후 다른 쿼리를 완료 할 수 있습니다. 팁 : col1 / col2 / col3에 그룹화 기준 인덱스가 있는지 확인하십시오.
Chloe

17
SELECT  DISTINCT *
      INTO tempdb.dbo.tmpTable
FROM myTable

TRUNCATE TABLE myTable
INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable
DROP TABLE tempdb.dbo.tmpTable

5
myTable에 대한 외래 키 참조가 있으면 잘림이 작동하지 않습니다.
Sameer Alibhai 2016 년

15

특수한 환경에서 작동하기 때문에 솔루션을 공유하겠다고 생각했습니다. 필자의 경우 중복 값을 가진 테이블에 외래 키가 없었습니다 (값이 다른 db에서 복제 되었기 때문입니다).

begin transaction
-- create temp table with identical structure as source table
Select * Into #temp From tableName Where 1 = 2

-- insert distinct values into temp
insert into #temp 
select distinct * 
from  tableName

-- delete from source
delete from tableName 

-- insert into source from temp
insert into tableName 
select * 
from #temp

rollback transaction
-- if this works, change rollback to commit and execute again to keep you changes!!

추신 : 이와 같은 일을 할 때 항상 거래를 사용합니다. 이는 모든 것이 전체적으로 실행되도록 보장 할뿐만 아니라 아무것도 위험없이 테스트 할 수있게 해줍니다. 그러나 물론 당신은 확실하게 백업을해야합니다 ...


14

이 쿼리는 나에게 매우 좋은 성능을 보여주었습니다.

DELETE tbl
FROM
    MyTable tbl
WHERE
    EXISTS (
        SELECT
            *
        FROM
            MyTable tbl2
        WHERE
            tbl2.SameValue = tbl.SameValue
        AND tbl.IdUniqueValue < tbl2.IdUniqueValue
    )

2M 테이블에서 30 초 미만으로 1M 행을 삭제했습니다 (50 % 복제).


14

CTE 사용. 아이디어는 중복 레코드를 형성하는 하나 이상의 열을 결합한 다음 원하는 것을 제거하는 것입니다.

;with cte as (
    select 
        min(PrimaryKey) as PrimaryKey
        UniqueColumn1,
        UniqueColumn2
    from dbo.DuplicatesTable 
    group by
        UniqueColumn1, UniqueColumn1
    having count(*) > 1
)
delete d
from dbo.DuplicatesTable d 
inner join cte on 
    d.PrimaryKey > cte.PrimaryKey and
    d.UniqueColumn1 = cte.UniqueColumn1 and 
    d.UniqueColumn2 = cte.UniqueColumn2;

1
JOIN에 AND가 누락 된 것 같습니다.
Justin R.

13

또 다른 쉬운 해결책은 여기에 붙여진 링크에서 찾을 수 있습니다 . 이것은 이해하기 쉽고 비슷한 문제의 대부분에 효과적입니다. 그것은 SQL Server를위한 것이지만 사용 된 개념은 받아 들일 수 없습니다.

링크 된 페이지의 관련 부분은 다음과 같습니다.

이 데이터를 고려하십시오.

EMPLOYEE_ID ATTENDANCE_DATE
A001    2011-01-01
A001    2011-01-01
A002    2011-01-01
A002    2011-01-01
A002    2011-01-01
A003    2011-01-01

그렇다면 중복 데이터를 어떻게 삭제할 수 있습니까?

먼저 다음 코드를 사용하여 해당 테이블에 ID 열을 삽입하십시오.

ALTER TABLE dbo.ATTENDANCE ADD AUTOID INT IDENTITY(1,1)  

다음 코드를 사용하여 해결하십시오.

DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID) _
    FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE) 

1
"파악하기 쉽다", "유효하다", 그러나 그 방법이 어떻게 구성되어 있는지에 대한 단어는 없다. 링크가 무효화되었다고 상상하면, 그 방법 이해하기 쉽고 효과적이라는 것을 어떻게 알 수 있을까? 메소드 설명의 필수 부분을 게시물에 추가해보십시오. 그렇지 않으면 답변이 아닙니다.
Andriy M

이 방법은 아직 아이디가 정의되지 않은 테이블에 유용합니다. 기본 키를 정의하기 위해 중복을 제거해야하는 경우가 종종 있습니다!
Jeff Davis

@JeffDavis- ROW_NUMBER시작하기 전에 새 열을 추가하는 길이로 갈 필요 없이이 경우 버전 이 올바르게 작동합니다.
Martin Smith

12

중복 제거 에 대한 또 다른 좋은 기사가 있습니다.

"이 SQL은 관계형 대수를 기반으로하며, 세트에서 복제가 허용되지 않기 때문에 관계형 대수에서 복제가 발생할 수없는 이유에 대해 설명합니다. "

임시 테이블 솔루션과 두 가지 MySQL 예제.

앞으로는 데이터베이스 수준에서 또는 응용 프로그램 관점에서이를 방지 할 것입니다. 데이터베이스가 참조 무결성을 유지 관리해야하기 때문에 데이터베이스 수준을 제안하고 개발자는 문제를 일으킬 것입니다.)


1
SQL은 다중 집합을 기반으로합니다. 그러나 세트를 기반으로 하더라도이 두 튜플 (1, a) 및 (2, a)는 다릅니다.
Andrew

12

그렇지. 임시 테이블을 사용하십시오. "작동하는"성능이 떨어지는 단일 진술을 원한다면 다음을 수행 할 수 있습니다.

DELETE FROM MyTable WHERE NOT RowID IN
    (SELECT 
        (SELECT TOP 1 RowID FROM MyTable mt2 
        WHERE mt2.Col1 = mt.Col1 
        AND mt2.Col2 = mt.Col2 
        AND mt2.Col3 = mt.Col3) 
    FROM MyTable mt)

기본적으로, 테이블의 각 행에 대해 부속 선택은 고려중인 행과 정확히 동일한 모든 행의 최상위 RowID를 찾습니다. 따라서 "원본"복제되지 않은 행을 나타내는 RowID 목록으로 끝납니다.


11

중복되지 않은 행을 보존 해야하는 테이블이 있습니다. 속도 나 효율성이 확실하지 않습니다.

DELETE FROM myTable WHERE RowID IN (
  SELECT MIN(RowID) AS IDNo FROM myTable
  GROUP BY Col1, Col2, Col3
  HAVING COUNT(*) = 2 )

7
이는 최대 1 개의 복제본이 있다고 가정합니다.
Martin Smith

왜 안돼 HAVING COUNT(*) > 1?
Philipp M

11

이것을 사용하십시오

WITH tblTemp as
(
SELECT ROW_NUMBER() Over(PARTITION BY Name,Department ORDER BY Name)
   As RowNumber,* FROM <table_name>
)
DELETE FROM tblTemp where RowNumber >1

10

다른 방법은 동일한 필드 와 고유 색인 으로 새 테이블을 작성하는 것입니다 . 그런 다음 모든 데이터를 이전 테이블에서 새 테이블로 이동하십시오 . 자동 SQL SERVER 무시 (중복 값이있는 경우 수행 할 작업 (무시, 인터럽트 또는 sth)에 대한 옵션도 있음)가 중복 값입니다. 따라서 중복 행이없는 동일한 테이블이 있습니다. 고유 색인을 원하지 않으면 전송 데이터 후에 삭제할 수 있습니다.

특히 큰 테이블의 경우 DTS (SSIS 패키지를 사용하여 데이터 가져 오기 / 내보내기)를 사용하여 모든 데이터를 새로운 고유 인덱스 테이블로 빠르게 전송할 수 있습니다. 7 백만 행의 경우 몇 분 밖에 걸리지 않습니다.


9

아래 쿼리를 사용하면 단일 열 또는 여러 열을 기반으로 중복 레코드를 삭제할 수 있습니다. 아래 쿼리는 두 열을 기반으로 삭제됩니다. 테이블 이름은 다음 testing과 같습니다.empno,empname

DELETE FROM testing WHERE empno not IN (SELECT empno FROM (SELECT empno, ROW_NUMBER() OVER (PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
or empname not in
(select empname from (select empname,row_number() over(PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)

9
  1. 동일한 구조로 새 빈 테이블 만들기

  2. 이 같은 쿼리를 실행

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) > 1
  3. 그런 다음이 쿼리를 실행하십시오.

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) = 1

9

중복 레코드를 삭제하는 가장 쉬운 방법입니다

 DELETE FROM tblemp WHERE id IN 
 (
  SELECT MIN(id) FROM tblemp
   GROUP BY  title HAVING COUNT(id)>1
 )

http://askme.indianyouth.info/details/how-to-dumplicate-record-from-table-in-using-sql-105


왜 이것을지지하는 사람이 있습니까? 동일한 ID가 두 개 이상인 경우 작동하지 않습니다. 대신 쓰십시오 : 아이디가없는 tblemp에서 삭제하십시오 (제목으로 tblemp 그룹에서 min (id)를 선택하십시오)
crellee

7

도움이 될 수있을뿐만 아니라이 접근법에 대해서도 언급하고 모든 SQL 서버에서 작동합니다. 종종 1-2 개의 복제본 만 있고 ID 및 복제 횟수가 알려져 있습니다. 이 경우 :

SET ROWCOUNT 1 -- or set to number of rows to be deleted
delete from myTable where RowId = DuplicatedID
SET ROWCOUNT 0

7

불행히도 응용 프로그램 수준에서. 중복을 방지하는 올바른 방법은 고유 인덱스를 사용하여 데이터베이스 수준에 있지만 SQL Server 2005에서는 인덱스를 900 바이트로만 허용하고 varchar (2048) 필드를 사용하면 문제가 해결된다는 데 동의합니다.

나는 그것이 얼마나 잘 수행 될지 모르겠지만 인덱스로 직접 할 수는 없지만 이것을 시행하기 위해 트리거를 작성할 수 있다고 생각합니다. 다음과 같은 것 :

-- given a table stories(story_id int not null primary key, story varchar(max) not null)
CREATE TRIGGER prevent_plagiarism 
ON stories 
after INSERT, UPDATE 
AS 
    DECLARE @cnt AS INT 

    SELECT @cnt = Count(*) 
    FROM   stories 
           INNER JOIN inserted 
                   ON ( stories.story = inserted.story 
                        AND stories.story_id != inserted.story_id ) 

    IF @cnt > 0 
      BEGIN 
          RAISERROR('plagiarism detected',16,1) 

          ROLLBACK TRANSACTION 
      END 

또한 varchar (2048)는 비린내가 들립니다 (일부는 2048 바이트이지만 매우 드 pretty니다). 실제로 varchar (max)가 아니어야합니까?


7

이것을하는 또 다른 방법 :-

DELETE A
FROM   TABLE A,
       TABLE B
WHERE  A.COL1 = B.COL1
       AND A.COL2 = B.COL2
       AND A.UNIQUEFIELD > B.UNIQUEFIELD 

2008 년 8 월 20 일의 기존 답변과 다른 점은 무엇입니까? - stackoverflow.com/a/18934/692942
Lankymart

7
DELETE
FROM
    table_name T1
WHERE
    rowid > (
        SELECT
            min(rowid)
        FROM
            table_name T2
        WHERE
            T1.column_name = T2.column_name
    );

안녕하세요 Teena, 삭제 주석 후 Alice 이름 T1 테이블을 놓쳤습니다. 그렇지 않으면 구문 예외가 발생합니다.
Nagaraj M 11

6
CREATE TABLE car(Id int identity(1,1), PersonId int, CarId int)

INSERT INTO car(PersonId,CarId)
VALUES(1,2),(1,3),(1,2),(2,4)

--SELECT * FROM car

;WITH CTE as(
SELECT ROW_NUMBER() over (PARTITION BY personid,carid order by personid,carid) as rn,Id,PersonID,CarId from car)

DELETE FROM car where Id in(SELECT Id FROM CTE WHERE rn>1)

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