2010-07-08 6 views

Répondre

4

Vérifiez les exemples suivants. Tout d'abord, je grouper les valeurs dans un collect. J'ai utilisé le construit dans SYS.DBMS_DEBUG_VC2COLL mais il est préférable que vous créiez votre won. Ensuite, je prends cette collection puis fais un MULTISET UNION DISTINCT avec une collection vide du même type. Cela supprimera les entrées dupliquées.

select * from 
(select sys.dbms_debug_vc2coll(1,2,3) a, 
     sys.dbms_debug_vc2coll(1,2,3) multiset union distinct sys.dbms_debug_vc2coll() b 
from dual) 
where a=b; 

select * from 
(select sys.dbms_debug_vc2coll(1,2,3,1) a, 
     sys.dbms_debug_vc2coll(1,2,3,1) multiset union distinct sys.dbms_debug_vc2coll() b 
from dual) 
where a=b 

Enfin, je compare cette collection DISTINCT'd avec la collection originale. Si elles correspondent, alors la collection n'a déjà que des valeurs uniques.

+1

+1 très agréable. . –

+1

Le soutien de l'IIRC pour MULTISET UNION était une nouvelle caractéristique de 10g et l'OP spécifiait 9i. Mais +1 pour la solution la plus lisse de loin. – APC

3

si c'est une contrainte de données - alors je le mettrais dans un déclencheur - et de comparer chaque valeur dans PLSQL. (Je pense que cela est recommandé en fonction de votre description)

S'il s'agit d'une requête, alors vous aurez une clause where assez grande vérifiant chaque colonne par rapport aux autres.

modifier:

quelque chose comme:

select * from mytable where 
(col1=col2 or col1=col3 or col1=col4 or col1=col5 ...) 
or 
(col2=col3 or col2=col4 or col2=col5 ...) 
or 
(col3=col4 or col3=col5 ...) 
etc... 
+0

Cela ne peut-il pas être fait avec une requête sql où je choisis toutes les lignes qui ont des colonnes avec des données similaires. – Arc

+1

A moins que je ne comprenne mal, c'est une grosse vérification dans le déclencheur ou une clause WHERE assez grande dans une requête ... Je suis avec Andy sur celui-ci: factoriser les colonnes dans une autre table. –

+0

La longue requête fonctionnera à coup sûr. N'y a-t-il pas de requête plus petite et optimisée pour faire la même chose? – Arc

4

Il me semble que ces 14 colonnes sont dénormalisées, et devrait en fait être un sous-table avec une contrainte d'index unique sur eux.

+0

En fait c'est un assez gros ensemble de données. – Arc

+0

bon commentaire, j'ai supposé qu'il y avait un effort de nettoyage de données requis dans ma réponse. Une structure normalisée appropriée est toujours la meilleure. :) – Randy

+0

Un index unique composite ne capturait que les doublons du même ensemble de valeurs de colonne. IE: 14 sur 14 doivent correspondre, 13 sur 14 ne provoquera pas une erreur de contrainte unique. –

3

Voici une autre façon de le faire en SQL. Cet exemple concerne trois colonnes. Vous ajoutez simplement plus de clauses union all select ... pour ajouter plus de colonnes à la vérification. Il renvoie le ROWID de toute ligne pour laquelle le nombre total de colonnes est supérieur au nombre de valeurs distinctes.

Je suppose qu'aucune des colonnes ne peut contenir des valeurs NULL. Si c'est un problème, cela peut vous donner des faux positifs.

select rowid,count(*),count(distinct col) 
from (
select rowid,col1 col from the_table 
    union all 
select rowid,col2 col from the_table 
    union all 
select rowid,col3 col from the_table 
) 
group by rowid 
having count(distinct col) < count(*) 
+0

+1 pour y arriver près de 30 minutes plus vite qu'il ne m'a fallu pour prouver la méthode –

0

Une méthode très sale, kludgey .... mais il devrait fonctionner avec 9i

SELECT * 
    FROM (SELECT keyIdentifierField, 
       COUNT(testField) AS fieldCount, 
       COUNT(DISTINCT testField) AS distinctFieldCount 
      FROM (SELECT keyIdentifierField, 
         col1 AS testField 
        FROM myTable 
        UNION ALL 
        SELECT keyIdentifierField, 
         col2 AS testField 
        FROM myTable 
        UNION ALL 
        SELECT keyIdentifierField, 
         col3 AS testField 
        FROM myTable 
        ... 
        UNION ALL 
        SELECT keyIdentifierField, 
         col14 AS testField 
        FROM myTable 
       ) 
      GROUP BY keyIdentifierField 
     ) 
WHERE fieldCount <> distinctFieldCount 
+0

On dirait que Dave Costa a posté une solution très similaire pendant que je travaillais dessus ... mais je ne peux pas être dérangé pour supprimer ma réponse après en tapant tout dans –

0

Si vous avez seulement un nombre possible en double, il existe des solutions possibles en utilisant des opérateurs de bits. Si vous utilisez Oracle 11, vous pouvez UNPIVOT les données de colonne en lignes,

présumant votre table a une clé unique appelée UniqueKey

SELECT UniqueKey,cvalue 
FROM 
(SELECT * 
FROM yourTable 
    UNPIVOT INCLUDE NULLS (cvalue FOR check_values IN (col1, col2, col3, col4)) 
) 
GROUP BY UniqueKey,cvalue HAVING count(cvalue) > 1 

Cela peut être syntaxiquement un peu hors que je n'ai pas Ora 11 test db à la main. Avant Oracle 11, la seule façon de faire quelque chose comme ceci serait d'utiliser les types d'objet et pl/sql (fonction qui donne un Id, retourne la liste des valeurs de colonne sur cette ligne en tant que Collection, puis joint cette fonction à l identité).

Il est probablement plus facile de simplement le faire en pl/sql (créer un tableau indexé par Integer, pour chaque vérification de colonne .exists (value) avant de définir - s'il existe, vous avez votre doublon). Appelez la fonction une fois par colonne par ligne et réinitialisez la matrice entre les lignes. Sinon, s'il s'agit d'une vérification d'intégrité unique, créez une table temporaire sur les paires clé/valeur, clé unique sur la paire, puis insérez chaque valeur de chaque ligne dans la clé et laissez Oracle rejeter vos erreurs.

0

Une autre approche qui fonctionnera dans 9i. Je ne donne aucune garantie pour les performances, seulement que c'est une approche SQL pure qui fonctionne sur 9i - mais en cours d'exécution pour 10 000 lignes avec 5 colonnes était sous-seconde, donc c'est raisonnable.

create table test (
    uniqueKey number, 
    c1 number, 
    c2 number, 
    c3 number, 
    c4 number, 
    c5 number) 

Construire Quelques cas de test - tous les 4 rangs est mauvais - on utilise un pseudo-table des entiers

insert into test 
    select r,1,2,3,4,CASE WHEN MOD(r,4)=0 THEN 4 ELSE 5 END 
    FROM (SELECT rownum r from dual connect by rownum <= 10000); 

maintenant convertir les valeurs de la colonne arrière en lignes en utilisant la même technique d'un pseudo- table sur la séquence d'entiers

SELECT uniqueKey,r from 
(
    SELECT rownum r from dual connect by rownum <= 100 
/* 100 is the max value in any of our columns */ 
) numbers, 
    test 
WHERE r in (c1,c2,c3,c4,c5) 

Ceci donne l'ensemble des nombres uniques contre chaque ligne.

Pour trouver des lignes invalides, puis juste vérifier si le compte est inférieur au nombre de colonnes

SELECT uniqueKey from 
(
    SELECT rownum r from dual connect by rownum <= 100 /* Our max potential value */ 
) numbers, 
    test 
WHERE r in (c1,c2,c3,c4,c5) 
GROUP BY uniqueKey 
HAVING COUNT(r) < 5 

Malheureusement, cela ne vous dit pas quelles valeurs sont dupliqués, mais il identifie vos lignes de problème.

Questions connexes