如何编写`select ... FOR XML`查询生成一个xml和一个xsd,以便他们准备好用于SQLXMLBulkLoad?
我正在寻找最简单的方式将表(或其中的一部分)导出到xml文件,然后将此xml文件导入到其他数据库中的相应表中。如何编写`select ... FOR XML`查询生成一个xml和一个xsd,以便他们准备好用于SQLXMLBulkLoad?
我发现的原理很简单:
-
出口:源数据库我生成一个XML字符串,并且还加入了
FOR XML root('Data')
和FOR XML, XMLSCHEMA
子句选择查询XSD架构串上。 - 在目标数据库上导入:我使用生成的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
产生的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>
and
<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可以这样修改,即使用VBScript所生成的XML和XSD工作无需任何手动修改?
正如您的问题所述,最简单的方式可以是高度可移植且兼容的,可以像这样使用简单的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,只需使用类似读取到目标数据库这个:
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。 – mma
这是一个非常好的问题(从我身边+1)!用代码清除,但是 - 我很抱歉 - 但没有回答... SQL-Server提供了“XMLSCHEMA”和“XMLDATA”来生成两种不同版本的(嵌入式)元描述。这显然不符合你的需求。你可以使用vb的字符串方法来修改它。也许别人知道得更好...... – Shnugo