【问题标题】:How to write `select ... FOR XML` queries that generates an xml and an xsd so, that they are kitchen ready for an SQLXMLBulkLoad?如何编写生成 xml 和 xsd 的“select ... FOR XML”查询,以便它们为 SQLXMLBulkLoad 做好准备?
【发布时间】:2017-06-28 21:54:04
【问题描述】:

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

我发现的原理很简单:

  1. 导出:在源数据库上,我通过在选择查询中添加FOR XML root('Data') 和FOR XML, XMLSCHEMA 子句来生成一个xml 字符串和一个xsd 架构字符串。
  2. 导入: 在目标数据库上,我使用生成的 xsd 通过 SQLXMLBulkLoad 批量加载生成的 xml 文件。

但我不能完全做到这一点。在导出和导入之间,我必须对 xsd 架构进行一些小的修改。

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

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

和

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

生成的 generate.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

只有当我在 generate.xsd 中进行以下修改时,这才有效

  • 删除这个xsd:schema属性:targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1"
  • 添加此xsd:schema 属性:xmlns:sql="urn:schemas-microsoft-com:mapping-schema"
  • 将&lt;myTable&gt; 元素替换为&lt;myTable&gt; 元素序列,并将整个元素包装成&lt;xsd:element name="Data" sql:is-constant="1"&gt; 元素
  • 将属性maxOccurs="unbounded" sql:relation="myTable" 添加到&lt;myTable&gt; 元素

所以,真正适合通过SQLXMLBulkLoad批量加载生成的xml的修改后的xsd看起来像这样:

<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)!清楚,有代码,但是 - 我很抱歉 - 但没有回答...... SQL-Server提供XMLSCHEMA和XMLDATA来生成两个不同版本的(嵌入式)元描述。这显然不能满足您的需求。您可以使用 vb 的字符串方法来修改它。也许其他人知道得更好......

标签: sql-server xml vbscript xsd sqlxml


【解决方案1】:

正如您的问题所问的,具有高度可移植性和兼容性的最简单方式可以使用像这样的简单 XML 数据集。假设您有两个 SQL 服务器。我在 SQL>Excel、SQL>SQL、SQL>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

【讨论】:

  • 这还不错,但是当有很多字段时,它不一定是最简单的方法。而且您的代码包含一些错误。工作代码是 SELECT tbl.c.value('field1[1]','varchar(1000)'), tbl.c.value('field2[1]','bigint') FROM @XML.nodes(' /root[1]/row') tbl(c)。尽管如此,我还是应该给它一个 +1 的评价。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-03
  • 2014-12-07
  • 2020-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多