SQL Server: как импортировать XML с полями узла

Я следую это руководство, которое учит меня, как импортировать файл XML в SQL Server.

Мой 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&apos;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

А затем импортировали id, lat и long из каждого <node>:

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

Идеально, это работает!

Но теперь я застрял. Что мне нужно сделать, чтобы создать еще 2 столбца с name и website?

введите здесь описание изображения

Потому что <tag> всегда одно и то же, и мне нужно взять v= за то, что является ценностью k=


person Francesco Mantovani    schedule 11.08.2018    source источник


Ответы (2)


Вы также можете также сделать это с помощью встроенной поддержки XQuery в SQL Server, не прибегая к устаревшим вызовам 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; не просто конвертируйте все в строки, потому что вы слишком ленивы, чтобы понять, что использовать!

person marc_s    schedule 11.08.2018

Черт возьми, я сам нашел решение благодаря этому сообщению в StackOverflow:

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
person Francesco Mantovani    schedule 11.08.2018