2009-04-23 14 views
0

Ich habe Probleme beim Schreiben einer Abfrage. Ich habe eine Unterstützung namens "MYTABLE" und es hat eine Spalte namens "TABLENAME", die einen oder mehrere Tabellennamen enthalten kann. Mehrere Tabellen sind durch Kommata getrennt.Fehler beim Schreiben der SQL-Abfrage

Beispiel:

TBLUSER 
TBLUSER, TBLACCOUNT 

Ich versuche, eine Abfrage zu schreiben, die alle Einträge in der Tabelle MYTABLE identifizieren, die keine gültigen Tabellen in der Datenbank sind. Ich konnte die Folge schreiben ....

     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; 

Und es funktioniert genau, wie ich will - aber es funktioniert nur, wenn der Eintrag in MYTABLE eine einzelne Tabelle enthält. Wenn mehrere Tabellen durch Kommas getrennt sind, schlägt es fehl. Meine SQL-Kenntnisse sind etwas mangelhaft und mein natürlicher Instinkt ist es, "Do a For Each" zu tun, aber ich denke, das ist nicht der richtige Ansatz (und ich habe keine Ahnung, wie man das in SQL macht).

+0

Warum in der Welt würden Sie mehrere Tabellen in einer einzigen Zeile behalten? – TheTXI

+0

Umgekehrte Normalisierung, TheTXI. Es ist der letzte Schrei. – Welbog

+0

Ich glaube, der ursprüngliche Gedanke dahinter war, dass es für "nicht-technische" Benutzer einfacher wäre, die Daten zu ändern, wenn sie alles nur in einem Feld eingeben könnten. Ich bin mir nicht sicher, ob ich dem zustimme oder nicht; aber leider ist das "wie es ist". Wenn eine dieser Tabellen falsch geschrieben wird, führt dies natürlich zum Absturz der Anwendung - ich hatte gehofft, eine SQL-Abfrage schreiben zu können, um die Zeilen zu identifizieren, die einen Absturz verursachen. –

Antwort

2

Sie eine Zeichenfolge in MYTABLE.TABLENAME zu speichern und versuchen, es gegen eine Zeichenfolge in ALL_TAB_COLS.TABLE_NAME zu passen (die btw, ich Sie in diesem Fall benutzen würde ALL_TAB_COLS statt ALL_TABLES keinen Grund sehen).

Wenn Ihre Zeichenfolge 'TBLUSER, TBLACCOUNT' ist, wird sie nicht mit der Zeichenfolge 'TBLUSER' oder der Zeichenfolge 'TBLACCOUNT' übereinstimmen. Das ist der ganze Ausdruck upper(T1.TABLENAME) = upper(t2.Table_Name) testet - sind diese beiden Zeichenketten gleich? Sie scheinen zu erwarten, dass es irgendwie "weiß", dass Ihre Daten zufällig eine durch Kommas getrennte Liste von Tabellennamen sind.

Die Brute-Force-Methode, um Ihre Arbeit mit Zeichenfolgenvergleichen durchzuführen, besteht darin, die Bedingung in ','||upper(T1.TABLENAME)||',' LIKE '%,'||upper(t2.Table_Name)||',% zu ändern. Sie würden also grundsätzlich prüfen, ob TABLE_NAME eine Teilzeichenfolge Ihres TABLENAME-Spaltenwerts ist.

Der eigentliche Punkt ist jedoch, dass dies ein nicht sehr gutes Datenbankdesign ist. Vor allem, aus einem einfachen Punkt der Klarheit, warum würden Sie eine Spalte "TABLENAME" (Singular) benennen und dann Werte einfügen, die mehrere Tabellennamen repräsentieren? Wenn Sie das tun, sollten Sie es zumindest so nennen wie "TABLENAMELIST".

Noch wichtiger ist, das ist nicht die Art, wie wir Dinge in relationalen Datenbanken tun.Wenn Ihr MYTABLE wie folgt aussieht:

ID  TABLENAME 
1  TBLUSER 
2  TBLUSER, TBLACCOUNT 

dann ein richtiger relationaler Weg, um die Tabelle zu entwerfen wäre:

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

dann Ihre Abfrage funktionieren würde, wie sie ist, mehr oder weniger, weil die TABELLENNAME Spalte würde immer den Namen einer einzelnen Tabelle enthalten.

3

Sie müssen ernsthaft Ihr Datenbankdesign dort überdenken. Mehrere Einträge in einem einzigen Datensatz in einer Tabelle zu behalten, die diese Einträge verfolgen soll, ist ein großer, riesiger WTF.

Sie müssen Ihr Design ändern, so dass statt dessen, was Sie beschreiben Sie so etwas wie haben:

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

Wo die ID + Tablename einen zusammengesetzten Primärschlüssel ist. Das würde Ihre Abfrage, die Sie geschrieben haben, arbeiten lassen (obwohl es nicht funktioniert, basierend auf dem obigen Beispiel).

HINWEIS Ich weiß, dass dies möglicherweise nicht das ist, was Sie in Ihrem genauen Problem suchen, aber ich denke, es ist wichtig zu sagen, weil zukünftige Benutzer kommen und dieses Problem finden und ein besseres Verständnis der Datenbanknormalisierung benötigen Praktiken (die Sie möglicherweise nicht können, da die Anwendung so ist, weil "das ist, wie es ist").

+0

Das ist ein ausgezeichneter Punkt. Einverstanden. –

1

Die kurze Antwort lautet:

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)||',') 
     ) 
    ) 

Die lange Antwort war bereits von David Costa Post beschrieben.

Verwandte Themen