在同一节点级别导入数据的SQL OPENXML问题

时间:2017-09-20 15:44:08

标签: sql-server tsql nodes openxml

我有一个XML格式的日志文件,我想安排自动导入SQL。我能够使用OPENROWSET和OPENXML部分导入数据,但是我无法导入一些数据,因为它在同一节点级别。具体而言,“用户”节点与“storageObject”处于同一级别,“cabinet”节点与“Client”,“Matter”等处于同一级别。

示例XML:

<ActivityLog repositoryId="ZZ-T6KQ1I1B" repositoryName="Training" startDate="2017-07-01" endDate="2017-09-18">
    <activity date="2017-08-08T10:29:02" name="change access list" host="127.0.0.1">
        <user id="JS" name="John Smith" memberType="I" />
        <storageObject docId="4161-1264-9996" name="Hello World" size="0" fileExtension="eml">
            <cabinet name="Materials">QPIRVQK</cabinet>
        </storageObject>
    </activity>
    <activity date="2017-08-08T10:29:03" name="change access list" host="127.0.0.1">
        <user id="JS" name="John Smith" memberType="I" />
        <storageObject docId="4161-1264-9996" name="Screen Shot" size="0" fileExtension="jpg">
            <cabinet name="Materials">QPIRVQK</cabinet>
            <Client>1011</Client>
            <Matter>007</Matter>
            <Author>EMAIL</Author>
            <DocumentType>JPG</DocumentType>
        </storageObject>
    </activity>
</ActivityLog>

我的T-SQL脚本:

DECLARE @x xml

SELECT @x=L
FROM OPENROWSET (BULK 'C:\Log.xml', SINGLE_BLOB) AS Log(L)

DECLARE @hdoc int

EXEC sp_xml_preparedocument @hdoc OUTPUT, @x

SELECT *
FROM OPENXML (@hdoc, 'ActivityLog/activity/storageObject/cabinet', 1)
WITH (
        activitydate datetime '../../@date',
        activityname nvarchar(max) '../../@name',
        host nvarchar(32) '../../@host',
        id nvarchar(32) '../@id',
        username nvarchar(max) '../@username',
            memberType nvarchar(50) '../@memberType',
        docId nvarchar(50) '../@docId',
        filename nvarchar(max) '../@filename',
        size int '../@size',
        fileExtension nvarchar(max) '../@fileExtension',
        cabinetname nvarchar(max) '@cabinetname',
        Client nvarchar(max) '@Client',
        Matter nvarchar(max) '@Matter',
        Author nvarchar(max) '@Author',
        DocumentType nvarchar(max) '@DocumentType'
    )

EXEC sp_xml_removedocument @hdoc

上述脚本返回除用户标记以外的所有内容:id,username(name),memberType和Client,Matter,Author和DocumentType。如果有人可以就如何导入所有活动提供建议,那将非常感激。

1 个答案:

答案 0 :(得分:0)

我不习惯使用OPENXML,因为我听说这是从XML文档中检索内容的老派方式。我这样做的方式是使用SQL Server支持的XML函数。具体来说,XML函数:

  • nodes

      

    nodes()方法的结果是一个包含原始XML实例的逻辑副本的行集。在这些逻辑副本中,每个行实例的上下文节点都设置为使用查询表达式标识的节点之一,以便后续查询可以相对于这些上下文节点进行导航。

  • value

      

    对XML执行XQuery并返回SQL类型的值

你会看到例如id<user>属性ID)您处于错误的级别,您必须更深入。对于例如<Client>你再次处于错误的水平,你必须回到一个水平再次上升。我没有在你的XML中找到filename属性。

DECLARE @x XML;
SET @x=N'<ActivityLog repositoryId="ZZ-T6KQ1I1B" repositoryName="Training" startDate="2017-07-01" endDate="2017-09-18">
    <activity date="2017-08-08T10:29:02" name="change access list" host="127.0.0.1">
        <user id="JS" name="John Smith" memberType="I" />
        <storageObject docId="4161-1264-9996" name="Hello World" size="0" fileExtension="eml">
            <cabinet name="Materials">QPIRVQK</cabinet>
        </storageObject>
    </activity>
    <activity date="2017-08-08T10:29:03" name="change access list" host="127.0.0.1">
        <user id="JS" name="John Smith" memberType="I" />
        <storageObject docId="4161-1264-9996" name="Screen Shot" size="0" fileExtension="jpg">
            <cabinet name="Materials">QPIRVQK</cabinet>
            <Client>1011</Client>
            <Matter>007</Matter>
            <Author>EMAIL</Author>
            <DocumentType>JPG</DocumentType>
        </storageObject>
    </activity>
</ActivityLog>';
SELECT
    activitydate=n.v.value('../../@date','DATETIME'),
    activityname=n.v.value('../../@name','NVARCHAR(MAX)'),
    host=n.v.value('../../@name','NVARCHAR(32)'),
    id=n.v.value('../../user[1]/@id','NVARCHAR(32)'),
    username=n.v.value('../../user[1]/@name','NVARCHAR(MAX)'),
    memberType=n.v.value('../../user[1]/@memberType','NVARCHAR(50)'),
    docId=n.v.value('../@docId','NVARCHAR(50)'),
    filename=n.v.value('../@filename','NVARCHAR(MAX)'),
    size=n.v.value('../@size','INT'),
    fileExtension=n.v.value('../@fileExtension','NVARCHAR(MAX)'),
    cabinetname=n.v.value('@cabinetname','NVARCHAR(MAX)'),
    Client=n.v.value('../Client[1]','NVARCHAR(MAX)'),
    Matter=n.v.value('../Matter[1]','NVARCHAR(MAX)'),
    Author=n.v.value('../Author[1]','NVARCHAR(MAX)'),
    DocumentType=n.v.value('../DocumentType[1]','NVARCHAR(MAX)')
FROM
    @x.nodes('ActivityLog/activity/storageObject/cabinet') AS n(v);