将 XML 多个嵌套节点插入 SQL 表
Posted
技术标签:
【中文标题】将 XML 多个嵌套节点插入 SQL 表【英文标题】:Inserting XML Multiple Nested Nodes into SQL Tables 【发布时间】:2020-10-26 13:04:20 【问题描述】:我有一个具有以下结构的 XML 文件:
<NIACList>
<NIAC>
<Number></Number>
<SubmissionDate></SubmissionDate>
<ExpirationDate />
<IssuerIDNO></IssuerIDNO>
<IssuerName></IssuerName>
<SuspensionPeriod/>
<Cessation>
<Basis />
<Date />
</Cessation>
<Merchant>
<IDNx></IDNx>
<Name></Name>
<Address>
<Region></Region>
<Locality></Locality>
<Street></Street>
<House></House>
<Block />
<Flat />
<Phone />
<Fax />
<Email />
</Address>
</Merchant>
<CommercialUnit>
<IDNx />
<Name />
<Type></Type>
<Area></Area>
<Location></Location>
<Address>
<Region></Region>
<Locality></Locality>
<Street></Street>
<House></House>
<Block />
<Flat />
</Address>
<Activities>
<Activity>
<Code></Code>
<Name></Name>
</Activity>
</Activities>
<Goods>
<Good>
<Name></Name>
</Good>
</Goods>
<WorkProgram />
<PublicSupplyUnit>
<Capacity />
<TerraceCapacity />
</PublicSupplyUnit>
<TradingAlcohol />
<TradingBeer />
<TradingTobaccoProducts />
<AmbulatoryTrading />
<MobileUnitTrading></MobileUnitTrading>
<MobileUnit>
<Type />
<Length />
<Width />
<Height />
</MobileUnit>
<CommercialApparatusTrading></CommercialApparatusTrading>
<CommercialApparatus>
<Count />
<Length />
<Width />
<Height />
</CommercialApparatus>
</CommercialUnit>
<Modifications />
</NIAC>
</NIACList>
基于这个 XML 结构,我在 MS SQL 中创建了一个带有以下表脚本的数据库:
create table NIAC (
IDNIAC int identity primary key,
Number nvarchar(80) null,
SubmissionDate datetime2 null,
ExpirationDate datetime2 null,
IssuerIDNO nvarchar(max) null,
IssuerName nvarchar(60) null,
SuspensionPeriod datetime2 null,
Modifications nvarchar(60) null
);
create table Cessation (
IdCessation int identity primary key,
Basis nvarchar(60) null,
Date date null,
IDNIAC int
);
create table Merchant (
IdMerchant int identity primary key,
IDNX nvarchar(max) null,
Name nvarchar(max) null,
WorkProgram datetime2 null,
IdAddress int
);
create table Address (
IdAddress int identity primary key,
Region nvarchar(60) null,
Locality nvarchar(50) null,
Street nvarchar (60) null,
House nvarchar (10) null,
Block nvarchar (10) null,
Flat nvarchar(10) null,
Phone nvarchar(30) null,
Fax nvarchar(60) null,
Email nvarchar(60) null
);
create table CommercialUnit (
IDCommercialUt int identity primary key,
IDNx nvarchar(90) null,
Name nvarchar(90) null,
Type nvarchar(90) null,
Area int null,
Location nvarchar(max) null,
TerraceCapacity float null,
TradingAlcohol bit null,
TradingBeer bit null,
TradingTobaccoProducts bit null,
AmbulatoryTrading bit null,
MobileUnitTrading bit null,
CommercialApparatusTrading bit null,
IdAddress int,
IDActivities int ,
IDGoods int ,
IDMobileUnit int ,
IDCommercial int ,
IDPSU int
);
create table Activities (
IDActivities int identity primary key,
Code nvarchar (90) null,
Name nvarchar (90) null
);
create table Goods(
IDGoods int identity primary key,
Name nvarchar(60) null
);
create table MobileUnit(
IDMobileUnit int identity primary key,
Type numeric null,
Length numeric null,
Width numeric null,
Height numeric null
);
create table CommercialApparatus(
IDCommercial int identity primary key,
Count float null,
Length numeric null,
Width numeric null,
Height numeric null
);
create table PublicSupplyUnit(
IDPSU int identity primary key,
Capacity float,
TerraceCapacity float
);
create table NIACList(
ID int identity primary key,
IDNIAC int not null,
IDNIACList int
);
create table NIACToComponents(
IDNIACToComponents int identity primary key,
IDNIAC int,
IDAddressMerchant int,
IDAddressCU int,
IdCessation int,
IdMerchant int,
IDCommercialUt int,
IDActivities int,
IDGoods int,
IDMobileUnit int,
IDCommercial int,
IDPSU int,
);
drop table if exists NIAC;
drop table if exists NIACList;
drop table if exists Cessation;
drop table if exists Merchant;
drop table if exists Address;
drop table if exists CommercialApparatus;
drop table if exists CommercialUnit;
drop table if exists Goods;
drop table if exists MobileUnit;
drop table if exists PublicSupplyUnit;
drop table if exists Activities;
drop table if exists NIACToComponents;
alter table dbo.NIACList
add constraint FK_ID_NIAC
foreign key (IDNIAC) references dbo.NIAC(IDNIAC)
on delete cascade
on update cascade;
alter table dbo.Cessation
Add constraint FK_IDNIAC
foreign key(IDNIAC) references dbo.NIAC(IDNIAC)
on delete cascade
on update cascade;
alter table dbo.Merchant
add constraint FK_IdAdress
foreign key(IdAddress) references dbo.Address(IdAddress)
on delete cascade
on update cascade;
alter table dbo.CommercialUnit
add constraint FK_IdAddress
foreign key(IdAddress) references dbo.Address(IdAddress)
on delete cascade
on update cascade;
alter table dbo.CommercialUnit
add constraint FK_Activities
foreign key(IDActivities) references dbo.Activities(IDActivities)
on delete cascade
on update cascade;
alter table dbo.CommercialUnit
add constraint FK_IDGoods
foreign key(IDGoods) references dbo.Goods(IDGoods)
on delete cascade
on update cascade;
alter table dbo.CommercialUnit
add constraint FK_IDMobileUnit
foreign key(IDMobileUnit) references dbo.MobileUnit(IDMobileUnit)
on delete cascade
on update cascade;
alter table dbo.CommercialUnit
add constraint FK_IDCommercial
foreign key(IDCommercial) references dbo.CommercialApparatus(IDCommercial)
on delete cascade
on update cascade;
alter table dbo.CommercialUnit
add constraint FK_IDPSU
foreign key(IDPSU) references dbo.PublicSupplyUnit(IDPSU)
on delete cascade
on update cascade;
假设NIACList
(50-100 个节点)中有很多 NIAC
,我想从我的 XML 文件中插入数据。
我只为一个NIAC
执行了INSERT
操作,使用3 个过程(2 个用于插入表,1 个用于调用两个过程并将插入数据的表的所有ID 插入另一个表,所以所有数据都将链接到 NIAC)。
向表中插入数据的脚本如下: 1个程序:
ALTER procedure [dbo].[InsertXMLMultipleTables]
(
@idAddress1 int out,
@idAddress2 int out,
@idactivities int out,
@idgoods int out,
@idmobileunit int out,
@idcommercial int out,
@idcommercialut int out,
@idpsu int out,
@idmerchant int out,
@xml xml
)
as
set @xml = *
begin
set nocount on
INSERT INTO Activities(Code,Name)
SELECT
Code=c.value('Code[1]','nvarchar(90)') ,
Name=c.value('Name[1]','nvarchar(90)')
FROM @xml.nodes('/NIACList/NIAC/CommercialUnit/Activities/Activity') Activities(c)
set @IDActivities=SCOPE_IDENTITY();
end;
begin
INSERT INTO Address(Region,Locality,Street,House,Block,Flat,Phone,Fax,Email)
SELECT
Region=c.value('Region[1],','nvarchar(60)'),
Locality=c.value('Locality[1],','nvarchar(50)') ,
Street=c.value('Street[1],','nvarchar(60)') ,
House=c.value('House[1],','nvarchar(10)') ,
Block=c.value('Block[1],','nvarchar(10)') ,
Flat=c.value('Flat[1],','nvarchar(10)') ,
Phone=c.value('Phone[1],','nvarchar(30)') ,
Fax=c.value('Fax[1],','nvarchar(60)') ,
Email=c.value('Email[1],','nvarchar(60)')
FROM @xml.nodes('NIACList/NIAC/Merchant/Address') Address(c)
set @idAddress1=SCOPE_IDENTITY();
end;
begin
INSERT INTO Merchant(IDNX,Name,WorkProgram,IdAddress)
SELECT
Region=c.value('IDNx[1],','nvarchar(max)'),
Locality=c.value('Name[1],','nvarchar(max)') ,
Street=c.value('WorkProgram[1],','datetime2') ,
@idAddress1
FROM @xml.nodes('NIACList/NIAC/Merchant') Merchant(c)
set @idmerchant=SCOPE_IDENTITY();
end;
begin
INSERT INTO Address(Region,Locality,Street,House,Block,Flat,Phone,Fax,Email)
SELECT
Region=c.value('Region[1],','nvarchar(60)'),
Locality=c.value('Locality[1],','nvarchar(50)') ,
Street=c.value('Street[1],','nvarchar(60)') ,
House=c.value('House[1],','nvarchar(10)') ,
Block=c.value('Block[1],','nvarchar(10)') ,
Flat=c.value('Flat[1],','nvarchar(10)') ,
Phone=c.value('Phone[1],','nvarchar(30)') ,
Fax=c.value('Fax[1],','nvarchar(60)') ,
Email=c.value('Email[1],','nvarchar(60)')
FROM @xml.nodes('NIACList/NIAC/CommercialUnit/Address') Address(c)
set @idAddress2=SCOPE_IDENTITY();
set @idcommercialut=SCOPE_IDENTITY();
end;
begin
INSERT INTO CommercialApparatus(Count,Length,Width,Height )
SELECT
Count =c.value('Type[1]','int') ,
Length=c.value('Length[1]','int') ,
Width=c.value('Width[1]','int') ,
Height=c.value('Height[1]','int')
FROM @xml.nodes('/NIACList/NIAC/CommercialUnit/CommercialApparatus') CommercialApparatus(c)
set @idcommercial=SCOPE_IDENTITY();
end;
begin
INSERT INTO Goods(Name)
SELECT
Name=c.value('Name[1]','nvarchar(60)')
FROM @xml.nodes('/NIACList/NIAC/CommercialUnit/Goods/Good') Goods(c)
set @idgoods=SCOPE_IDENTITY();
end;
begin
INSERT INTO MobileUnit(Type,Length,Width,Height )
SELECT
Type =c.value('Type[1]','int') ,
Length=c.value('Length[1]','int') ,
Width=c.value('Width[1]','int') ,
Height=c.value('Height[1]','int')
FROM @xml.nodes('/NIACList/NIAC/CommercialUnit/MobileUnit') MobileUnit(c)
set @idmobileunit=SCOPE_IDENTITY();
end;
begin
INSERT INTO PublicSupplyUnit(Capacity,TerraceCapacity)
SELECT
Capacity=c.value('Capacity[1]','int') ,
TerraceCapacity=c.value('TerraceCapacity[1]','int')
FROM @xml.nodes('/NIACList/NIAC/CommercialUnit/PublicSupplyUnit') PublicSupplyUnit(c)
set @idpsu=SCOPE_IDENTITY();
end;
begin
INSERT INTO CommercialUnit(IDNX,Name,Type,Area,Location,TerraceCapacity,TradingAlcohol,TradingBeer,TradingTobaccoProducts,AmbulatoryTrading,MobileUnitTrading,CommercialApparatusTrading,IDActivities,IdAddress,IDCommercial,IDGoods,IDMobileUnit,IDPSU)
SELECT
IDNx=c.value('IDNx[1],','nvarchar(90)'),
Name=c.value('Name[1],','nvarchar(90)') ,
Type=c.value('Type[1],','nvarchar(90)') ,
Area=c.value('Area[1],','int') ,
Location=c.value('Location[1],','nvarchar(max)'),
TerraceCapacity=c.value('TerraceCapacity[1],','float') ,
TradingAlcohol=c.value('TradingAlcohol[1],','bit') ,
TradingBeer=c.value('TradingBeer[1],','bit') ,
TradingTobaccoProducts=c.value('TradingTobaccoProducts[1],','bit'),
AmbulatoryTrading=c.value('AmbulatoryTrading[1],','bit') ,
MobileUnitTrading=c.value('MobileUnitTrading[1],','bit') ,
CommercialApparatusTrading=c.value('CommercialApparatusTrading[1],','bit') ,
@idactivities,@idAddress2,@idcommercial,@idgoods,@idmobileunit,@idpsu
FROM @xml.nodes('NIACList/NIAC/CommercialUnit') CommercialUnit(c)
end;
2 程序:
ALTER procedure [dbo].[InsertXMLNIAC]
(
@xml xml,
@idNIAC int output,
@idCessation int output
)
as
set @xml=*
begin
set nocount on
INSERT INTO NIAC(Number,SubmissionDate,ExpirationDate,IssuerIDNO,IssuerName,SuspensionPeriod,Modifications)
SELECT
Number=c.value('Number[1],','nvarchar(80)'),
SubmissionDate=c.value('SubmissionDate[1],','datetime2') ,
ExpirationDate=c.value('ExpirationDate[1],','datetime2') ,
IssuerIDNO=c.value('IssuerIDNO[1],','nvarchar(max)') ,
IssuerName=c.value('IssuerName[1],','nvarchar(60)') ,
SuspensionPeriod=c.value('SuspensionPeriod[1],','datetime2') ,
Modifications=c.value('Modifications[1],','nvarchar(60)')
FROM @xml.nodes('NIACList/NIAC') NIAC(c)
set @idNIAC=SCOPE_IDENTITY();
end;
begin
INSERT INTO Cessation(Basis,Date,IDNIAC)
SELECT
Basis=c.value('Basis[1],','nvarchar(60)'),
Date=c.value('Date[1],','date') ,
@idNIAC
FROM @xml.nodes('NIACList/NIAC/Cessation') Cessation(c)
set @idCessation=SCOPE_IDENTITY();
end;
3 程序:
ALTER PROCEDURE [dbo].[NIACFORCOMPONENTS]
@xml1 xml
AS
BEGIN
DECLARE
@idAddress1 int,
@idAddress2 int,
@idactivities int,
@idgoods int,
@idmobileunit int,
@idcommercial int,
@idcommercialut int,
@idpsu int,
@idmerchant int,
@idNIAC int,
@idCessation int
SET NOCOUNT ON;
declare @trancount int;
set @trancount=@@TRANCOUNT;
BEGIN TRANSACTION
EXEC [dbo].[InsertXMLMultipleTables]
@idAddress1 = @idAddress1 OUTPUT,
@idAddress2 = @idAddress2 OUTPUT,
@IDActivities = @idactivities OUTPUT,
@idgoods = @idgoods OUTPUT,
@idmobileunit = @idmobileunit OUTPUT,
@idcommercial = @idcommercial OUTPUT,
@idcommercialut = @idcommercialut OUTPUT,
@idpsu = @idpsu OUTPUT,
@idmerchant = @idmerchant OUTPUT,
@xml = @xml1
EXEC [dbo].[InsertXMLNIAC]
@idNIAC = @idNIAC OUTPUT,
@idCessation = @idCessation OUTPUT,
@xml=@xml1
begin try
if @trancount = 0
begin transaction
else
save transaction NIACFORCOMPONENTS;
lbexit:
if @trancount = 0
commit;
end try
begin catch
declare @error int, @message varchar(4000), @xstate int;
select @error = ERROR_NUMBER(),
@message = ERROR_MESSAGE(), @xstate = XACT_STATE();
if @xstate = -1
rollback;
if @xstate = 1 and @trancount = 0
rollback
if @xstate = 1 and @trancount > 0
rollback transaction NIACFORCOMPONENTS;
raiserror ('NIACFORCOMPONENTS: %d: %s', 16, 1, @error, @message) ;
return;
end catch
Begin
INSERT INTO NIACToComponents(IDNIAC,IdCessation,IdMerchant,IDAddressMerchant,IDAddressCU,IDCommercialUt,IDActivities,IDGoods,IDMobileUnit,IDCommercial,IDPSU)
SELECT
@idNIAC as N'@idNIAC',
@idCessation as N'@idCessation',
@idmerchant as N'@idmerchant',
@idAddress1 as N'@idAddress1',
@idAddress2 as N'@idAddress2',
@idcommercialut as N'@idcommercialut',
@idactivities as N'@idactivities',
@idgoods as N'@idgoods',
@idmobileunit as N'@idmobileunit',
@idcommercial as N'@idcommercial',
@idpsu as N'@idpsu'
COMMIT
END
END
基于这些脚本,插入非常适合一个 NIAC
,表中的每个 ID 都链接到它,但我想对 NIACList
内的所有 NIAC
节点进行此类插入,知道他们每个人的位置。
【问题讨论】:
我建议通过 SSIS 执行 XML 读取和 DB 插入。它工作得很好,尤其是当您创建一个 XSLT 表来为您进行 XML 解释时。 【参考方案1】:您可以根据需要使用以下概念示例。
您可以通过遍历父 XML 元素将INSERT
数据写入数据库表。您将需要两个 INSERT 语句。在第一个之后,您需要保留一个 IDENTITY 值,就像您今天已经在做的那样,在第二个 INSERT 中用于子 XML 片段和相应的行。
SQL
DECLARE @INPUTXML XML = '<Lineitems>
<Lineitem>
<Ticker>TER</Ticker>
<ID>0</ID>
<LineItem>Net Revenue</LineItem>
<XFundCode>TRIN</XFundCode>
<UserID>TDP</UserID>
</Lineitem>
<Lineitem>
<Ticker>TER</Ticker>
<ID>0</ID>
<LineItem>Cost of Revenue</LineItem>
<XFundCode>XXP</XFundCode>
<UserID>TDP</UserID>
</Lineitem>
</Lineitems>';
DECLARE @Ticker AS VARCHAR(MAX)
, @ID AS INT
, @Lineitem AS VARCHAR(MAX)
, @XFundCode AS VARCHAR(MAX)
, @UserID AS VARCHAR(MAX);
-- count total number of items
DECLARE @i INT
, @cnt INT = @INPUTXML.value('count(/Lineitems/Lineitem)', 'INT');
SELECT @cnt;
-- loop XML item by item
SET @i = 1;
WHILE @i <= @cnt BEGIN
SELECT @Ticker = col.value('(Ticker/text())[1]','VARCHAR(MAX)')
, @ID = col.value('(ID/text())[1]','INT')
, @Lineitem = col.value('(LineItem/text())[1]','VARCHAR(MAX)')
, @XFundCode = col.value('(XFundCode/text())[1]','VARCHAR(MAX)')
, @UserID = col.value('(UserID/text())[1]','VARCHAR(MAX)')
FROM @INPUTXML.nodes('/Lineitems/Lineitem[position() = sql:variable("@i")]') AS tab(col)
-- do whatever needed in the loop here
SET @i += 1;
END
【讨论】:
markossw,很高兴听到建议的解决方案对您有用。请在 LinkedIn 上与我联系。以上是关于将 XML 多个嵌套节点插入 SQL 表的主要内容,如果未能解决你的问题,请参考以下文章
将具有多个嵌套级别的任何 XML 读取到结构化表中以写入 Excel 的通用方法