SQL 服务器:如何使用节点的字段导入 XML
SQL Server: how import XML with node's fields
我正在关注 this guide,它教我如何将 XML 文件导入 SQL 服务器。
我的 XML 看起来像这样:
<?xml version='1.0' encoding='UTF-8'?>
<osm version="0.6" generator="Osmosis 0.46">
<bounds minlon="-180.00000" minlat="-90.00000" maxlon="180.00000" maxlat="90.00000" origin="http://www.openstreetmap.org/api/0.6"/>
<node id="1014954" version="5" timestamp="2016-01-09T23:33:09Z" uid="1894634" user="Wikilux" changeset="36472980" lat="46.4928487" lon="7.5628558">
<tag k="url" v="www.cine-rex.ch"/>
<tag k="name" v="Ciné Rex"/>
<tag k="amenity" v="cinema"/>
<tag k="website" v="http://www.cine-rex.ch/kino.shtml"/>
<tag k="addr:street" v="Landstrasse"/>
<tag k="addr:housenumber" v="18"/>
</node>
<node id="20823872" version="7" timestamp="2017-09-12T15:19:00Z" uid="364" user="Edward" changeset="51976823" lat="52.2062941" lon="0.1346864">
<tag k="name" v="Vue Cambridge"/>
<tag k="screen" v="8"/>
<tag k="amenity" v="cinema"/>
<tag k="operator" v="Vue Cinemas"/>
<tag k="wikidata" v="Q39197413"/>
<tag k="cinema:3D" v="yes"/>
<tag k="addr:street" v="The Grafton Centre"/>
<tag k="addr:postcode" v="CB1 1PS"/>
</node>
<node id="20922159" version="12" timestamp="2017-09-12T15:19:00Z" uid="364" user="Edward" changeset="51976823" lat="52.2028721" lon="0.1234498">
<tag k="name" v="Arts Picturehouse"/>
<tag k="screen" v="3"/>
<tag k="amenity" v="cinema"/>
<tag k="operator" v="City Screen Limited"/>
<tag k="wikidata" v="Q39197264"/>
<tag k="addr:city" v="Cambridge"/>
<tag k="wheelchair" v="no"/>
<tag k="addr:street" v="St Andrew's Street"/>
<tag k="addr:country" v="GB"/>
<tag k="addr:postcode" v="CB2 3AR"/>
<tag k="addr:housenumber" v="38-39"/>
</node>
</osm>
所以我首先以这种方式导入 XML:
CREATE DATABASE OPENXMLTesting
GO
USE OPENXMLTesting
GO
CREATE TABLE XMLwithOpenXML
(
Id INT IDENTITY PRIMARY KEY,
XMLData XML,
LoadedDateTime DATETIME
)
INSERT INTO XMLwithOpenXML(XMLData, LoadedDateTime)
SELECT CONVERT(XML, BulkColumn) AS BulkColumn, GETDATE()
FROM OPENROWSET(BULK 'C:\Users\franc\Desktop\cinema.osm', SINGLE_BLOB) AS x;
SELECT * FROM XMLwithOpenXML
然后从每个 <node>
:
导入 id
、lat
和 long
USE OPENXMLTesting
GO
DECLARE @XML AS XML, @hDoc AS INT, @SQL NVARCHAR (MAX)
SELECT @XML = XMLData FROM XMLwithOpenXML
EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML
SELECT id, lat, lon
FROM OPENXML(@hDoc, 'osm/node')
WITH
(
id [varchar](50) '@id',
lat [varchar](100) '@lat',
lon [varchar](100) '@lon'
)
EXEC sp_xml_removedocument @hDoc
GO
完美,有效!
但现在我卡住了。我需要做什么才能使用 name
和 website
创建另外 2 个列?
因为<tag>
总是一样的,我需要用v=
代表k=
的值
该死,感谢this post on Whosebug:
,我自己找到了解决方案
USE OPENXMLTesting
GO
DECLARE @XML AS XML, @hDoc AS INT, @SQL NVARCHAR (MAX)
SELECT @XML = XMLData FROM XMLwithOpenXML
EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML
SELECT id, lat, lon,name,website
FROM OPENXML(@hDoc, 'osm/node')
WITH
(
id [varchar](50) '@id',
lat [varchar](100) '@lat',
lon [varchar](100) '@lon',
name [varchar](100) '(tag[@k="name"]/@v)[1]',
website [varchar](500) '(tag[@k="website"]/@v)[1]'
)
EXEC sp_xml_removedocument @hDoc
GO
您可以也使用 SQL 服务器中的本机 XQuery 支持来完成它,而不必求助于以内存着称的遗留 OPENXML
调用泄漏和其他问题。
只需改用此代码:
DECLARE @XML AS XML
SELECT @XML = XMLData FROM XMLwithOpenXML
SELECT
id = xc.value('@id', 'int'),
lon = xc.value('@lon', 'decimal(20,8)'),
lat = xc.value('@lat', 'decimal(20,8)'),
name = xc.value('(tag[@k="name"]/@v)[1]', 'varchar(50)'),
website = xc.value('(tag[@k="website"]/@v)[1]', 'varchar(50)')
FROM
@XML.nodes('/osm/node') AS XT(XC)
而且我还建议 始终 使用 最合适的 数据类型 - 在这里,id
看起来像一个 INT
- 所以这样使用它 - lat
和 lon
显然是 DECIMAL
值;不要只是将所有内容都转换为字符串,因为您懒得弄清楚要使用什么!
我正在关注 this guide,它教我如何将 XML 文件导入 SQL 服务器。
我的 XML 看起来像这样:
<?xml version='1.0' encoding='UTF-8'?>
<osm version="0.6" generator="Osmosis 0.46">
<bounds minlon="-180.00000" minlat="-90.00000" maxlon="180.00000" maxlat="90.00000" origin="http://www.openstreetmap.org/api/0.6"/>
<node id="1014954" version="5" timestamp="2016-01-09T23:33:09Z" uid="1894634" user="Wikilux" changeset="36472980" lat="46.4928487" lon="7.5628558">
<tag k="url" v="www.cine-rex.ch"/>
<tag k="name" v="Ciné Rex"/>
<tag k="amenity" v="cinema"/>
<tag k="website" v="http://www.cine-rex.ch/kino.shtml"/>
<tag k="addr:street" v="Landstrasse"/>
<tag k="addr:housenumber" v="18"/>
</node>
<node id="20823872" version="7" timestamp="2017-09-12T15:19:00Z" uid="364" user="Edward" changeset="51976823" lat="52.2062941" lon="0.1346864">
<tag k="name" v="Vue Cambridge"/>
<tag k="screen" v="8"/>
<tag k="amenity" v="cinema"/>
<tag k="operator" v="Vue Cinemas"/>
<tag k="wikidata" v="Q39197413"/>
<tag k="cinema:3D" v="yes"/>
<tag k="addr:street" v="The Grafton Centre"/>
<tag k="addr:postcode" v="CB1 1PS"/>
</node>
<node id="20922159" version="12" timestamp="2017-09-12T15:19:00Z" uid="364" user="Edward" changeset="51976823" lat="52.2028721" lon="0.1234498">
<tag k="name" v="Arts Picturehouse"/>
<tag k="screen" v="3"/>
<tag k="amenity" v="cinema"/>
<tag k="operator" v="City Screen Limited"/>
<tag k="wikidata" v="Q39197264"/>
<tag k="addr:city" v="Cambridge"/>
<tag k="wheelchair" v="no"/>
<tag k="addr:street" v="St Andrew's Street"/>
<tag k="addr:country" v="GB"/>
<tag k="addr:postcode" v="CB2 3AR"/>
<tag k="addr:housenumber" v="38-39"/>
</node>
</osm>
所以我首先以这种方式导入 XML:
CREATE DATABASE OPENXMLTesting
GO
USE OPENXMLTesting
GO
CREATE TABLE XMLwithOpenXML
(
Id INT IDENTITY PRIMARY KEY,
XMLData XML,
LoadedDateTime DATETIME
)
INSERT INTO XMLwithOpenXML(XMLData, LoadedDateTime)
SELECT CONVERT(XML, BulkColumn) AS BulkColumn, GETDATE()
FROM OPENROWSET(BULK 'C:\Users\franc\Desktop\cinema.osm', SINGLE_BLOB) AS x;
SELECT * FROM XMLwithOpenXML
然后从每个 <node>
:
id
、lat
和 long
USE OPENXMLTesting
GO
DECLARE @XML AS XML, @hDoc AS INT, @SQL NVARCHAR (MAX)
SELECT @XML = XMLData FROM XMLwithOpenXML
EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML
SELECT id, lat, lon
FROM OPENXML(@hDoc, 'osm/node')
WITH
(
id [varchar](50) '@id',
lat [varchar](100) '@lat',
lon [varchar](100) '@lon'
)
EXEC sp_xml_removedocument @hDoc
GO
完美,有效!
但现在我卡住了。我需要做什么才能使用 name
和 website
创建另外 2 个列?
因为<tag>
总是一样的,我需要用v=
代表k=
该死,感谢this post on Whosebug:
,我自己找到了解决方案USE OPENXMLTesting
GO
DECLARE @XML AS XML, @hDoc AS INT, @SQL NVARCHAR (MAX)
SELECT @XML = XMLData FROM XMLwithOpenXML
EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML
SELECT id, lat, lon,name,website
FROM OPENXML(@hDoc, 'osm/node')
WITH
(
id [varchar](50) '@id',
lat [varchar](100) '@lat',
lon [varchar](100) '@lon',
name [varchar](100) '(tag[@k="name"]/@v)[1]',
website [varchar](500) '(tag[@k="website"]/@v)[1]'
)
EXEC sp_xml_removedocument @hDoc
GO
您可以也使用 SQL 服务器中的本机 XQuery 支持来完成它,而不必求助于以内存着称的遗留 OPENXML
调用泄漏和其他问题。
只需改用此代码:
DECLARE @XML AS XML
SELECT @XML = XMLData FROM XMLwithOpenXML
SELECT
id = xc.value('@id', 'int'),
lon = xc.value('@lon', 'decimal(20,8)'),
lat = xc.value('@lat', 'decimal(20,8)'),
name = xc.value('(tag[@k="name"]/@v)[1]', 'varchar(50)'),
website = xc.value('(tag[@k="website"]/@v)[1]', 'varchar(50)')
FROM
@XML.nodes('/osm/node') AS XT(XC)
而且我还建议 始终 使用 最合适的 数据类型 - 在这里,id
看起来像一个 INT
- 所以这样使用它 - lat
和 lon
显然是 DECIMAL
值;不要只是将所有内容都转换为字符串,因为您懒得弄清楚要使用什么!