SQL Удалить подзапрос, удалены дубликаты записей - PullRequest
2 голосов
/ 05 июля 2011

Я пытаюсь написать запрос к удаленным дубликатам записей из следующей таблицы (valid_columns) и сохранить только записи с наименьшим возможным номером [order].

Например, в следующей таблице я хотел быудалить повторяющиеся строки, область 2,3 и задание 3 и сохранить записи с наименьшим возможным [порядком].

Например, таблица ввода valid_columns выглядит следующим образом:

name    col_order
-------------
job     1   
job     3   
status  2   
cust    2   
county  1   
state   1   
region  1
region  2
region  3
so      4

ЖелательноВывод:

name    col_order
-------------
job     1       
status  2   
cust    2   
county  1   
state   1   
region  1
so      4

Я пытаюсь исправить ошибку и не могу понять SQL.В настоящее время он использует удаление статистики и подзапрос.Используемый в данный момент запрос выглядит следующим образом:

- 3) Удалить дублирующиеся столбцы

DELETE 
FROM valid_columns
WHERE   NOT ( col_order = ( SELECT  TOP 1 col_order 
            FROM    valid_columns   firstValid
            WHERE   name = firstValid.name
            AND col_order = firstValid.col_order
            ORDER BY col_order ASC ))

Однако это возвращает только следующее, что неверно:

name    col_order
-------------
job     1
county  1
state   1
region  1

Большое спасибо

Ответы [ 6 ]

1 голос
/ 05 июля 2011
DELETE FROM t1
FROM valid_columns t1
WHERE col_order > 
    (SELECT MIN(col_order) from valid_columns t2 WHERE t1.name = t2.name)

EDIT: можно упростить до этого:

   DELETE FROM valid_columns 
   WHERE col_order > 
        (SELECT MIN(col_order) from valid_columns t2 WHERE valid_columns.name = t2.name)

Оператор DELETE может содержать предложение FROM для удаления записи на основе значения связанной записи во второй таблице. В этом случае FROM на самом деле не требуется (иногда я использую FROM для псевдонима имени таблицы, потому что мне не нравится дополнительная ввод.)

DELETE FROM TableA
FROM TableA 
JOIN TableB On TableA.CriteriaA = TableB.CriteriaA

Вы также можете попробовать этот пример (может быть быстрее, если вам придется много делать):

DELETE FROM valid_columns 
WHERE EXISTS
    (SELECT * FROM valid_columns t1 
     WHERE t1.name = valid_columns.name AND valid_columns.col_order > t1.col_order);
1 голос
/ 05 июля 2011
-- Test table
declare @T table(Name varchar(10), col_order int)

-- Sample data
insert into @T
select 'job',     1 union all
select 'job',     3 union all
select 'status',  2 union all
select 'cust',    2 union all
select 'county',  1 union all
select 'state',   1 union all
select 'region',  1 union all
select 'region',  2 union all
select 'region',  3 union all
select 'so',      4

-- Delete using CTE and row_number()
;with cte as
(
  select row_number() over(partition by Name order by col_order) as rn
  from @T
)
delete from cte
where rn > 1

-- Result
select *
from @T

Или с подзапросом вместо CTE

delete vc
from (select row_number() over(partition by Name order by col_order) as rn
      from valid_columns) as vc
where vc.rn > 1      
0 голосов
/ 06 июля 2011

Удалить запись с двоичной контрольной суммой (это работает в любой версии сервера sql)


CREATE TABLE #t1(ID INT NULL, VALUE VARCHAR(2))
INSERT INTO #t1(ID, VALUE) VALUES (1,'aa')
INSERT INTO #t1(ID, VALUE) VALUES (2,'bb')
INSERT INTO #t1(ID, VALUE) VALUES (1,'aa')
INSERT INTO #t1(ID, VALUE) VALUES (1,'aa')
INSERT INTO #t1(ID, VALUE) VALUES (3,'cc')
INSERT INTO #t1(ID, VALUE) VALUES (3,'cc')
GO

-- BINARY_CHECKSUM():  are columns that we want to compare duplicates for
-- if you want to compare the full row then change BINARY_CHECKSUM() -> BINARY_CHECKSUM(*)

-- for SQL Server 2000+ a loop
-- save checksums and rowcounts for duplicates

SELECT BINARY_CHECKSUM(ID, VALUE) AS ChkSum, COUNT(*) AS Cnt 
INTO #t2 
FROM #t1 
GROUP BY BINARY_CHECKSUM(ID, VALUE) HAVING COUNT(*)>1

DECLARE @ChkSum BIGINT, @rc INT

-- get the first checksum and set the rowcount to the count - 1 
-- because we want to leave one duplicate

SELECT TOP 1 @ChkSum = ChkSum, @rc = Cnt-1 FROM #t2

WHILE EXISTS (SELECT * FROM #t2)
BEGIN    
    -- rowcount is one less than the duplicate rows count
    SET ROWCOUNT @rc
    DELETE FROM #t1 WHERE BINARY_CHECKSUM(ID, VALUE) = @ChkSum 
    -- remove the processed duplicate from the checksum table
    DELETE #t2 WHERE ChkSum = @ChkSum 
    -- select the next duplicate rows to delete
    SELECT TOP 1 @ChkSum = ChkSum, @rc = Cnt-1 FROM #t2    
END 
SET ROWCOUNT 0
GO

SELECT * FROM #t1 

-- for SQL Server 2005+ a cool CTE
;WITH Numbered 
AS 
(
    SELECT ROW_NUMBER() OVER (PARTITION BY ChkSum ORDER BY ChkSum) AS RN, *
    FROM (
             SELECT BINARY_CHECKSUM(ID, VALUE) AS ChkSum
             FROM #t1
         ) t
) 
DELETE FROM Numbered WHERE RN > 1;
GO

SELECT * FROM #t1 

DROP TABLE #t1;
DROP TABLE #t2;


0 голосов
/ 05 июля 2011

Или вы можете перебрать таблицу с помощью курсора и вставить первое значение, найденное для элемента во временной таблице (убедитесь, что временная таблица имеет уникальное ограничение, указанное для столбца имени).

Редактировать : для удобства я добавил фрагмент кода ...

declare @Ti table(name varchar(10), col_order int);
declare @Tf table(name varchar(10) unique not null, col_order int not null);

declare @name varchar(10);
declare @col_order int;

-- Sample data
insert into @Ti
select 'job',     1 union all
select 'job',     3 union all
select 'status',  2 union all
select 'cust',    2 union all
select 'county',  1 union all
select 'state',   1 union all
select 'region',  1 union all
select 'region',  2 union all
select 'region',  3 union all
select 'so',      4

select * from @Ti

declare i cursor for
    select * from @Ti;

open i;
fetch next from i into @name, @col_order;

while @@FETCH_STATUS = 0
begin
    if not exists( select * from @Tf where name = @name )
    begin
        insert into @Tf(name, col_order)
            select @name, @col_order;
    end

    fetch next from i into @name, @col_order;
end

close i;
deallocate i;

select * from @Tf;
0 голосов
/ 05 июля 2011

Это должно сделать то, что вам нужно:

DELETE FROM valid_columns a
WHERE (SELECT MAX(col_order)
    FROM valid_columns b
    WHERE a.name = b.name) > a.col_order;

Тем не менее, я рекомендую сделать резервную копию данных перед тестированием.

0 голосов
/ 05 июля 2011

Попробуйте это (вы можете заменить удаление на выборку, чтобы убедиться, что вы получите правильные результаты перед удалением).

DELETE FROM [valid_columns] t1
WHERE col_order > (SELECT MIN(col_order) from [valid_columns] t2 
        WHERE t1.name = t2.name)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...