Instrução Select para encontrar duplicatas em determinados campos

415

Você pode me ajudar com instruções SQL para encontrar duplicatas em vários campos?

Por exemplo, no pseudo-código:

select count(field1,field2,field3) 
from table 
where the combination of field1, field2, field3 occurs multiple times

e da declaração acima, se houver várias ocorrências, eu gostaria de selecionar todos os registros, exceto o primeiro .

JOE SKEET
fonte
3
seu pseudo-código é ambíguo e você não define a ordem de acordo com a qual não deseja o primeiro. Eu sugiro que você dê alguns dados de amostra.
razoável

Respostas:

840

Para obter a lista de campos para os quais existem vários registros, você pode usar ..

select field1,field2,field3, count(*)
  from table_name
  group by field1,field2,field3
  having count(*) > 1

Verifique este link para obter mais informações sobre como excluir as linhas.

http://support.microsoft.com/kb/139444

Editar: como os outros usuários mencionados, deve haver um critério para decidir como você define "primeiras linhas" antes de usar a abordagem no link acima. Com base nisso, você precisará usar uma ordem por cláusula e uma subconsulta, se necessário. Se você puder postar alguns dados de amostra, isso realmente ajudaria.

Rajesh Chamarthi
fonte
42

Você mencionou "o primeiro", então presumo que você tenha algum tipo de pedido em seus dados. Vamos supor que seus dados sejam ordenados por algum campo ID.

Esse SQL deve fornecer as entradas duplicadas, exceto a primeira. Basicamente, seleciona todas as linhas para as quais existe outra linha com (a) os mesmos campos e (b) existe um ID menor. O desempenho não será ótimo, mas pode resolver seu problema.

SELECT A.ID, A.field1, A.field2, A.field3
  FROM myTable A
 WHERE EXISTS (SELECT B.ID
                 FROM myTable B
                WHERE B.field1 = A.field1
                  AND B.field2 = A.field2
                  AND B.field3 = A.field3
                  AND B.ID < A.ID)
Heinzi
fonte
17

Esta é uma solução divertida com o SQL Server 2005 que eu gosto. Eu vou assumir que por "para cada registro, exceto o primeiro", você quer dizer que existe outra coluna "id" que podemos usar para identificar qual linha é "primeira".

SELECT id
    , field1
    , field2
    , field3
FROM
(
    SELECT id
        , field1
        , field2
        , field3
        , RANK() OVER (PARTITION BY field1, field2, field3 ORDER BY id ASC) AS [rank]
    FROM table_name
) a
WHERE [rank] > 1
Nick Vaccaro
fonte
Só notei a tag do SQL Server 2008. Ainda bem que minha sugestão ainda é válida.
Nick Vaccaro
1
Excelente solução porque também retorna as linhas que terão de ser excluídos da tabela em questão
Realto619
1
ele ajuda a pensar a partição lista de campo como uma lista de campos PK
bkwdesign
6

Para ver valores duplicados:

with MYCTE  as (
    select row_number() over ( partition by name  order by name) rown, *
    from tmptest  
    ) 
select * from MYCTE where rown <=1
manoj Verma
fonte
3

Se você estiver usando o SQL Server 2005 ou posterior (e as tags da sua pergunta indicarem o SQL Server 2008), poderá usar as funções de classificação para retornar os registros duplicados após o primeiro, se o uso de junções for menos desejável ou impraticável por algum motivo. O exemplo a seguir mostra isso em ação, onde também trabalha com valores nulos nas colunas examinadas.

create table Table1 (
 Field1 int,
 Field2 int,
 Field3 int,
 Field4 int 
)

insert  Table1 
values    (1,1,1,1)
        , (1,1,1,2)
        , (1,1,1,3)
        , (2,2,2,1)
        , (3,3,3,1)
        , (3,3,3,2)
        , (null, null, 2, 1)
        , (null, null, 2, 3)

select    *
from     (select      Field1
                    , Field2
                    , Field3
                    , Field4
                    , row_number() over (partition by   Field1
                                                      , Field2
                                                      , Field3
                                         order by       Field4) as occurrence
          from      Table1) x
where     occurrence > 1

Observe depois de executar este exemplo que o primeiro registro de cada "grupo" é excluído e que os registros com valores nulos são tratados corretamente.

Se você não tiver uma coluna disponível para ordenar os registros em um grupo, poderá usar as colunas de partição por como as colunas de ordenação.

Bradford Hoagland
fonte
1
CREATE TABLE #tmp
(
    sizeId Varchar(MAX)
)

INSERT  #tmp 
    VALUES ('44'),
        ('44,45,46'),
        ('44,45,46'),
        ('44,45,46'),
        ('44,45,46'),
        ('44,45,46'),
        ('44,45,46')


SELECT * FROM #tmp
DECLARE @SqlStr VARCHAR(MAX)

SELECT @SqlStr = STUFF((SELECT ',' + sizeId
              FROM #tmp
              ORDER BY sizeId
              FOR XML PATH('')), 1, 1, '') 


SELECT TOP 1 * FROM (
select items, count(*)AS Occurrence
  FROM dbo.Split(@SqlStr,',')
  group by items
  having count(*) > 1
  )K
  ORDER BY K.Occurrence DESC    
Mr.X
fonte
0

tente esta consulta para ter uma contagem sepratley de cada instrução SELECT:

select field1,count(field1) as field1Count,field2,count(field2) as field2Counts,field3, count(field3) as field3Counts
from table_name
group by field1,field2,field3
having count(*) > 1
daryosh setorg
fonte