2010-12-20 41 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

相关问题