2个数据表上的C#动态完全外部联接

2个数据表上的C#动态完全外部联接,c#,ssis,full-outer-join,C#,Ssis,Full Outer Join,我需要在两个数据表上进行完整的外部联接,我不知道数据表中有哪些列,但它们在每个表中都是相同的,我也只有在变量中进行联接所需的列的名称。有没有办法做到这一点 我需要做的是在一个C#脚本中连接两个数据表。我在SSIS中使用数据流从几个文件中获取数据,最后我需要比较最后两组数据。只要两个数据表具有相同的列,我就需要对它们执行此操作,因此我无法在SSIS中完成此过程,因为我需要指定列 GetData()我只是在需要比较两个表时使用它,但是SSI中的对象变量填充了donnesPROD和donnesDEV

我需要在两个数据表上进行完整的外部联接,我不知道数据表中有哪些列,但它们在每个表中都是相同的,我也只有在变量中进行联接所需的列的名称。有没有办法做到这一点

我需要做的是在一个C#脚本中连接两个数据表。我在SSIS中使用数据流从几个文件中获取数据,最后我需要比较最后两组数据。只要两个数据表具有相同的列,我就需要对它们执行此操作,因此我无法在SSIS中完成此过程,因为我需要指定列

GetData()我只是在需要比较两个表时使用它,但是SSI中的对象变量填充了
donnesPROD
donnesDEV

以下是我目前的代码:

DataTable donnesPROD = GetData(connectionPROD, sql_request);
DataTable donnesDEV = GetData(connectionDEV, sql_request);
下面是GetData的代码:

DataTable GetData(string cs, string query)
        {
            OleDbConnection conn = new OleDbConnection(cs);
            conn.Open();
            OleDbCommand cmd = new OleDbCommand(query, conn);

            DataTable dt = new DataTable();
            dt.Load(cmd.ExecuteReader());
            conn.Close();
            return dt;
        }
我有另一个datatable中的列列表,还有字符串变量
key
中主键的名称。从这里开始,我需要能够在
键上完成
donnesPROD
donnesDEV
。可以这样做吗?或者有没有一种方法可以自动生成脚本代码,然后执行它?

您有两种选择

条件连接 如果您不知道特定的列名,但确实知道列名可能是什么,则可以执行如下条件联接:

CREATE PROCEDURE ExampleDynamicJoin(@JoinColumn AS VarChar(40))
AS
BEGIN
    SELECT *
    FROM   TableA
    JOIN   TableB ON (@JoinColumn = 'ColumnA' AND TableA.ColumnA = TableB.ColumnA)
                  OR (@JoinColumn = 'ColumnB' AND TableA.ColumnB = TableB.ColumnB)
                  OR (@JoinColumn = 'ColumnC' AND TableA.ColumnC = TableB.ColumnC)
END
bool ValidateColumn(string columnName)
{
    switch columnName.ToUpper()
    {
        case "COLUMNA":
        case "COLUMNB":
        case "COLUMNC":
            return true;
        default:
            return false;
    }
}
您可能无法从中获得最佳性能(条件联接将混淆查询引擎,如果它选择了一个索引,它可能不会选择最佳索引)。如果桌子很大,你也可以这样做。这看起来有点痛苦,但会获得更好的性能:

CREATE PROCEDURE ExampleDynamicJoin(@JoinColumn AS VarChar(40))
AS
BEGIN
    IF (@JoinColumn = 'ColumnA') BEGIN
        SELECT *
        FROM   TableA
        JOIN   TableB ON TableA.ColumnA = TableB.ColumnA
    END
    IF (@JoinColumn = 'ColumnB') BEGIN
        SELECT *
        FROM   TableA
        JOIN   TableB ON TableA.ColumnB = TableB.ColumnB
    END
    IF (@JoinColumn = 'ColumnC') BEGIN
        SELECT *
        FROM   TableA
        JOIN   TableB ON TableA.ColumnC = TableB.ColumnC
    END
END
如果
TableA
TableA
是较大查询的一部分,并且最终会复制大量SQL,则始终可以将
TableA
TableB
的结果集提取到临时表中,然后在较大查询中使用临时表

动态结构化查询语言 如果您对列名没有任何模糊的认识,并且存在大量的可能性,那么可以将SQL构造为字符串并以这种方式连接。您应该验证传入的列名;这不仅可以确保列实际存在,而且可以防止在
@JoinColumn
包含注入攻击时构造动态SQL,因为合法的列名不包含SQL语句。例如:

CREATE PROCEDURE ExampleDynamicJoin(@JoinColumn AS VarChar(40))
AS
BEGIN
    DECLARE @Sql AS VarChar(MAX)

    IF NOT EXISTS 
    (
        SELECT 0 
        FROM syscolumns c 
        JOIN sysobjects o ON o.id = c.id
        WHERE  o.Name = 'TableA'
        AND    c.Name = @JoinColumn
    )
    RAISERROR  (15600,-1,-1, 'ExampleDynamicJoin');  //Throw error if column doesn't exist

    SET @Sql = 
       'SELECT *
        FROM   TableA
        JOIN   TableB ON TableA.' + @JoinColumn + ' = TableB.' + @JoinColumn

    sp_ExecuteSql @Sql
END
或者,如果不使用存储过程

DataTable ExampleDynamicJoin(string joinColumn)
{
    if (!ValidateColumn(joinColumn)) throw new ArgumentException();

    var sql = String.Format(
      @"SELECT * 
        FROM TableA 
        JOIN TableB ON TableA.{0} = TableB.{0}", 
        joinColumn
    );

    using (var connection = GetConnectionFromSomewhere())
    {
        using (var cmd = new SqlCommand
        {   
            CommandText = sql,
            CommandType = CommandType.Text,
            Connection = connection
        })
        {
            var reader = cmd.ExecuteReader();
            var table = new DataTable();
            table.Load(reader);
            return table;
        }
    }
}
使用动态SQL时,如果可能,应始终使用参数。但是您不能使用参数作为列名,因此在本例中,您必须连接。连接时,始终将输入列为白名单。这就是为什么我包含了一个名为
ValidateColumn
的函数,它可能如下所示:

CREATE PROCEDURE ExampleDynamicJoin(@JoinColumn AS VarChar(40))
AS
BEGIN
    SELECT *
    FROM   TableA
    JOIN   TableB ON (@JoinColumn = 'ColumnA' AND TableA.ColumnA = TableB.ColumnA)
                  OR (@JoinColumn = 'ColumnB' AND TableA.ColumnB = TableB.ColumnB)
                  OR (@JoinColumn = 'ColumnC' AND TableA.ColumnC = TableB.ColumnC)
END
bool ValidateColumn(string columnName)
{
    switch columnName.ToUpper()
    {
        case "COLUMNA":
        case "COLUMNB":
        case "COLUMNC":
            return true;
        default:
            return false;
    }
}

根本不清楚你在问什么或者你期望得到什么答案。对于您遇到的任何特定问题,请包括一个。请读一个好问题。请确保您的问题是具体的,而不是过于宽泛。看看这种方法:条件连接解决方案只适用于几乎微不足道的小表,因为连接条件不可搜索,因此始终会导致全表或索引扫描。感谢John Wu提供的所有示例。我将更新这个问题,但我需要做的是在一个C#脚本中连接两个数据表。我在SSIS中使用数据流从几个文件中获取数据,最后我需要比较最后两组数据。只要两个数据表具有相同的列,我就需要对它们执行此操作,因此我无法在SSIS中完成此过程,因为我需要指定列。