SQL 在同一节点级别导入数据时出现 OPENXML 问题
SQL OPENXML Issue With Importing Data On The Same Node Level
我有一个 XML 格式的日志文件,我想为其安排自动导入 SQL。我可以使用 OPENROWSET 和 OPENXML 部分导入数据,但是我无法导入某些数据,因为它们处于同一节点级别。具体来说,'user' 节点与 '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
上述脚本 returns 除了用户标签之外的所有内容:id、用户名(名称)、memberType 和 Client、Matter、Author 和 DocumentType。如果有人可以就如何导入所有内容提供建议 activity,将不胜感激。
我不习惯使用 OPENXML
,据我所知,这是从 XML 文档中检索内容的老派方法。我这样做的方式是使用 SQL 服务器支持的 XML 函数。具体来说,XML 函数:
-
The result of the nodes() method is a rowset that contains logical copies of the original XML instances. In these logical copies, the context node of every row instance is set to one of the nodes identified with the query expression, so that subsequent queries can navigate relative to these context nodes.
-
Performs an XQuery against the XML and returns a value of SQL type
你会看到,例如id
(<user>
attribute Id) 你走错层了,你必须更深一层。例如<Client>
你又上错层了,你必须退回一层才能再上去。我在你的 XML.
中没有找到文件名属性
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);
我有一个 XML 格式的日志文件,我想为其安排自动导入 SQL。我可以使用 OPENROWSET 和 OPENXML 部分导入数据,但是我无法导入某些数据,因为它们处于同一节点级别。具体来说,'user' 节点与 '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
上述脚本 returns 除了用户标签之外的所有内容:id、用户名(名称)、memberType 和 Client、Matter、Author 和 DocumentType。如果有人可以就如何导入所有内容提供建议 activity,将不胜感激。
我不习惯使用 OPENXML
,据我所知,这是从 XML 文档中检索内容的老派方法。我这样做的方式是使用 SQL 服务器支持的 XML 函数。具体来说,XML 函数:
-
The result of the nodes() method is a rowset that contains logical copies of the original XML instances. In these logical copies, the context node of every row instance is set to one of the nodes identified with the query expression, so that subsequent queries can navigate relative to these context nodes.
-
Performs an XQuery against the XML and returns a value of SQL type
你会看到,例如id
(<user>
attribute Id) 你走错层了,你必须更深一层。例如<Client>
你又上错层了,你必须退回一层才能再上去。我在你的 XML.
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);