2010-12-20 7 views
0

Wir verwenden eine Extraktor-Anwendung, die Daten aus der Datenbank in CSV-Dateien exportieren wird. Basierend auf einer Bedingungsvariablen extrahiert es Daten aus verschiedenen Tabellen und für einige Bedingungen müssen wir UNION ALL verwenden, da die Daten aus mehr als einer Tabelle extrahiert werden müssen. Um die UNION ALL-Bedingung zu erfüllen, verwenden wir Nullen, um die Anzahl der Spalten anzupassen.Die beste Methode zum dynamischen Abrufen von Spaltennamen aus Oracle Tabellen

Momentan sind alle Abfragen im System basierend auf der Bedingungsvariablen vordefiniert. Das Problem besteht darin, dass bei jeder Änderung der Tabellenprojektion (d. H. Neue Spalte hinzugefügt, vorhandene Spalte geändert, Spalte gelöscht) der Code in der Anwendung manuell geändert werden muss.

Können Sie bitte einige Vorschläge machen, wie Sie die Spaltennamen dynamisch extrahieren, so dass Änderungen in der Tabellenstruktur keine Änderung im Code erfordern?


Mein Anliegen ist die Bedingung, die entscheidet, welche Tabelle abgefragt werden soll. Der variable Zustand wie

  • wenn der Zustand A ist, dann ist von der Last TableX
  • wenn die Bedingung B dann aus TableA und Tabley laden.

Wir müssen wissen, aus welcher Tabelle wir Daten bekommen müssen. Sobald wir die Tabelle kennen, ist es einfach, die Spaltennamen aus dem Data Dictionary abzufragen. Aber es gibt eine weitere Bedingung, nämlich dass einige Spalten ausgeschlossen werden müssen und diese Spalten für jede Tabelle unterschiedlich sind.

Ich versuche, das Problem nur für das dynamische Generieren der Listenspalten zu lösen. Aber mein Manager sagte mir, ich solle eine Lösung auf der konzeptionellen Ebene machen, anstatt nur zu reparieren. Dies ist ein sehr großes System, bei dem Anbieter und Verbraucher ständig Daten laden und konsumieren. Also wollte er eine Lösung, die allgemein sein kann.

Also, was ist der beste Weg zum Speichern von Bedingung, Tabellenname, ausgeschlossene Spalten? Eine Möglichkeit ist das Speichern in der Datenbank. Gibt es noch andere Möglichkeiten? Wenn ja, was ist das Beste? Da muss ich vor dem Finalisieren noch ein paar Ideen geben.

Danke,

Antwort

1

Ok, MNC, versuchen Sie dies für die Größe (in eine neue Konsolenanwendung einfügen):

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Test.Api; 
using Test.Api.Classes; 
using Test.Api.Interfaces; 
using Test.Api.Models; 

namespace Test.Api.Interfaces 
{ 
    public interface ITable 
    { 
     int Id { get; set; } 
     string Name { get; set; } 
    } 
} 

namespace Test.Api.Models 
{ 
    public class MemberTable : ITable 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
    } 
    public class TableWithRelations 
    { 
     public MemberTable Member { get; set; } 
     // list to contain partnered tables 
     public IList<ITable> Partner { get; set; } 

     public TableWithRelations() 
     { 
      Member = new MemberTable(); 
      Partner = new List<ITable>(); 
     } 
    } 
} 

namespace Test.Api.Classes 
{ 
    public class MyClass 
    { 
     private readonly IList<TableWithRelations> _tables; 

     public MyClass() 
     { 
      // tableA stuff 
      var tableA = new TableWithRelations { Member = { Id = 1, Name = "A" } }; 
      var relatedclasses = new List<ITable> 
      { 
       new MemberTable 
       { 
        Id = 2, 
        Name = "B" 
       } 
      }; 
      tableA.Partner = relatedclasses; 


      // tableB stuff 
      var tableB = new TableWithRelations { Member = { Id = 2, Name = "B" } }; 
      relatedclasses = new List<ITable> 
      { 
       new MemberTable 
       { 
        Id = 3, 
        Name = "C" 
       } 
      }; 
      tableB.Partner = relatedclasses; 


      // tableC stuff 
      var tableC = new TableWithRelations { Member = { Id = 3, Name = "C" } }; 
      relatedclasses = new List<ITable> 
      { 
       new MemberTable 
       { 
        Id = 2, 
        Name = "D" 
       } 
      }; 
      tableC.Partner = relatedclasses; 


      // tableD stuff 
      var tableD = new TableWithRelations { Member = { Id = 3, Name = "D" } }; 
      relatedclasses = new List<ITable> 
      { 
       new MemberTable 
       { 
        Id = 1, 
        Name = "A" 
       }, 
       new MemberTable 
       { 
        Id = 2, 
        Name = "B" 
       }, 
      }; 
      tableD.Partner = relatedclasses; 

      // add tables to the base tables collection 
      _tables = new List<TableWithRelations> { tableA, tableB, tableC, tableD }; 
     } 

     public IList<ITable> Compare(int tableId, string tableName) 
     { 
      return _tables.Where(table => table.Member.Id == tableId 
          && table.Member.Name == tableName) 
         .SelectMany(table => table.Partner).ToList(); 
     } 
    } 
} 

namespace Test.Api 
{ 
    public class TestClass 
    { 
     private readonly MyClass _myclass; 
     private readonly IList<ITable> _relatedMembers; 

     public IList<ITable> RelatedMembers 
     { 
      get { return _relatedMembers; } 
     } 

     public TestClass(int id, string name) 
     { 
      this._myclass = new MyClass(); 
      // the Compare method would take your two paramters and return 
      // a mathcing set of related tables that formed the related tables 
      _relatedMembers = _myclass.Compare(id, name); 
      // now do something wityh the resulting list 
     } 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     // change these values to suit, along with rules in MyClass 
     var id = 3; 
     var name = "D"; 
     var testClass = new TestClass(id, name); 

     Console.Write(string.Format("For Table{0} on Id{1}\r\n", name, id)); 
     Console.Write("----------------------\r\n"); 
     foreach (var relatedTable in testClass.RelatedMembers) 
     { 
      Console.Write(string.Format("Related Table{0} on Id{1}\r\n", 
         relatedTable.Name, relatedTable.Id)); 
     } 
     Console.Read(); 
    } 
} 

Ich werde in ein wenig zurück, um zu sehen, ob es passt oder nicht.

+0

Hallo Jim, das ist genau das, was ich wollte. Danke vielmals. Eigentlich versuche ich das Problem nur für das dynamische Erzeugen von Spalten zu lösen. Aber mein Manager sagte mir, ich solle eine Lösung auf der konzeptionellen Ebene machen, anstatt sie zu reparieren. Dies ist ein sehr großes System, bei dem Anbieter und Verbraucher ständig Daten laden und konsumieren. Er wollte also eine Lösung, die allgemein sein kann. Vielen dank für Deine Hilfe. Genau das habe ich mir gedacht. Aber ich denke, ich muss mehr Informationen über das System erhalten und an der Lösung arbeiten, die allgemein genug ist, um sie auf jedem System anzuwenden. – MNC

+0

haben Sie keine Angst, es ein Häkchen zu geben und Antwort-Marke als beantwortet dann :) - hoffe, Sie schaffen es, um für alle Szenarien erweiterbar zu sein. Jahreszeiten Grüße ... –

+0

Hallo Jim, Wie wählt man 2 Beiträge als Antwort. Wie ich versuche, Antwort auf Ihre und @APC zu markieren. Es erlaubt mir nicht, beide als Antwort zu markieren. – MNC

4

Eine einfache Abfrage wie dies hilft Ihnen, jeden Spalt Namen einer Tabelle in Oracle zu kennen.

Select COLUMN_NAME from user_tab_columns where table_name='EMP' 

es in Ihrem Code verwenden :)

+0

Meine Sorge ist Bedingung, die entscheidet, welche Tabelle abzufragen ist. Die Variable Bedingung Wie die Bedingung A ist, dann laden von TabelleX, wenn die Bedingung B ist, dann laden von TabelleA & tableY.Wir müssen wissen, aus welcher Tabelle wir Daten erhalten müssen, Sobald wir die Tabelle kennen, ist es einfach wie du vorgeschlagen hast. & ihre ist eine weitere Bedingung gibt es einige Spalten, die ausgeschlossen werden müssen & diese Spalten sind für jede Tabelle so unterschiedlich was ist der beste Weg zum Speichern von Bedingung, Tabellenname, Spalten ausschließen ist in der Datenbank speichern sind ihre any andere Möglichkeiten & wenn ja, die beste – MNC

+0

@MNC: Was ich in thr Code tun würde, ist die Spaltennamen jeder Tabelle in enums, abhängige oder nicht von den Bedingungen beteiligt, wenn Sie bevorzugen, laden Sie nur die Enums erforderlich, oder Sie laden alle am Anfang Ihres Codes. Über das Ausschließen von Spalten und Bedingungen ist es in der Datenbank von großem Interesse, dass Sie Ihre Anwendung nicht erneut erstellen müssen, wenn Sie Ihre Parameter ändern. Ich würde es so machen. – LaGrandMere

+0

@LeGrandMere Tut mir leid, ich schätze, ich gebe nicht genügend Informationen. Es gibt einige Variablen, die weiter unterteilt sind. Lassen Sie mich ein Beispiel geben. Es gibt 2 Variablen, Name, Name. Für die meisten auf der ID basierenden Abfragen ermitteln wir den Tabellennamen und extrahieren Daten. Aber für einige Ids müssen wir auch Namen berücksichtigen. Wie wenn ID 5 ist, dann haben wir Check-Name, wenn Id 5 ist und Name ist A, dann laod Tabelle A, wenn ID 5 ist Name ist B dann Laden von TableB, TableA etc ... Also, wenn wir Enum auf die IDs verwenden , dann könnten wir den Namen Zustand vermissen. – MNC

0

MNC,

Wie wäre es vorne ein Wörterbuch aller bekannten beteiligten Tabellen im Bewerbungsprozess zu schaffen (unabhängig von den Kombinationen - nur ein Wörterbuch der Tabellen), die auf Tabellenname eingegeben wird. Die Mitglieder dieses Wörterbuchs wären IList<string> der Spaltennamen. Dies würde Ihnen erlauben, zwei Tabellen sowohl hinsichtlich der Anzahl der vorhandenen Spalten dicTable[myVarTableName].Count als auch der dicTable[myVarTableName].value Iteration zu vergleichen, um die Spaltennamen herauszuziehen.

Am Ende des Stücks könnten Sie eine kleine Linq-Funktion ausführen, um die Tabelle mit der größten Anzahl von Spalten zu bestimmen und die Struktur entsprechend mit Nullen zu erstellen.

Hoffe, das gibt Denkanstöße ..

+0

@Jim Sorry, ich gebe nicht genügend Informationen. Es gibt einige Variablen, die weiter unterteilt sind. Lassen Sie mich ein Beispiel geben. Es gibt 2 Variablen, Name, Name. Für die meisten auf der ID basierenden Abfragen ermitteln wir den Tabellennamen und extrahieren Daten. Aber für einige Ids müssen wir auch Namen berücksichtigen. Wenn ID 5 ist, dann haben wir den Namen überprüfen, wenn Id 5 ist und Name ist A, dann laod Tabelle A, wenn ID 5 ist Name ist B dann Laden von TableB, TableA etc ... Also wenn wir Wörterbuch verwenden dann einschalten die IDs, dann könnten wir den Namen Bedingung vermissen. – MNC

+0

Sorry, ich wollte die Tabellendaten nicht in das Wörterbuch laden, sondern nur die Meta-Daten (d. H. Schlüssel auf Tabellenname mit Spaltennamen in der IList <>). Sie könnten einen Entscheidungsbaum in linq erstellen, indem Sie die erforderliche Logik weiter in ein reicheres Wertobjekt extrapolieren. –

+0

Auch ich habe es nicht als Laoding-Tabelle Daten im Wörterbuch nur die Metadaten. Aber die Bedingung ist abhängig von 2 Werten. Das war meine Sorge. Es wäre eine große Hilfe, wenn Sie ein Beispiel geben könnten. Danke. – MNC

1

Worauf Sie wirklich hinaus wollen, ist das Entwickeln einer Regel-Engine zum Erstellen dynamischer Abfragen. Dies ist kein kleines Unternehmen. Die Anforderungen, die Sie zur Verfügung gestellt haben, sind:

  1. Shop Regeln (was man eine „Zustandsgröße“ nennen)
  2. Jede Regel wählt aus einem oder mehreren Tabellen
  3. Zusätzlich einige Regeln Spalten angeben, aus einer Tabelle ausgeschlossen werden
  4. Regeln, die aus mehreren Tabellen auswählen, sind mit dem Operator UNION ALL zufrieden; Tabellen, deren Projektionen nicht übereinstimmen, müssen mit Nullspalten ausgerichtet werden.

Einige mögliche Anforderungen, die Sie erwähnen nicht:

  1. Format Maskierung z.B. einschließlich oder das Zeitelement von DATE-Spalt ohne
  2. die Reihenfolge der Spalten in der Projektion der Abfrage ändern
  3. Die bisherige Forderung ist besonders bedeutsam, wenn es um die Multi-Table-Regeln kommt, da die Projektionen der Tabellen übereinstimmen müssen Datentyp sowie Anzahl der Spalten.
  4. Darauf folgend müssen die Füll-NULL-Spalten nicht notwendigerweise an das Ende der Projektion angeheftet werden, z. Eine Drei-Spalten-Tabelle kann einer Vier-Spalten-Tabelle als col1, col2, null, col3 zugeordnet werden.
  5. Einige Multitabellenabfragen müssen möglicherweise erfüllt werden, indem Joins anstelle von Operationen gesetzt wird.
  6. Regeln zum Hinzufügen von WHERE-Klauseln.
  7. Ein Mechanismus zum Definieren von Standardsätzen von ausgeschlossenen Spalten (d. H. Die jedes Mal angewendet werden, wenn eine Tabelle abgefragt wird).

Ich würde diese Regeln in Datenbanktabellen speichern. Weil sie Daten sind und Daten speichern, wofür Datenbanken sind. (Es sei denn, Sie bereits eine Regel-Engine zur Hand.)

Unter dem ersten Satz von Anforderungen, die Sie benötigen drei Tabellen:

RULES 
----- 
RuleID 
Description 
    primary key (RuleID) 

RULE_TABLES 
----------- 
RuleID 
Table_Name 
Table_Query_Order 
All_Columns_YN 
No_of_padding_cols 
    primary key (RuleID, Table_Name) 


RULE_EXCLUDED_COLUMNS 
--------------------- 
RuleID 
Table_Name 
Column_Name 
    primary key (RuleID, Table_Name, Column_Name) 

ich verwendet habe Verbindung Primärschlüssel, nur weil es einfacher ist, mit ihnen zu arbeiten in dieser Kontext z laufende Wirkungsanalysen; Ich würde es nicht für normale Anwendungen empfehlen.

Ich denke, alle diese sind selbsterklärend mit Ausnahme der zusätzlichen Spalten auf RULE_TABLES.

  • Table_Query_Order gibt die Reihenfolge an, in der die Tabellen in UNION ALL-Abfragen angezeigt werden; Dies ist nur von Bedeutung, wenn Sie die column_names der führenden Tabelle als Überschriften in der CSV-Datei verwenden möchten.
  • All_Columns_YN gibt an, ob die Abfrage als SELECT * geschrieben werden kann oder ob Sie die Spaltennamen aus dem Data Dictionary und der Tabelle RULE_EXCLUDED_COLUMNS abfragen müssen.
  • No_of_padding_cols ist eine vereinfachte Implementierung für übereinstimmende Projektionen in diesen UNION ALL-Spalten, indem angegeben wird, wie viele NULL am Ende der Spaltenliste hinzugefügt werden sollen.
  • Ich werde nicht die Anforderungen angehen, die Sie nicht angegeben haben, weil ich nicht weiß, ob Sie sich um sie kümmern. Die grundlegende Sache ist, was dein Chef verlangt, ist eine Anwendung an seinem eigenen Recht. Denken Sie daran, dass Sie nicht nur eine Anwendung zum Generieren von Abfragen benötigen, sondern auch eine Schnittstelle zum Verwalten der Regeln benötigen.

    +0

    danke für die Antwort Ich plane, dies zu implementieren Welche Datenstruktur können wir verwenden, wenn wir dies implementieren, wenn wir dies im Speicher speichern möchten? oder ist es am besten, unseren eigenen Datentyp zu implementieren? Wenn die App zum ersten Mal geladen wird, können wir die Regeln und die entsprechenden Tabellen abrufen. Wenn wir die SQL-Abfrage erstellen und im Speicher speichern können, welche die Datenstruktur ist, ist das richtiger? – MNC

    Verwandte Themen