2014-07-02 9 views
1

Je m'excuse si cette question a été posée, j'ai du mal à la mettre en mots.Rechercher le texte dans un champ contenu dans un autre champ Oracle SQL

J'ai été invité à filtrer des lignes dans une requête où le texte d'un champ est contenu dans un autre champ. Un exemple serait sans doute expliquer mieux:

Column_1   Column_2 
    Low Static  Static 
    Static   Static 
    Static   Clear 
        Static 
    Very Low Freq Freq 

Le résultat de la requête doit retourner uniquement les lignes 3 et 4, puisque les lignes 1, 2 et 5 contiennent des chaînes qui sont similaires. En ce moment, je la condition suivante:

WHERE 
    ((Column_2 NOT LIKE '%' || Column_1 || '%') 
    OR (Column_1 NOT LIKE '%' || Column_2 || '%' OR Column_1 IS NULL)) 

Cependant, il est de retour les lignes 1, 3, 4, et 5 quand je veux revenir que les lignes 3 et 4. Ces données sont seulement par exemple, mon jeu de données réel contient De nombreuses chaînes de texte différentes dans les colonnes 1 et 2, je ne peux donc pas écrire des instructions de cas spécifiques pour exclure certaines instances où les colonnes sont similaires.

Peut-être que ce n'est tout simplement pas possible, puisque je ne peux pas définir une chaîne comme quelque chose contenu dans 2 espaces, tout en prenant en considération des cas où il n'y a pas d'espaces?

Merci

+0

changer la première ou à une et 'WHERE (column_2 pas comme « % » || column_1 || « % » et Colonne_1 pas comme « % » || column_2 || '%') OU Colonne_1 est nulle OU colonne_2 est nulle' – xQbert

+0

Le titre de la question dit le contraire de la dernière partie de votre question où vous dites "Je ne veux que retourner les lignes 3 et 4", donc je suis confus . – codenheim

+0

Merci d'avoir trouvé cela. Je l'ai changé en ET qui a corrigé quelques cas, mais je reçois toujours des résultats incohérents, par exemple. Colonne 1 = 'Bruit sonore droit' et Colonne 2 = 'Bruit sonore clair' (donc je voudrais exclure cette rangée). – GrubBumble

Répondre

1

Pour votre expression, je pense que vous voulez and plutôt que or:

WHERE ((Column_2 NOT LIKE '%' || Column_1 || '%') AND 
     (Column_1 NOT LIKE '%' || Column_2 || '%' OR Column_1 IS NULL) 
    ) 

Vous avez besoin pour les deux conditions pour être vrai. Vous trouverez peut-être la logique plus facile à suivre comme:

WHERE NOT (Column_2 LIKE '%' || Column_1 || '%' OR 
      Column_1 LIKE '%' || Column_2 || '%' 
     ) 
0

L'approche que vous allez avec va faire des analyses de table complet il échelle coutume que la table se développe. Si vous souhaitez implémenter une solution plus efficace (sans utiliser l'indexation de texte volumineux Oracle) qui utilisera un index, utilisez un index basé sur une fonction pour pré-calculer les sous-chaînes communes des colonnes. En utilisant INSTR(), vous pouvez déterminer si une colonne est une sous-chaîne d'une autre colonne et renvoyer une note pour cela. 0 signifie pas de correspondance.

create index ix_t_score on t (instr(nvl(column_1,' '), nvl(column_2, ' ')), 
           instr(nvl(column_2,' '), nvl(column_1, ' '))); 

Maintenant, écrivez la requête de sorte qu'elle permette à Oracle d'utiliser les index.

-- Find rows that don't have common strings 
select * from t 
    where instr(nvl(column_1, ' '), nvl(column_2, ' ')) = 0 and 
     instr(nvl(column_2, ' '), nvl(column_1, ' ')) = 0; 

-- Find rows that do 
select * from t 
    where instr(nvl(column_1, ' '), nvl(column_2, ' ')) > 0 or 
     instr(nvl(column_2, ' '), nvl(column_1, ' ')) > 0; 


set autotrace on 


Execution Plan 
---------------------------------------------------------- 
Plan hash value: 4100696360 

--------------------------------------------------------------------------------- 
| Id | Operation   | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
--------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |    |  1 | 22 |  2 (0)| 00:00:01 | 
| 1 | SORT AGGREGATE |    |  1 | 22 |   |   | 
|* 2 | INDEX RANGE SCAN| IX_T_SCORE |  1 | 22 |  2 (0)| 00:00:01 | 
--------------------------------------------------------------------------------- 


Predicate Information (identified by operation id): 
--------------------------------------------------- 

    2 - access(INSTR(NVL("COLUMN_1",' '),NVL("COLUMN_2",' '))=0 AND 
       INSTR(NVL("COLUMN_2",' '),NVL("COLUMN_1",' '))=0) 

Vous pouvez simplifier en créant une procédure/fonction déterministe stockée pour retourner un score, et le SQL devient beaucoup plus simple que ce qui précède. L'utilisation de NVL() est de prendre soin des colonnes avec des zéros.

Questions connexes