2010-12-20 84 views
0

我們正在使用一個將數據從數據庫導出到csv文件的提取應用程序。基於某些條件變量,它從不同的表中提取數據,對於某些條件,我們必須使用UNION ALL,因爲數據必須從多個表中提取。因此,爲了滿足UNION ALL條件,我們使用空值來匹配列數。從oracle表中動態獲取列名的最佳方法

現在系統中的所有查詢都是基於條件變量預先構建的。問題是每當表格投影發生變化時(即添加新列,修改現有列,刪除列),我們必須手動更改應用程序中的代碼。

您可以請給出一些建議,如何動態提取列名稱,以便表結構中的任何更改不需要更改代碼?


我的問題是決定查詢哪個表的條件。變量條件是 像

  • 如果條件爲A,然後從TableX的
  • 加載如果條件B,則來自表A和TableY加載。

我們必須知道從哪張表中我們需要獲取數據。一旦我們知道了表格,就可以直接從數據字典中查詢列名。但是還有一個條件,那就是需要排除一些列,並且這些列對於每個表是不同的。

我想解決這個問題只是爲了動態生成列表列。但是我的經理告訴我要在概念層面上解決問題,而不是僅僅解決問題。這是一個非常大的系統,供應商和消費者不斷地加載和使用數據。所以他想要解決方案可以是一般的。

那麼存儲條件,表名,排除列的最佳方式是什麼?一種方法是存儲在數據庫中。還有其他方法嗎?如果是,什麼是最好的?因爲在最終確定之前我必須給出至少兩個想法。

感謝,

回答

1

好吧,MNC,嘗試一下本作的大小(它粘貼到一個新的控制檯應用程序):

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(); 
    } 
} 

我會再回來,看看它是否適合與否。

+0

嗨,吉姆,這正是我想要的。非常感謝。其實我試圖解決這個問題只是爲了動態生成列。但是我的經理告訴我要在概念層面上解決問題,而不是解決問題。這是一個非常大的系統,供應商和消費者不斷地加載和使用數據。所以他想要的解決方案可以是一般的。非常感謝你的幫助。這正是我的想法。但是我想我必須獲得關於該系統的更多信息,並且研究可以適用於任何系統的通用解決方案。 – MNC 2010-12-20 22:23:00

+0

不要害怕給它一個答案和回答標記,因爲回答:)然後希望你設法將它塑造成可擴展的所有場景。季節問候... – 2010-12-21 08:17:46

+0

嗨吉姆,如何選擇2個職位作爲答案。正當我試圖標記答案給你和@APC。它不允許我將兩者都標記爲答案。 – MNC 2010-12-22 16:05:15

4

這樣一個簡單的查詢可以幫助您知道在Oracle中的表中的每一列名。

Select COLUMN_NAME from user_tab_columns where table_name='EMP' 

用它在你的代碼:)

+0

我的問題是決定查詢哪個表的條件。可變條件 如果條件爲A,則從tableX加載,如果條件爲 爲B,則從TableA和tableY加載我們必須知道從哪張表中我們需要獲取數據,一旦我們知道該表的一個簡單如你所建議的。 &他們是一個更多的條件,有一些列需要排除 &這些列對於每個表是不同的所以 什麼是存儲條件,表名,排除列的一種方式的最佳途徑 是存儲在數據庫中的是他們的任何其他方式 如果是最好的 – MNC 2010-12-20 15:46:42

+0

@MNC:我會在thr代碼中做的是,如果您希望只加載所需的枚舉,則可以根據條件獲取與枚舉有關的每個表的列名,你在代碼的開始加載它們。關於排除列和條件,在數據庫中執行它有一個主要的興趣,那就是當您更改參數時,不必再次構建應用程序。我會這樣做。 – LaGrandMere 2010-12-20 15:51:46

+0

@LeGrandMere對不起,我想我沒有提供足夠的信息。有一些變數被進一步分割。讓我舉個例子。有兩個變量Id,名稱。對於基於Id的大多數查詢,我們確定表名並提取數據。但對於某些我也必須考慮名字。如果id是5,那麼我們檢查名稱,如果Id是5,名稱是A,那麼laod表A,如果Id是5,那麼名稱是B,然後從tableB,tableA等加載...因此,如果我們使用枚舉ID ,那麼我們可能會錯過名稱條件。 – MNC 2010-12-20 16:05:43

0

MNC,

如何參與創造在申請過程中前面(不論組合所有已知表的字典 - 只是一本字典的表格),這是鍵入表名。該字典的成員將是列名稱的IList<string>。這將允許您比較兩個表中的兩個表,這兩個表都存在於dicTable[myVarTableName].Count列的列數中,以及圍繞dicTable[myVarTableName].value迭代以提取列名稱。

在作品的最後,你可以做一些linq函數來確定列數最多的表格,並相應地用空值創建結構。

希望這可以帶給我們深思。

+0

@Jim對不起,我想我沒有提供足夠的信息。有一些變數被進一步分割。讓我舉個例子。有兩個變量Id,名稱。對於基於Id的大多數查詢,我們確定表名並提取數據。但對於某些我也必須考慮名字。如果id爲5,那麼我們檢查名稱,如果Id是5並且名稱是A,那麼laod表A,如果Id是5,則名稱是B,然後從tableB,tableA等加載...因此,如果我們使用字典,則鍵入ID,那麼我們可能會錯過名稱條件。 – MNC 2010-12-20 16:06:41

+0

對不起,我沒有意義將表數據加載到字典中,只有元數據(即在IList <>中鍵入帶有列名的表名)。你可以通過將所需邏輯進一步外推到更豐富的值對象中來創建linq中的決策樹。 – 2010-12-20 16:10:28

+0

即使我沒有把它作爲字典中只有元數據的表格數據。但條件取決於2個值。這是我的擔憂。如果你能舉一個例子,這將是很大的幫助。謝謝你。 – MNC 2010-12-20 16:21:57

1

那麼你真的在設計一個建立動態查詢的規則引擎。這不是一件小事。您提供的要求是:

  1. 商店的規則(你所謂的「條件變量」)
  2. 每個規則選擇一個或多個表
  3. 此外,一些規則指定的列從表中排除
  4. 從UNION ALL運算符滿足從多個表中選擇的規則;其投影不匹配的表必須與空列對齊。

一些可能要求你不提:

  1. 格式例如屏蔽包括或不包括DATE列的時間元素
  2. 更改查詢投影中列的順序
  3. 對於多表規則,以前的要求特別重要,因爲表的投影需要匹配數據類型以及列數。
  4. 接下來,填充NULL列可能不一定要粘貼到投影的結尾,例如,三列表可以被映射到四列表格,如col1, col2, null, col3
  5. 某些多表查詢可能需要由加入而不是設置操作來滿足。
  6. 添加WHERE子句的規則。
  7. 用於定義排除列的默認集合(即,每次查詢表格時應用的列)的機制。

我會將這些規則存儲在數據庫表中。因爲它們是數據,而存儲數據是數據庫的用途。 (除非你已經有一個規則引擎來的手。)

以第一組的要求,你需要三個表:

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) 

我用複合主鍵,只是因爲它更容易與他們工作這個上下文例如運行影響分析;我不會推薦它用於常規應用程序。

我認爲所有這些都是不言而喻的,除了RULE_TABLES上的其他列。

  • Table_Query_Order指定表在UNION ALL查詢中出現的順序;這隻有在您想要使用CSV表頭中的column_names作爲CSV文件中的標題時才起作用。
  • All_Columns_YN指示查詢是否可以寫爲SELECT *或是否需要從數據字典和RULE_EXCLUDED_COLUMNS表中查詢列名。
  • No_of_padding_cols是通過指定要添加到列列表末尾的NULL數量來匹配那些UNION ALL列中的投影的簡單實現。

我不打算解決你沒有指定的那些要求,因爲我不知道你是否在意他們。基本的事情是,你的老闆要求的是一個應用程序本身。請記住,除了生成查詢的應用程序之外,您還需要一個用於維護規則的接口。

+0

感謝您的答案我打算實現這個如果我們想要將它存儲在內存中,我們可以使用什麼數據結構?或者最好是實現我們自己的數據類型?即第一次加載應用程序時,我們可以獲取規則和相應的表格。如果我們可以構建sql查詢並將其存儲在數據結構的內存中,即更正確? – MNC 2010-12-27 16:03:58

相關問題