SSIS包 - 从一个表到无限表,具体取决于数据

时间:2014-12-05 16:45:10

标签: ssis

我有一个简单的要求。我有一个包含产品名称及其计数的表格。我想创建一个SSIS包,根据产品名称将数据从一个表提取到无限表。 在表格中,如果我有10个产品,那么SSIS包应该动态地创建10个表,每个表中有一个产品。

表名:产品

ProductName  , QuantitySold
   ABC              10
   xyz              15
   Testing          25

表名:ABC

ProductName  , QuantitySold
   ABC              10

表名:XYZ

ProductName  , QuantitySold
   xyz              15

表名:测试

ProductName  , QuantitySold
   ABC              10

1 个答案:

答案 0 :(得分:2)

从概念上讲,你正在寻找像

这样的东西

enter image description here

概念是您将识别表中的所有产品名称并在每行上执行2个任务:如果需要,创建目标表。针对该行的源运行查询并将其加载到表中。

变量

我声明了6个变量

enter image description here

Query_TableCreateBase是一个格式化为

的大字符串
IF  NOT EXISTS
(
    SELECT
        *
    FROM
        sys.tables AS T
    WHERE
        T.name = '<Table/>'
)
BEGIN
    CREATE TABLE dbo.<Table/>
    (
        ProductName varchar(30) NOT NULL
    ,   QuantitySold int NOT NULL
    );
END

我在Query_Source,Query_TableCreate和TargetTable

上有表达式

Query_Source表达式

"SELECT ProductName, QuantitySold FROM (
    VALUES
        ('ABC', 10)
    ,   ('xyz', 15)
    ,   ('Testing', 25)
) Products(ProductName, QuantitySold) WHERE ProductName = '" + @[User::ProductName] + "'"

Query_TableCreate表达式

replace(@[User::Query_TableCreateBase], "<Table/>", @[User::ProductName])

TargetTable表达式

"[dbo].[" +@[User::ProductName] + "]"

SQL Get Rows

我使用查询模拟您的Products表。我将这些结果加载到名为RS_Product的变量中。

SELECT 
ProductName
FROM
(
    VALUES
        ('ABC', 10)
    ,   ('xyz', 15)
    ,   ('Testing', 25)
) Products(ProductName, QuantitySold);

FELC粉碎结果

我使用Foreach循环容器,设置为处理ADO结果集并将第0列解析为我们的ProductName变量

SQL Create表(如果需要)

这是一个被评估为类似

的查询
IF  NOT EXISTS
(
    SELECT
        *
    FROM
        sys.tables AS T
    WHERE
        T.name = 'Foo'
)
BEGIN
    CREATE TABLE dbo.Foo
    (
        ProductName varchar(30) NOT NULL
    ,   QuantitySold int NOT NULL
    );
END

DFT加载表

我将此设置为DelayValidation = true,因为该表可能不会存在,直到它获得启动信号。

再次,模拟您的Products表,我的查询看起来像

SELECT ProductName, QuantitySold FROM (
    VALUES
        ('ABC', 10)
    ,   ('xyz', 15)
    ,   ('Testing', 25)
) Products(ProductName, QuantitySold) WHERE ProductName = 'Foo'

结束语

严格地说,不需要数据流。如果我们撤回源查询中的所有列,则可以通过您的执行SQL任务完成所有操作。

Biml实施

商业智能标记语言Biml描述了商业智能平台。在这里,我们将使用它来描述ETL。 BIDS Helper,是Visual Studio / BIDS / SSDT的免费补充,它解决了许多缺点。具体来说,我们将使用将描述ETL的Biml文件转换为SSIS包的能力。这样做的另一个好处是为您提供了一种机制,可以准确生成我所描述的解决方案,而不是点击许多繁琐的对话框。

以下代码假定您在本地计算机上有一个默认实例,而在tempdb中,您有一个名为Foo的表。

    use tempdb;
    GO
    CREATE TABLE dbo.Foo
    (
        ProductName varchar(30) NOT NULL
    ,   QuantitySold int NOT NULL
    );

将以下脚本保存到.biml文件中,当您添加到SSIS项目时,该文件将显示在Miscellaneous虚拟文件夹下。右键单击,选择Generate SSIS Package,它应该创建一个名为so_27320726

的包
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
    <Connections>
        <OleDbConnection Name="tempdb" ConnectionString="Data Source=localhost;Initial Catalog=tempdb;Provider=SQLNCLI10.1;Integrated Security=SSPI;" />
    </Connections>
    <Packages>
        <Package Name="so_27320726" ConstraintMode="Parallel" >
            <Variables>
                <Variable Name="ProductName" DataType="String">Foo</Variable>
                <Variable Name="Query_Source" DataType="String" EvaluateAsExpression="true">"SELECT ProductName, QuantitySold FROM (
    VALUES
        ('ABC', 10)
    ,   ('xyz', 15)
    ,   ('Testing', 25)
) Products(ProductName, QuantitySold) WHERE ProductName = '" + @[User::ProductName] + "'"</Variable>
                <Variable Name="Query_TableCreate" DataType="String" EvaluateAsExpression="true"><![CDATA[replace(@[User::Query_TableCreateBase], "<Table/>", @[User::ProductName])]]></Variable>
                <Variable Name="Query_TableCreateBase" DataType="String" ><![CDATA[IF  NOT EXISTS
(
    SELECT
        *
    FROM
        sys.tables AS T
    WHERE
        T.name = '<Table/>'
)
BEGIN
    CREATE TABLE dbo.<Table/>
    (
        ProductName varchar(30) NOT NULL
    ,   QuantitySold int NOT NULL
    );
END]]></Variable>
                <Variable Name="RS_Product" DataType="Object" />
                <Variable Name="TargetTable" DataType="String" EvaluateAsExpression="true">"[dbo].[" +@[User::ProductName] + "]"</Variable>
            </Variables>
            <Tasks>
                <ExecuteSQL Name="SQL Get Rows" ConnectionName="tempdb" ResultSet="Full">
                    <Variables>
                        <Variable Name="Variable" DataType="Int32" IncludeInDebugDump="Include">0</Variable>
                    </Variables>
                    <Results>
                        <Result Name="0" VariableName="User.RS_Product" />
                    </Results>
                    <DirectInput>SELECT
*
FROM
(
    VALUES
        ('ABC', 10)
    ,   ('xyz', 15)
    ,   ('Testing', 25)
) Products(ProductName, QuantitySold);</DirectInput>
                </ExecuteSQL>
                <ForEachAdoLoop Name="FELC Shred Results" ConstraintMode="Linear" SourceVariableName="User.RS_Product">
                    <PrecedenceConstraints>
                        <Inputs>
                            <Input OutputPathName="SQL Get Rows.Output" SsisName="Constraint" />
                        </Inputs>
                    </PrecedenceConstraints>
                    <Tasks>
                        <ExecuteSQL Name="SQL Create Table if needed" ConnectionName="tempdb">
                            <VariableInput VariableName="User.Query_TableCreate" />
                        </ExecuteSQL>
                        <Dataflow Name="DFT Load Table" DelayValidation="true">
                            <Transformations>
                                <OleDbSource Name="OLE_SRC Get Data" DefaultCodePage="1252" ConnectionName="tempdb">
                                    <VariableInput VariableName="User.Query_Source" />
                                </OleDbSource>
                                <OleDbDestination Name="OLE_DST Save data" ConnectionName="tempdb" >
                                    <TableFromVariableOutput VariableName="User.TargetTable" />
                                    <Columns>
                                        <Column SourceColumn="ProductName" TargetColumn="ProductName" />
                                        <Column SourceColumn="QuantitySold" TargetColumn="QuantitySold" />
                                    </Columns>
                                </OleDbDestination>
                            </Transformations>
                        </Dataflow>
                    </Tasks>
                    <VariableMappings>
                        <VariableMapping Name="0" VariableName="User.ProductName" />
                    </VariableMappings>
                </ForEachAdoLoop>
            </Tasks>
            <Connections>
                <Connection ConnectionName="tempdb" />
            </Connections>
        </Package>
    </Packages>
</Biml>