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