1
votes

Supprimer presque les doublons dans un tableau

J'ai une table où les chaînes 1 et 2 sont presque dupliquées - elles ont les mêmes valeurs mais dans l'ordre inverse. Comment puis-je supprimer ces doublons?

+--------+-------+
| COL_1  | COL_@ |
+--------+-------+
| a1     | b1    |
| b1     | a1    | <- same as 1stline but in reversed order, needs to be removed
| a2     | b2    |   
| a3     | b3    |
| b3     | a3    |<-- also is duplicate of string above, one of these 2str need                        
+--------+-------+     to be removed

expected result:
+--------+-------+
| COL_1  | COL_@ |
+--------+-------+
| b1     | a1    | 
| a2     | b2    |   
| a3     | b3    |                   
+--------+-------+

or
+--------+-------+
| COL_1  | COL_@ |
+--------+-------+
| a1     | b1    |
| a2     | b2    |   
| a3     | b3    |                    
+--------+-------+


4 commentaires

Quel est votre résultat final?


Merci pour la question. Ajout d'une explication du résultat final dans ma question


Pourquoi voulez-vous conserver (a1, b1) au lieu de (b1, a1)? N'oubliez pas que les lignes n'ont pas d'ordre implicite.


Ajoutez les lignes (a4, b4) et (a4, b4) à vos exemples de données et décrivez le résultat attendu.


5 Réponses :


1
votes

Voulez-vous dire comme ceci:

DELETE(
    select e.COL_@, f.COL_1
    from example as e
    join example as f on e.COL_@ = f.COL_1 and e.COL_@ < f.COL_1 )


5 commentaires

La syntaxe est désactivée. Oracle n'accepte pas AS pour les qualificatifs de table et je doute fort qu'il puisse supprimer d'une vue où deux tables sont jointes (peu importe qu'il s'agisse d'une auto-jointure ici). Laquelle des deux lignes jointes attendez-vous qu'il supprime?


Peu importe, en fait.


@Katya: Qu'est-ce que cela signifie? Peu importe que votre SGBD soit capable d'exécuter l'instruction SQL ou non? Cela ne semble pas logique.


@ThorstenKettner, vous m'avez trompé. C'était la réponse à votre question, laquelle des lignes doit être supprimée :) Dans mon cas, il n'y a aucune différence quelle ligne sera enregistrée dans DB


@Katya: Haha, d'accord. C'était une question rhétorique. Je voulais souligner qu'Oracle n'aurait aucun moyen de savoir quelles lignes supprimer avec une telle syntaxe.



0
votes

Si col_1 et col_ @ ne peuvent pas être nuls, vous pouvez utiliser LEAST et GREATEST pour conserver une ligne par combinaison:

delete from tbl
where rowid not in
(
  select min(rowid) -- one rowid per combination to keep
  from tbl
  group by least(col_1, col_@), greatest(col_1, col_@)
);

p >


0 commentaires

0
votes

Je pense que c'est un peu compliqué d'y parvenir avec une requête de suppression. Peut-être est-il acceptable que vous ayez d'abord une telle requête de sélection:

select A,B from (
                    select A,
                           B,
                           ROW_NUMBER() over (PARTITION BY ORA_HASH(A) * ORA_HASH(B) ORDER BY A) as RANK
                    FROM <your_table_name>
) where RANK = 1;

Vous pouvez enregistrer le résultat de cette requête en tant que nouvelle table avec CREATE TABLE AS SELECT ... code> Et puis il vous suffit de SUPPRIMER votre ancienne table.


0 commentaires

0
votes

Cela ne semble pas si compliqué:

delete t
   where col1 > col2 and
         exists (select 1
                 from t t2
                 where t2.col1 = t.col2 and
                       t2.col2 = t.col1
             );

Ou:

delete t
   where not (col1 < col2 or
              not exists (select 1
                          from t t2
                          where t2.col1 = t.col2 and
                                t2.col2 = t.col1
                         )
             );


2 commentaires

Il semble que ce soit ;-) delete t où col1 peut supprimer beaucoup de lignes qui n'ont même pas de doublon.


@ThorstenKettner. . . Merci. Ce n'est pas une instruction SELECT , n'est-ce pas? J'ai corrigé la réponse.



0
votes

Une solution possible est:

DELETE FROM T
  WHERE (COL_1, "COL_@") IN (SELECT COL_1, "COL_@"
                             FROM (SELECT ROWNUM AS RN, t1.COL_1, t1."COL_@"
                                     FROM T t1
                                     INNER JOIN T t2
                                       ON t2."COL_@" = t1.COL_1 AND
                                          t2.COL_1 = t1."COL_@")
                             WHERE RN / 2 <> TRUNC(RN / 2));

Notez que COL_ @ doit être cité dans Oracle car @ n’est pas un caractère légal dans un identifiant sans guillemets.

dbfiddle ici


0 commentaires