0

我的数据库中有 2 个表,其中一个名为 Sales.Salesperson,它是源数据库,目标数据库是 dbo.Salesperson。我制作了一个 BIML,它使用 C# 代码从源获取现有表的列表,然后将所有数据从源导入到目标,例如,我只有上面列出的 1 个表。在 C# 上,我使用 SQL 连接和 SQL 命令来获取所有表的表和架构(同样只有 1 个,所以它可以是动态的),

问题,因为我有一个句点来分隔模式和表,在我的 SQL 命令中,当我从 BIML 转到生成 SSIS 包时,当我尝试截断表时,它会从 SSIS 步骤 EXECUTESQL DirectInput 给我一条错误消息<#=表 #> 错误显示“DynamicDataLoad 包中的 Sales.SalesPerson 包含 SSIS 的无效字符 (/:[].=)。无效字符将替换为 _”,因此,我的 SSIS 包出现错误

这是下面的代码以提供帮助:

<Biml xmlns="http://schemas.varigence.com/biml.xsd">
    <Packages>
        <Package Name="DynamicDataLoad" ConstraintMode ="Linear"          ProtectionLevel="DontSaveSensitive">
        <Tasks>
            <# foreach(var table in GetTables()) { #>
            <ExecuteSQL Name="Truncate Table Dest <#=table#>" ConnectionName="Target">
                **<DirectInput>Truncate Table <#=table#></DirectInput>          
            </ExecuteSQL>**
            <Dataflow Name="Load Table <#=table#>" >
                <Transformations>
                    <OleDbSource Name="Source Table" ConnectionName="Source">
                        <ExternalTableInput Table="<#=table#>" />
                    </OleDbSource>
                    <OleDbDestination Name="Destination Table" ConnectionName="Target">
                        <ExternalTableOutput Table="<#=table#>" />
                    </OleDbDestination>
                </Transformations>
            </Dataflow>
          <# } #>
        </Tasks>
    </Package>
 </Packages>
</Biml>

下面是 C# 部分,如果您查看 SQL 命令,我将带回 Schema,然后是一个名为“表”的列表中的表,它在上面的 BIML 中用于列出所有要转换为 SSIS 包的表,这用于BIML 部分称为截断,这是 BIML 中错误的来源。

<#+
List<string> GetTables() {
    List<string> tables = new List<string>();

        SqlConnection cn = new SqlConnection("Data Source=mdsdqsdev;Initial Catalog=Test;Persist Security Info=False;Integrated Security=SSPI;");
        SqlDataAdapter da = new SqlDataAdapter();
        DataSet ds = new DataSet();
        DataTable dt = new DataTable();

        string q = "Select TABLE_SCHEMA+'.'+TABLE_NAME as name from INFORMATION_SCHEMA.TABLES";

        var cmd = new SqlCommand(q);
        cmd.Connection = cn;

    try 
    {
            da.SelectCommand = cmd;

            ds.Tables.Add(new DataTable("Results"));

            if(cn.State != ConnectionState.Open)
            {
                cn.Open();
            }

            ds.Tables[0].BeginLoadData();
            da.Fill(ds,"Results");
            ds.Tables[0].EndLoadData();

            dt = ds.Tables[0];

            if(cn.State != ConnectionState.Closed)
            {
                cn.Close();
            }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        if (cn.State != ConnectionState.Closed)
        {
            cn.Close();
        }
        cn.Dispose();
    }

    foreach (DataRow row in dt.Rows)
    {
        tables.Add(row["name"].ToString());
    }

    return tables;
}

#>
4

1 回答 1

0

由于您的表变量将以 schema.table 的形式生成<ExecuteSQL Name="Truncate Table Dest <#=table#>" ConnectionName="Target"><Dataflow Name="Load Table <#=table#>" >因此您的数据流的名称将类似于“Dataflow Foo.Bar”,如果您尝试手动键入,SSDT 会拒绝指定您不能这样命名。

解决此特定问题的方法是执行“安全”字符串之类的操作。一种低租金的方法是应用一个 Replace 调用来交换该期间的下划线。

<ExecuteSQL Name="Truncate Table Dest <#=table.Replace(".", "_")#>" ConnectionName="Target">

更大的问题是表或模式中包含无效字符或空格。这将需要你用 [] 包装它们。我不会盲目地应用它们,而是将这项工作推送到 SQL ServerQUOTENAME()

Select QUOTENAME(TABLE_SCHEMA) +'.' + QUOTENAME(TABLE_NAME) as name

我发现将模式和表名作为离散部分返回通常会更好,因为我发现连接比拆分容易得多。这使得 GetTables() 的签名不同。也许List<KeyValuePair<string, string>>,我不知道。

即便如此,当原生 Biml 方式大约是 4 行代码时,您仍然做的工作比我想做的要多。我有一个示例,我使用 Biml 对数据库的特定模式进行逆向工程,但在 Biml + GetDatabaseSchema 上搜索将为您提供许多如何执行此操作的示例。

于 2017-02-17T17:59:50.660 回答