0

我们正在使用一个提取器应用程序,它将数据从数据库导出到 csv 文件。它基于一些条件变量从不同的表中提取数据,对于某些条件,我们必须使用 UNION ALL,因为必须从多个表中提取数据。因此,为了满足 UNION ALL 条件,我们使用空值来匹配列数。

现在系统中的所有查询都是基于条件变量预先构建的。问题是每当表投影发生变化(即添加新列、修改现有列、删除列)时,我们都必须手动更改应用程序中的代码。

您能否提供一些建议如何动态提取列名,以便表结构的任何更改都不需要更改代码?


我关心的是决定查询哪个表的条件。变量条件就像

  • 如果条件为 A,则从 TableX 加载
  • 如果条件为 B,则从 TableA 和 TableY 加载。

我们必须知道我们需要从哪个表中获取数据。一旦我们知道了表,就可以直接从数据字典中查询列名。但是还有一个条件,就是需要排除一些列,而这些列对于每个表都是不同的。

我试图解决这个问题只是为了动态生成列表列。但我的经理告诉我要在概念层面提出解决方案,而不仅仅是修复。这是一个非常大的系统,提供者和消费者不断地加载和消费数据。所以他想要通用的解决方案。

那么存储条件、表名、排除列的最佳方式是什么?一种方法是存储在数据库中。还有其他方法吗?如果是,什么是最好的?因为我必须在最终确定之前至少给出几个想法。

谢谢,

4

4 回答 4

4

像这样的简单查询可以帮助您了解 Oracle 中表的每个列名。

Select COLUMN_NAME from user_tab_columns where table_name='EMP'

在您的代码中使用它:)

于 2010-12-20T15:38:43.453 回答
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();
    }
}

我一会儿回来看看它是否合适。

于 2010-12-20T17:43:12.227 回答
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 查询中出现的顺序;仅当您想使用前导表的 column_names 作为 CSV 文件中的标题时,这才重要。
  • All_Columns_YN表示查询是否可以写为 SELECT * 或者是否需要从数据字典和 RULE_EXCLUDED_COLUMNS 表中查询列名。
  • No_of_padding_cols是一个简单的实现,用于匹配那些 UNION ALL 列中的投影,通过指定将多少 NULL 添加到列列表的末尾。

我不会解决您未指定的那些要求,因为我不知道您是否关心它们。基本的事情是,你的老板要求的是一个应用程序本身。请记住,除了用于生成查询的应用程序之外,您还需要一个用于维护规则的接口。

于 2010-12-21T06:51:10.393 回答
0

跨国公司,

如何预先创建应用程序进程中涉及的所有已知表的字典(无论组合如何 - 只是表的字典),它以表名为键。该字典的成员将是IList<string>列名中的一个。这将允许您比较两个表的列数dicTable[myVarTableName].Count以及迭代dicTable[myVarTableName].value以提取列名。

在文章的最后,您可以执行一个小 linq 函数来确定具有最多列数的表,并相应地创建具有空值的结构。

希望这能给人以思考..

于 2010-12-20T15:53:47.813 回答