web-dev-qa-db-fra.com

Importer «xml» dans Sql Server

J'ai un fichier qui est structuré comme suit:

<?xml version="1.0" encoding="UTF-8"?>
<EventSchedule>
    <Event Uid="2" Type="Main Event">
        <IsFixed>True</IsFixed>
        <EventKind>MainEvent</EventKind>
        <Fields>
            <Parameter Name="Type" Value="TV_Show"/>
            <Parameter Name="Name" Value="The Muppets"/>
            <Parameter Name="Duration" Value="00:30:00"/>
        </Fields>
    </Event>
    <Event>
    ...and so on
    </Event>
</EventSchedule>

Je ne suis pas tout à fait sûr s'il s'agit d'un XML valide, mais je dois l'importer dans SQL Server, mais tout ce que j'essaie ne semble pas fonctionner.

S'il vous plaît quelqu'un pourrait-il m'orienter dans la bonne direction, soit avec un exemple de code ou une recommandation sur la méthode à utiliser?

Je souhaite idéalement obtenir les données brutes dans une table plate, le long des lignes de:

Name        | Type    | Duration | EventKind

The Muppets | TV_Show | 00:30:00 | MainEvent

Enfin, cela provient de fichiers assez volumineux et je devrai les importer régulièrement.

Merci, pugu

30
pugu

Essaye ça:

DECLARE @XML XML = '<EventSchedule>
    <Event Uid="2" Type="Main Event">
        <IsFixed>True</IsFixed>
        <EventKind>MainEvent</EventKind>
        <Fields>
            <Parameter Name="Type" Value="TV_Show"/>
            <Parameter Name="Name" Value="The Muppets"/>
            <Parameter Name="Duration" Value="00:30:00"/>
        </Fields>
    </Event>
    <Event Uid="3" Type="Secondary Event">
        <IsFixed>True</IsFixed>
        <EventKind>SecondaryEvent</EventKind>
        <Fields>
            <Parameter Name="Type" Value="TV_Show"/>
            <Parameter Name="Name" Value="The Muppets II"/>
            <Parameter Name="Duration" Value="00:30:00"/>
        </Fields>
    </Event>
</EventSchedule>'

SELECT
    EventUID = Events.value('@Uid', 'int'),
    EventType = Events.value('@Type', 'varchar(20)'),
    EventIsFixed =Events.value('(IsFixed)[1]', 'varchar(20)'),
    EventKind =Events.value('(EventKind)[1]', 'varchar(20)')
FROM
 @XML.nodes('/EventSchedule/Event') AS XTbl(Events)

Me donne une sortie de:

enter image description here

Et bien sûr, vous pouvez facilement faire un

INSERT INTO dbo.YourTable(EventUID, EventType, EventIsFixed, EventKind)
   SELECT 
         ......

pour insérer ces données dans une table relationnelle.

pdate: en supposant que vous avez votre XML dans des fichiers - vous pouvez utiliser ce code pour charger le fichier XML dans une variable XML dans SQL Server:

DECLARE @XmlFile XML

SELECT @XmlFile = BulkColumn
FROM  OPENROWSET(BULK 'path-to-your-XML-file', SINGLE_BLOB) x;

puis utilisez l'extrait de code ci-dessus pour analyser le XML.

pdate # 2: si vous avez aussi besoin des paramètres - utilisez cette instruction XQuery:

SELECT
    EventUID = Events.value('@Uid', 'int'),
    EventType = Events.value('@Type', 'varchar(20)'),
    EventIsFixed = Events.value('(IsFixed)[1]', 'varchar(20)'),
    EventKind = Events.value('(EventKind)[1]', 'varchar(20)'),
    ParameterType = Events.value('(Fields/Parameter[@Name="Type"]/@Value)[1]', 'varchar(20)'),
    ParameterName = Events.value('(Fields/Parameter[@Name="Name"]/@Value)[1]', 'varchar(20)'),
    ParameterDuration = Events.value('(Fields/Parameter[@Name="Duration"]/@Value)[1]', 'varchar(20)')
FROM
    @XML.nodes('/EventSchedule/Event') AS XTbl(Events)

Résulte en:

enter image description here

55
marc_s

Pour ce faire, créez une table de destination, puis un fichier de mappage de schéma qui mappe les éléments xml aux colonnes de la table.

Le vôtre pourrait ressembler un peu à ceci:

create table event (
    Type nvarchar(50),
    Name nvarchar(50),
    Duration nvarchar(50))

et ça:

<?xml version="1.0" ?>
<Schema xmlns="urn:schemas-Microsoft-com:xml-data" 
        xmlns:dt="urn:schemas-Microsoft-com:xml:datatypes"  
        xmlns:sql="urn:schemas-Microsoft-com:xml-sql" > 

   <ElementType name="Type" dt:type="string" />
   <ElementType name="Name" dt:type="string" />
   <ElementType name="Duration" dt:type="string" />

   <ElementType name="EventSchedule" sql:is-constant="1">
      <element type="Event" />
   </ElementType>

   <ElementType name="Event" sql:relation="Event">
      <element type="Type" sql:field="Type" />
      <element type="Name" sql:field="Name" />
      <element type="Duration" sql:field="Duration" />
   </ElementType>
</Schema>

Ensuite, vous pouvez charger votre XML dans votre table à l'aide du chargeur en bloc XML.

http://support.Microsoft.com/kb/316005

2
paul

Si vous devez le faire sans variable XML (à partir d'une chaîne dans une fonction table)

SELECT 
    --myTempTable.XmlCol.value('.', 'varchar(36)') AS val 
     myTempTable.XmlCol.query('./ID').value('.', 'varchar(36)') AS ID 
    ,myTempTable.XmlCol.query('./Name').value('.', 'nvarchar(MAX)') AS Name 
    ,myTempTable.XmlCol.query('./RFC').value('.', 'nvarchar(MAX)') AS RFC 
    ,myTempTable.XmlCol.query('./Text').value('.', 'nvarchar(MAX)') AS Text 
    ,myTempTable.XmlCol.query('./Desc').value('.', 'nvarchar(MAX)') AS Description 

    --,myTempTable.XmlCol.value('(Desc)[1]', 'nvarchar(MAX)') AS DescMeth2
FROM 
(
    SELECT  
        CAST('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        <data-set>
            <record>
                <ID>1</ID>
                <Name>A</Name>
                <RFC>RFC 1035[1]</RFC>
                <Text>Address record</Text>
                <Desc>Returns a 32-bit IPv4 address, most commonly used to map hostnames to an IP address of the Host, but it is also used for DNSBLs, storing subnet masks in RFC 1101, etc.</Desc>
            </record>
            <record>
                <ID>2</ID>
                <Name>NS</Name>
                <RFC>RFC 1035[1]</RFC>
                <Text>Name server record</Text>
                <Desc>Delegates a DNS zone to use the given authoritative name servers</Desc>
            </record>
        </data-set>
        ' AS xml) AS RawXml
) AS b 
--CROSS APPLY b.RawXml.nodes('//record/ID') myTempTable(XmlCol);
CROSS APPLY b.RawXml.nodes('//record') myTempTable(XmlCol);

Ou à partir du fichier:

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tfu_RPT_SEL_XmlData]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[tfu_RPT_SEL_XmlData]
GO



CREATE FUNCTION [dbo].[tfu_RPT_SEL_XmlData]
(
     @in_language varchar(10) 
    ,@in_reportingDate datetime 
)
RETURNS TABLE
AS
RETURN 
(   

    SELECT 
        --myTempTable.XmlCol.value('.', 'varchar(36)') AS val 
         myTempTable.XmlCol.query('./ID').value('.', 'varchar(36)') AS ID 
        ,myTempTable.XmlCol.query('./Name').value('.', 'nvarchar(MAX)') AS Name 
        ,myTempTable.XmlCol.query('./RFC').value('.', 'nvarchar(MAX)') AS RFC 
        ,myTempTable.XmlCol.query('./Text').value('.', 'nvarchar(MAX)') AS Text 
        ,myTempTable.XmlCol.query('./Desc').value('.', 'nvarchar(MAX)') AS Description 
    FROM 
    (
        SELECT CONVERT(XML, BulkColumn) AS RawXml 
        FROM OPENROWSET(BULK 'D:\username\Desktop\MyData.xml', SINGLE_BLOB) AS MandatoryRowSetName 
    ) AS b 
    CROSS APPLY b.RawXml.nodes('//record') myTempTable(XmlCol)

)


GO


SELECT * FROM tfu_RPT_SEL_XmlData('DE', CURRENT_TIMESTAMP);

par exemple.

DECLARE @bla varchar(MAX)
SET @bla = 'BED40DFC-F468-46DD-8017-00EF2FA3E4A4,64B59FC5-3F4D-4B0E-9A48-01F3D4F220B0,A611A108-97CA-42F3-A2E1-057165339719,E72D95EA-578F-45FC-88E5-075F66FD726C'

-- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes
SELECT 
    x.XmlCol.value('.', 'varchar(36)') AS val 
FROM 
(
    SELECT 
    CAST('<e>' + REPLACE(@bla, ',', '</e><e>') + '</e>' AS xml) AS RawXml
) AS b 
CROSS APPLY b.RawXml.nodes('e') x(XmlCol);

Vous pouvez donc avoir une fonction comme

SELECT * FROM MyTable 
WHERE UID IN 
(
    SELECT 
        x.XmlCol.value('.', 'varchar(36)') AS val 
    FROM 
    (
        SELECT 
        CAST('<e>' + REPLACE(@bla, ',', '</e><e>') + '</e>' AS xml) AS RawXml
    ) AS b 
    CROSS APPLY b.RawXml.nodes('e') x(XmlCol)
)
2
Stefan Steiger

Si vous essayez d'importer votre XML en tant que champ XML "pur", vous devez créer une table comme celle-ci (évidemment avec de nombreux autres champs comme vous le souhaitez):

CREATE TABLE [dbo].[TableXML](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [XmlContent] [xml] NOT NULL -- specify [xml] type
)

Ensuite, vous pouvez facilement insérer votre XML sous forme de chaîne:

INSERT INTO [dbo].[TableXML]
           ([XmlContent])
     VALUES
           ('<?xml version="1.0" encoding="UTF-8"?>
               <EventSchedule>
                 <Event Uid="2" Type="Main Event">
                   <IsFixed>True</IsFixed>
                   <EventKind>MainEvent</EventKind>
                   <Fields>
                     <Parameter Name="Type" Value="TV_Show"/>
                     <Parameter Name="Name" Value="The Muppets"/>
                     <Parameter Name="Duration" Value="00:30:00"/>
                   </Fields>
                </Event>
              </EventSchedule>')

Ensuite, pour lancer la requête à partir de MSDN t-SQL XML

Si vous préférez le stocker sous forme de chaîne, utilisez un varchar (max) à la place du type de colonne [XML] et le même insert. Mais si vous souhaitez interroger facilement, je suggère le type [XML]. Avec l'approche de chaîne plate, vous avez besoin de beaucoup de travail, sauf si vous implémentez du code d'application pour l'analyser et le stocker dans une table plate. Une bonne approche pourrait être un stockage XML dans une TABLE "compresser" et une VUE pour la récupération de données avec la disposition de champ plat.

0