Kah*_*ahn 2 xml sql-server import
我需要将 XML 从文件解析为表,同时通过自定义生成的 ID 值保留它们的关系。
例如,如果我有以下 XML:
<root>
<construction>
<constructionName>randomname1</constructionName>
<project>
<projectname>another randomname</projectname>
<businesspartners>
<partnername>bilbo bagginses</partnername>
</businesspartners>
<employees>
<employee>
<empname>frodo</empname>
<empaddress>etc...</empaddress>
</employee>
</employees>
</project>
<info>
<randElement></randElement>
</info>
<constructionType>houses</constructiontype>
</construction>
<construction>
<...(etc, same as above, times n^10)/>
</construction>
</root>
Run Code Online (Sandbox Code Playgroud)
由此,我需要生成到下表的数据:
CONSTRUCTION (CONSTRUCTION_ID INT PRIMARY KEY
, CONSTRUCTIONNAME VARCHAR..
, CONSTRUCTIONTYPE VARCHAR.. )
PROJECT (PROJECT_ID INT PRIMARY KEY
, CONSTRUCTION_ID INT FOREIGN KEY REFERENCES CONSTRUCTION
, PROJECTNAME VARCHAR.., )
BUSINESSPARTNERS (BUSINESSPARTNERS_ID INT PRIMARY KEY
, PROJECT_ID INT FOREIGN KEY REFERENCES PROJECT
, PARTNERNAME VARCHAR..)
etc...
Run Code Online (Sandbox Code Playgroud)
基本上,这个想法是构造带有完整引用的表来表示 XML。表结构已经存在,无法更改以适应此脚本。这只是能够进行相同类型的 XML 解析,然后将数据添加到表中,同时生成正确的引用 ID 值,就像我们之前在集成时所做的那样。仅使用 SQL Server 专门执行此操作,而不使用 SSIS。
现在,实际场景和相关文件相当庞大,因此我绝不期望得到完整的答案。只是关于从哪里开始寻找的提示。我在处理 XML 方面非常缺乏经验。
目前,我的首选解决方案是仅使用 导入数据OPENROWSET,然后使用动态 SQLOPENXML将文档解析到表中,方法是一次一个地循环元素及其子元素。但这似乎比其他更聪明的方法麻烦得多。
ID 值是如何生成的?
这是问题的一部分。目前,他们不是。这个想法是每个CONSTRUCTION元素都将被分配一个ID从 1 开始的递增。然后所有的子元素将CONSTRUCTION引用相同的ID分配给父元素,依此类推。基本上,它只是将 XML 中的数据分成多个表,同时保持参照完整性不变。
使用标识列作为主键没有问题,只要关系不会因此混淆。我不知道如何去做,所以我假设人们必须以某种方式手动定义创建 ID 的逻辑,而不是身份?
您可以使用Using merge..output to get mapping between source.id and target.id和 Adam Machanic 在Dr. OUTPUT 或:How I Learned to Stop Worrying and Love the MERGE 中描述的技术变体。
您merge在表变量中使用属于该 ID 的 XML 片段并捕获生成的 ID,然后在向子表添加行时使用该表变量。
declare @C table
(
CONSTRUCTION_ID int primary key,
PROJECT xml
);
merge CONSTRUCTION as T
using (
select T.X.value('(constructionName/text())[1]', 'varchar(30)') as CONSTRUCTIONNAME,
T.X.value('(constructionType/text())[1]', 'varchar(30)') as CONSTRUCTIONTYPE,
T.X.query('project') as PROJECT
from @xml.nodes('/root/construction') as T(X)
) as S
on 0 = 1
when not matched by target then
insert (CONSTRUCTIONNAME, CONSTRUCTIONTYPE)
values (S.CONSTRUCTIONNAME, S.CONSTRUCTIONTYPE)
output inserted.CONSTRUCTION_ID, S.PROJECT into @C;
declare @P table
(
PROJECT_ID int primary key,
BUSINESSPARTNERS XML
);
merge PROJECT as T
using (
select C.CONSTRUCTION_ID,
T.X.value('(projectname/text())[1]', 'varchar(30)') as PROJECTNAME,
T.X.query('businesspartners') as BUSINESSPARTNERS
from @C as C
cross apply C.PROJECT.nodes('/project') as T(X)
) as S
on 0 = 1
when not matched by target then
insert (CONSTRUCTION_ID, PROJECTNAME)
values(S.CONSTRUCTION_ID, S.PROJECTNAME)
output inserted.PROJECT_ID, S.BUSINESSPARTNERS into @P;
insert into BUSINESSPARTNERS(PROJECT_ID, PARTNERNAME)
select P.PROJECT_ID,
T.X.value('text()[1]', 'varchar(30)')
from @P as P
cross apply P.BUSINESSPARTNERS.nodes('/businesspartners/partnername') as T(X);
Run Code Online (Sandbox Code Playgroud)