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 | +--------+-------+
5 Réponses :
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 )
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.
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 >
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.
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 ) );
Il semble que ce soit ;-) delete t où col1
@ThorstenKettner. . . Merci. Ce n'est pas une instruction SELECT
, n'est-ce pas? J'ai corrigé la réponse.
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.
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.