我需要从XML文件中将行插入数据库表。我的XML格式如下:
<Main>
<Parent>
<Title>Title1</Title>
<Code>ABC123</Code>
<Name>name1</Name>
<company>test1</company>
<Children>
<Child>
<Title>t1</Title>
<ContentType>T1</ContentType>
<TimeStarted>2018-03-01T10:47:46</TimeStarted>
<TimeFinished>2018-03-01T10:48:08</TimeFinished>
</Child>
<Child>
<Title>t2</Title>
<ContentType>T1</ContentType>
<TimeStarted>2018-03-01T10:47:46</TimeStarted>
<TimeFinished>2018-03-01T10:48:08</TimeFinished>
</Child>
</Children>
</Parent>
<Parent>
<Title>Title2</Title>
<Code>def123</Code>
<Name>name2</Name>
<company>test2</company>
<Children>
<Child>
<Title>t1</Title>
<ContentType>T1</ContentType>
<TimeStarted>2018-03-01T10:47:46</TimeStarted>
<TimeFinished>2018-03-01T10:48:08</TimeFinished>
</Child>
<Child>
<Title>t2</Title>
<ContentType>T1</ContentType>
<TimeStarted>2018-03-01T10:47:46</TimeStarted>
<TimeFinished>2018-03-01T10:48:08</TimeFinished>
</Child>
</Children>
</Parent>
</Main>
我需要在表1中插入父级别数据(在父标记下 - 标题,代码,名称,公司),在表2中插入子级别数据。 表2具有对表1的foriengy键引用(我们需要在插入父记录后使用范围标识获取。)
这可能是非常大的xml文件。主要问题是我需要逐个插入记录,意味着在循环中,好像第一个父有一些问题,然后不应该中止该过程,但应该记录错误并继续进行第二个或下一个父标记。
我尝试搜索最佳方法,但大多数建议都不是通过xml迭代并直接插入表。以下是我尝试过的一些参考资料。
TSQL Inserting records from XML string
How to get individual identity in an XML Insert?
我需要建议,特别是我的要求可以在没有循环的情况下实现? 这也是最好的方法,比如先插入一些临时表然后处理它或者使用xquery首先获取平面数据中的所有记录,然后将光标放在它上面?或任何其他方法
请建议。
答案 0 :(得分:1)
一般来说,使用两步导入是个好主意,特别是在您预期会出现问题的情况下。
如果这是SQL-Server(我将此表单作为[tsql]
标记),您可以创建一个STORED PROCEDURE
接受XML作为参数,并使用以下代码将其粉碎成临时表。 / p>
提示:我使用*
来阅读您的节点<Parent1>
,<Parent2>
。我希望你没有名字编号的元素。但它无论如何都会起作用......
DECLARE @xml XML=N'Your xml here';
WITH Parents AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS ParentID
,prnt.value(N'(Title)[1]','nvarchar(max)') AS Title
,prnt.value(N'(Code)[1]','nvarchar(max)') AS Code
,prnt.value(N'(Name)[1]','nvarchar(max)') AS Name
,prnt.value(N'(company)[1]','nvarchar(max)') AS Company
,prnt.query(N'Children/*') AS ChildrenXML
FROM @xml.nodes(N'/Main/*') AS Lvl1(prnt)
)
SELECT Parents.ParentID
,Parents.Title
,Parents.Code
,Parents.Name
,Parents.Company
,ROW_NUMBER() OVER(PARTITION BY ParentID ORDER BY (SELECT NULL)) AS ChildID
,chld.value(N'(Title)[1]','nvarchar(max)') AS Child_Title
,chld.value(N'(ContentType)[1]','nvarchar(max)') AS Child_ContentType
,chld.value(N'(TimeStarted)[1]','nvarchar(max)') AS Child_TimeStarted
,chld.value(N'(TimeFinished)[1]','nvarchar(max)') AS Child_TimeFinished
INTO #StagingTable
FROM Parents
OUTER APPLY ChildrenXML.nodes(N'*') AS Lvl2(chld);
SELECT * FROM #StagingTable;
结果
+----------+--------+--------+-------+---------+---------+-------------+-------------------+---------------------+---------------------+
| ParentID | Title | Code | Name | Company | ChildID | Child_Title | Child_ContentType | Child_TimeStarted | Child_TimeFinished |
+----------+--------+--------+-------+---------+---------+-------------+-------------------+---------------------+---------------------+
| 1 | Title1 | ABC123 | name1 | test1 | 1 | t1 | T1 | 2018-03-01T10:47:46 | 2018-03-01T10:48:08 |
+----------+--------+--------+-------+---------+---------+-------------+-------------------+---------------------+---------------------+
| 1 | Title1 | ABC123 | name1 | test1 | 2 | t2 | T1 | 2018-03-01T10:47:46 | 2018-03-01T10:48:08 |
+----------+--------+--------+-------+---------+---------+-------------+-------------------+---------------------+---------------------+
| 2 | Title2 | def123 | name2 | test2 | 1 | t1 | T1 | 2018-03-01T10:47:46 | 2018-03-01T10:48:08 |
+----------+--------+--------+-------+---------+---------+-------------+-------------------+---------------------+---------------------+
| 2 | Title2 | def123 | name2 | test2 | 2 | t2 | T1 | 2018-03-01T10:47:46 | 2018-03-01T10:48:08 |
+----------+--------+--------+-------+---------+---------+-------------+-------------------+---------------------+---------------------+
这是非常宽容的。所有目标列都是NVARCHAR(MAX)
,所有父行都有编号,所有子行都在内部编号。
第二步 - 将其转移到目标表 - 可以从这里轻松完成。您可以包括任何类型的评估,日志记录和/或错误处理。
答案 1 :(得分:0)
我将结果放入数据表中。您可以使用对数据库的写入来替换对数据表的写入。 Ir从代码中读取数据,然后写入数据库。它取决于您想要使用的方法的数据库大小。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Parent", typeof(string));
dt.Columns.Add("Parent Title", typeof(string));
dt.Columns.Add("Code", typeof(string));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Company", typeof(string));
dt.Columns.Add("Child", typeof(string));
dt.Columns.Add("Child Title", typeof(string));
dt.Columns.Add("Content Type", typeof(string));
dt.Columns.Add("Time Start", typeof(DateTime));
dt.Columns.Add("Time Finish", typeof(DateTime));
XDocument doc = XDocument.Load(FILENAME);
List<XElement> parents = doc.Root.Elements().ToList();
foreach (XElement parent in parents)
{
try
{
string parentTagName = (string)parent.Name.LocalName;
string parentTitle = (string)parent.Element("Title");
string code = (string)parent.Element("Code");
string parentName = (string)parent.Element("Name");
string company = (string)parent.Element("company");
foreach (XElement child in parent.Element("Children").Elements())
{
try
{
string childTagName = child.Name.LocalName;
string childTitle = (string)child.Element("Title");
string contentType = (string)child.Element("ContentType");
DateTime timeStarted = (DateTime)child.Element("TimeStarted");
DateTime timeFinished = (DateTime)child.Element("TimeFinished");
dt.Rows.Add(new object[] {
parentTagName,
parentTitle,
code,
parentName,
company,
childTagName,
childTitle,
contentType,
timeStarted,
timeFinished
});
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
}