如何编写生成xml和xsd的`select ... FOR XML`查询,以便为SQLXMLBulkLoad做好厨房准备工作?

时间:2017-02-10 14:02:10

标签: sql-server xml vbscript xsd sqlxml

我正在寻找将表(或其中一部分)导出到xml文件的最简单方法,然后将此xml文件导入到其他数据库的相应表中。

我发现的原则非常简单:

    源数据库上的
  1. 导出:我通过向select查询添加FOR XML root('Data')FOR XML, XMLSCHEMA子句来生成xml字符串和xsd架构字符串。
  2. 目标数据库上的
  3. 导入:我使用生成的xsd通过SQLXMLBulkLoad批量加载生成的xml文件。
  4. 但我无法做到这一点。在导出和导入之间,我必须在xsd模式中进行一些小的修改。

    例如,我通过以下查询生成xml和xsd字符串:

    select top 3 * FROM myTable
    FOR XML AUTO, ELEMENTS 
    ,Root('Data')
    

    SELECT top 0 * FROM myTable
    FOR XML AUTO, ELEMENTS 
    ,XMLSCHEMA
    

    生成的generated.xml和generated.xsd看起来如此:

    <Data>
      <myTable>
          <field1>value11</field1>
          ...
          <field1>value1n</field1>
      </myTable>
      <myTable>
          <field1>value21</field1>
          ...
          <field1>value2n</field1>
      </myTable>
      <myTable>
          <field1>value31</field1>
          ...
          <field1>value3n</field1>
      </myTable>
    </Data>
    

    <xsd:schema 
    targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" 
    xmlns:schema="urn:schemas-microsoft-com:sql:SqlRowSet1" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes" 
    elementFormDefault="qualified">
        <xsd:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd"/>
        <xsd:element name="myTable">
            <xsd:complexType>
                <xsd:sequence>
                    <xsd:element name="field1" type="..." .../>
                    ...
                    <xsd:element name="fieldn" type="..." ... />
                </xsd:sequence>
            </xsd:complexType>
        </xsd:element>
    </xsd:schema>
    

    但是如果我想通过像这样的vb脚本进行批量加载

    set objBL = CreateObject("SQLXMLBulkLoad.SQLXMLBulkload.4.0")
    objBL.ConnectionString = "provider=SQLOLEDB.1;data source=localhost\SQLEXPRESS;database=Testdb;uid=sa;pwd=*****"
    objBL.ErrorLogFile = ".\error.xml"
    objBL.KeepIdentity = False
    objBL.Execute "generated.xsd", "generated.xml"
    set objBL=Nothing
    

    然后只有在generated.xsd

    中进行以下修改时才有效
    • 删除此xsd:schema属性:targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1"
    • 添加此xsd:schema属性:xmlns:sql="urn:schemas-microsoft-com:mapping-schema"
    • <myTable>元素替换为<myTable>元素序列,并将整个元素包装为<xsd:element name="Data" sql:is-constant="1">元素
    • 将属性maxOccurs="unbounded" sql:relation="myTable"添加到<myTable>元素

    因此,修改后的xsd非常适合通过SQLXMLBulkLoad批量加载生成的xml,如下所示:

    <xsd:schema 
    xmlns:sql="urn:schemas-microsoft-com:mapping-schema" 
    xmlns:schema="urn:schemas-microsoft-com:sql:SqlRowSet1" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes" 
    elementFormDefault="qualified">
        <xsd:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd"/>
        <xsd:element name="Data" sql:is-constant="1">
            <xsd:complexType>
                <xsd:sequence>
                    <xsd:element name="myTable" maxOccurs="unbounded" sql:relation="myTable">
                        <xsd:complexType>
                            <xsd:sequence>
                                <xsd:element name="field1" type="..." .../>
                                ...
                                <xsd:element name="fieldn" type="..." ... />
                            </xsd:sequence>
                        </xsd:complexType>
                    </xsd:element>
                </xsd:sequence>
            </xsd:complexType>
        </xsd:element>
    </xsd:schema>
    

    我想知道生成的sql查询和/或vbscript是否可以修改,生成的xml和xsd是否可以与vbscript一起使用而无需任何手动修改?

1 个答案:

答案 0 :(得分:1)

正如您的问题所要求的那样,SIMPLEST方法可以使用简单的XML数据集,它可以是高度可移植和兼容的。假设您有两个SQL服务器。我在SQL&gt; Excel,SQL&gt; SQL,SQL&gt; Oracle。

之间使用了这种方法

您可以在SQL上执行存储过程调用:

DECLARE @xml xml

SET @XML = (
SELECT field1, field2
FROM table
FOR XML RAW('row'), ROOT('data'), ELEMENTS
)

这将返回:

<root>
  <row>
<field1>SomeData</field1>
<field2>SomeOtherData</field2>
</row>
</root>

获得XML后,只需使用以下内容读入TARGET数据库:

INSERT INTO TargetDatabase.TargetTable(field1, field2)
SELECT tbl.c.value('field1','varchar(1000)'), tbl.c.value('field2','bigint')
FROM @XML.nodes('/root[1]/row) tbl(c)

如果需要,您还可以非常轻松地对传入的XML数据运行查询等:

INSERT INTO TargetTable(field1, field2)
SELECT tbl.c.value('field1','varchar(1000)'), tbl.c.value('field2','bigint')
FROM @XML.nodes('/root[1]/row) tbl(c)
WHERE tbl.c.value('field2','bigint') > 100 or tbl.c.value('field1','varchar(1000)') Like '%fish%'

非常高效且非常快。不需要乱用模式。唯一的事情是字段类型是硬编码的。所以你需要自定义构建每个SP读/写。

如果您有某种代理(例如MS Excel这样做),它只是编写存储过程以在目标数据库中接收XML数据的简单案例:

CREATE PROCEDURE sp_target_for_XML
@XML xml