从 Oracle 表动态获取列名的最佳方法

发布于 2024-10-08 19:05:16 字数 674 浏览 6 评论 0原文

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

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

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


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

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

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

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

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

谢谢,

We are using an extractor application that will export data from the database to csv files. Based on some condition variable it extracts data from different tables, and for some conditions we have to use UNION ALL as the data has to be extracted from more than one table. So to satisfy the UNION ALL condition we are using nulls to match the number of columns.

Right now all the queries in the system are pre-built based on the condition variable. The problem is whenever there is change in the table projection (i.e new column added, existing column modified, column dropped) we have to manually change the code in the application.

Can you please give some suggestions how to extract the column names dynamically so that any changes in the table structure do not require change in the code?


My concern is the condition that decides which table to query. The variable condition is
like

  • if the condition is A, then load from TableX
  • if the condition is B then load from TableA and TableY.

We must know from which table we need to get data. Once we know the table it is straightforward to query the column names from the data dictionary. But there is one more condition, which is that some columns need to be excluded, and these columns are different for each table.

I am trying to solve the problem only for dynamically generating the list columns. But my manager told me to make solution on the conceptual level rather than just fixing. This is a very big system with providers and consumers constantly loading and consuming data. So he wanted solution that can be general.

So what is the best way for storing condition, tablename, excluded columns? One way is storing in database. Are there any other ways? If yes what is the best? As I have to give at least a couple of ideas before finalizing.

Thanks,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

jJeQQOZ5 2024-10-15 19:05:16

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

Select COLUMN_NAME from user_tab_columns where table_name='EMP'

在您的代码中使用它:)

A simple query like this helps you to know each column name of a table in Oracle.

Select COLUMN_NAME from user_tab_columns where table_name='EMP'

Use it in your code :)

若无相欠,怎会相见 2024-10-15 19:05:16

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

我稍后会回来看看它是否合适。

Ok, MNC, try this for size (paste it into a new console app):

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

I'll get back in a bit to see if it fits or not.

厌倦 2024-10-15 19:05:16

因此,您真正想要的是设计一个用于构建动态查询的规则引擎。这不是一件小事。您提供的要求包括:

  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 文件中的标题时,这才重要。
  • All_Columns_YN 指示查询是否可以写为 SELECT * 或者是否需要从数据字典和 RULE_EXCLUDED_COLUMNS 表中查询列名。
  • No_of_padding_cols 是通过指定要添加到列列表末尾的 NULL 数量来匹配这些 UNION ALL 列中的投影的简单实现。

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

So what you are really after is designing a rule engine for building dynamic queries. This is no small undertaking. The requirements you have provided are:

  1. Store rules (what you call a "condition variable")
  2. Each rule selects from one or more tables
  3. Additionally some rules specify columns to be excluded from a table
  4. Rules which select from multiple tables are satisfied with the UNION ALL operator; tables whose projections do not match must be brought into alignment with null columns.

Some possible requirements you don't mention:

  1. Format masking e.g. including or excluding the time element of DATE columns
  2. Changing the order of columns in the query's projection
  3. The previous requirement is particularly significant when it comes to the multi-table rules, because the projections of the tables need to match by datatype as well as number of columns.
  4. Following on from that, the padding NULL columns may not necessarily be tacked on to the end of the projection e.g. a three column table may be mapped to a four column table as col1, col2, null, col3.
  5. Some multi-table queries may need to be satisfied by joins rather than set operations.
  6. Rules for adding WHERE clauses.
  7. A mechanism for defining default sets of excluded columns (i.e. which are applied every time a table is queried) .

I would store these rules in database tables. Because they are data and storing data is what databases are for. (Unless you already have a rules engine to hand.)

Taking the first set of requirements you need three tables:

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)

I've used compound primary keys just because it's easier to work with them in this context e.g. running impact analyses; I wouldn't recommend it for regular applications.

I think all of these are self-explanatory except the additional columns on RULE_TABLES.

  • Table_Query_Order specifies the order in which the tables appear in UNION ALL queries; this matters only if you want to use the column_names of the leading table as headings in the CSV file.
  • All_Columns_YN indicates whether the query can be written as SELECT * or whether you need to query the column names from the data dictionary and the RULE_EXCLUDED_COLUMNS table.
  • No_of_padding_cols is a simplistic implementation for matching projections in those UNION ALL columns, by specifying how many NULLs to add to the end of the column list.

I'm not going to tackle those requirements you didn't specify because I don't know whether you care about them. The basic thing is, what your boss is asking for is an application in its own right. Remember that as well as an application for generating queries you're going to need an interface for maintaining the rules.

捂风挽笑 2024-10-15 19:05:16

MNC,

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

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

希望这能给人深思。

MNC,

How about creating a dictionary of all the known tables involved in the application process up front (irrespective of the combinations - just a dictionary of the tables) which is keyed on tablename. the members of this dictionary would be a IList<string> of the column names. This would allow you to compare two tables on both the number of columns present dicTable[myVarTableName].Count as well as iterating round the dicTable[myVarTableName].value to pull out the column names.

At the end of the piece, you could do a little linq function to determine the table with the greatest number of columns and create the structure with nulls accordingly.

Hope this gives food for thought..

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文