2009-04-23 7 views
0

Je n'arrive pas à écrire une requête. J'ai un support appelé 'MYTABLE' et il a une colonne appelée 'TABLENAME' qui peut contenir un ou plusieurs noms de tables. Plusieurs tables sont séparées par des virgules.Problème lors de l'écriture d'une requête SQL

Exemple:

TBLUSER 
TBLUSER, TBLACCOUNT 

Je suis en train d'écrire une requête qui permettra d'identifier toutes les entrées de la table MYTABLE qui ne sont pas valides tables dans la base de données. J'ai pu écrire la suite ....

     SELECT * 
         FROM MYTABLE T1 
      LEFT outer JOIN ALL_TAB_COLS T2 
         ON ( upper(T1.TABLENAME) = upper(t2.Table_Name) 
          AND T2.Owner = 'ME' 
          ) 
         WHERE TABLE_NAME IS NULL; 

Et il fonctionne exactement comme je veux - mais il ne fonctionne que lorsque l'entrée en MYTABLE contient une seule table. Lorsque plusieurs tables sont séparées par des virgules, l'opération échoue. Mes compétences SQL manquent quelque peu et mon instinct naturel est de «faire un pour chacun» mais je pense que ce n'est pas la bonne approche (et je n'ai aucune idée de la façon de le faire en SQL).

+0

Pourquoi dans le monde conserveriez-vous plusieurs tables sur une seule ligne? – TheTXI

+0

Reverse normalisation, TheTXI. C'est toute la rage. – Welbog

+0

Je crois que la pensée originale était qu'il serait plus facile pour les utilisateurs «non techniques» de modifier les données si elles pouvaient simplement les taper dans un seul champ. Je ne suis pas sûr si je suis d'accord avec ça ou pas; mais, malheureusement, c'est "comment c'est". Naturellement, lorsque l'une de ces tables est mal typée, il se produit une panne de l'application - j'espérais écrire une requête SQL pour identifier les lignes qui causeraient un plantage. –

Répondre

2

Vous stockez une chaîne dans MYTABLE.TABLENAME et en essayant de le faire correspondre à une chaîne en ALL_TAB_COLS.TABLE_NAME (qui d'ailleurs, je ne vois aucune raison pour que vous utiliseriez ALL_TAB_COLS au lieu de ALL_TABLES dans ce cas).

Si votre chaîne est 'TBLUSER, TBLACCOUNT', elle ne sera pas égale à la chaîne 'TBLUSER' ou à la chaîne 'TBLACCOUNT'. C'est toute l'expression upper(T1.TABLENAME) = upper(t2.Table_Name) teste - ces deux chaînes sont-elles égales? Vous semblez vous attendre à ce qu'il «sache» que vos données se trouvent être une liste de noms de tables séparés par des virgules.

La méthode brute-force pour faire ce que vous avez travaillé en utilisant des comparaisons de chaînes est de changer la condition à ','||upper(T1.TABLENAME)||',' LIKE '%,'||upper(t2.Table_Name)||',%. Vous examinerez donc essentiellement si TABLE_NAME est une sous-chaîne de votre valeur de colonne TABLENAME.

Cependant, le point réel est que c'est une conception de base de données pas très bonne. Tout d'abord, d'un simple point de clarté, pourquoi nommez-vous une colonne "TABLENAME" (singulier) et y mettez des valeurs qui représentent plusieurs noms de tables? Si vous allez faire cela, vous devriez au moins l'appeler quelque chose comme "TÉLÉMÉLISTE".

Plus important encore, ce n'est généralement pas la façon dont nous faisons les choses dans les bases de données relationnelles.Si votre MYTABLE ressemble à ceci:

ID  TABLENAME 
1  TBLUSER 
2  TBLUSER, TBLACCOUNT 

alors d'une manière relationnelle plus propre à concevoir la table serait:

ID  TBL_NUM TABLENAME 
1  1   TBLUSER 
2  1   TBLUSER 
2  2   TBLACCOUNT 

Ensuite, votre requête fonctionnerait comme-est, plus ou moins, parce que le TABLENAME La colonne contiendra toujours le nom d'une seule table.

3

Vous avez sérieusement besoin de repenser votre conception de base de données. Garder plusieurs entrées sur un seul enregistrement dans une table qui est censée garder une trace de ces entrées est un gros WTF géant.

Vous devez changer votre conception de sorte qu'au lieu de ce que vous vous décrivez quelque chose comme:

ID TABLENAME 
---------------------- 
1  TBLUSER 
2  TBLUSER 
2  TBLACCOUNT 

Lorsque l'ID + est une Tablename clé primaire composite. Cela rendrait votre requête écrite (bien que n'étant pas basée sur l'exemple de bare-bones fourni ci-dessus). Je sais que ce n'est peut-être pas ce que vous recherchez dans votre problème exact, mais je pense qu'il est important de le dire quand même parce que les futurs utilisateurs pourraient trouver ce problème et avoir besoin de mieux comprendre la normalisation de la base de données. pratiques (que vous ne pouvez peut-être pas faire puisque l'application est telle qu'elle est parce que "c'est comme ça").

+0

C'est un excellent point. D'accord. –

1

La réponse courte est:

select distinct 
    atc.table_name 
from 
    mytable mt 
,all_tab_cols atc 
where atc.owner = 'SOMESCHEMA' 
    and (
     mt.tablename = atc.table_name 
     or 
     (
     0 < instr(','||replace(upper(mt.tablename),' ','')||',' 
          ,','||upper(atc.table_name)||',') 
     ) 
    ) 

La réponse longue est déjà bien décrit par le poste de David Costa.