2013-05-16 52 views
1

我有一些XML,我需要插入到兩個數據庫表。第二張表(TblSales)必須包含第一張(TblDetails.Id)的PK。SQL Server:操縱複雜的XML到表

我可以使用XQuery將數據插入到這些表中,但我想不出一種將TblDetails的PK轉換爲TblSales的FK(DetailsId)的好方法?

我使用SQL Server 2005的

DECLARE @xml XML 
SET @xml = 
N'<Details> 
    <Detail> 
     <Sub>SubjectName 1</Sub> 
     <Data>DataName 1</Data> 
     <Sales> 
      <Sale> 
       <Name>Name 1</Name> 
      </Sale> 
      <Sale> 
       <Name>Name 11</Name> 
      </Sale> 
      <Sale> 
       <Name>Name 111</Name> 
      </Sale> 
     </Sales> 
    </Detail> 
    <Detail> 
     <Sub>SubjectName 2</Sub> 
     <Data>DataName 2</Data> 
     <Sales> 
      <Sale> 
       <Name>Name 2</Name> 
      </Sale> 
      <Sale> 
       <Name>Name 22</Name> 
      </Sale> 
      <Sale> 
       <Name>Name 222</Name> 
      </Sale> 
     </Sales> 
    </Detail> 
</Details>' 

-- Details 

IF object_id('TblDetails') is not null 
    drop table TblDetails 

create table TblDetails ( 
    Id int identity not null primary key, 
    Sub nvarchar(max), 
    Data nvarchar(max)) 

INSERT INTO TblDetails (
    Sub, 
    Data 
) 
SELECT 
    ParamValues.Detail.value('(Sub)[1]','NVARCHAR(MAX)') AS [Sub], 
    ParamValues.Detail.value('(Data)[1]','NVARCHAR(MAX)') AS [Data] 
FROM 
    @xml.nodes('/Details/Detail') AS ParamValues(Detail) 


-- Sales 

IF object_id('TblSales') is not null 
    drop table TblSales 

create table TblSales ( 
    Id int identity not null primary key, 
    Name nvarchar(max), 
    DetailsId int) -- FK to TblDetails.Id PK 

INSERT INTO TblSales (
    Name, 
    DetailsId 
) 
SELECT 
    ParamValues.Sale.value('(Name)[1]','NVARCHAR(MAX)') AS [Name], 
    1 --Need to get the PK of the newly added row in TblDetails 
FROM 
    @xml.nodes('/Details/Detail/Sales/Sale') AS ParamValues(Sale) 



select * from TblDetails 
select * from TblSales 

回答

1

那麼,你可以嘗試這樣的事情:

-- first insert your rows into "TblDetails" 
INSERT INTO dbo.TblDetails(Sub, Data) 
    SELECT 
     ParamValues.Detail.value('(Sub)[1]','VARCHAR(50)') AS [Sub], 
     ParamValues.Detail.value('(Data)[1]','VARCHAR(50)') AS [Data] 
    FROM 
     @xml.nodes('/Details/Detail') AS ParamValues(Detail) 

-- now, in a second step, use a CTE (Common Table Expression) to get the 
-- inserted data and the new data for TblSales 
;WITH CTE AS 
(
    SELECT 
     ParamValues.Detail.value('(Sub)[1]','VARCHAR(50)') AS [Sub], 
     ParamValues.Detail.value('(Data)[1]','VARCHAR(50)') AS [Data], 
     XTbl.Sale.value('(Name)[1]', 'VARCHAR(50)') AS [Name] 
    FROM 
     @xml.nodes('/Details/Detail') AS ParamValues(Detail) 
    CROSS APPLY 
     ParamValues.Detail.nodes('Sales/Sale') AS XTbl(Sale) 
) 
INSERT INTO dbo.TblSales(Name, DetailsId) 
    SELECT 
     Name, 
     (SELECT TOP 1 ID -- fetch the ID from the TblDetails based on "Sub" and "Data" 
     FROM TblDetails d 
     WHERE d.Sub = CTE.Sub AND d.Data = CTE.DATA)  
    FROM CTE 

當然,這種方法只有真正起作用的,如果你的的(Sub, Data)組合在TblDetails中獨一無二。也許你需要調整這一點 - 但它應該是一個很好的startig點,我希望!

+0

謝謝,很遺憾,TblDetails中的數據不能保證是唯一的。這是用於執行此類程序的常用技術嗎?另一種方法是在'TblSales'表中添加一個額外的列,用於存儲'SalesXml'數據。然後當'TblDetails'上的'插入'發生時,我可以將'插入的TblDetails.Id'和'插入的TblDetails.SalesXml''輸出'到臨時表中。但是,這只是將額外的數據添加到僅用於此過程的表中。 –

+1

@DanielBillingham:如果你的('Sub,Data')不能是唯一的 - 那麼你必須在源XML中有其他的東西,你可以**唯一標識**一個''節點 - 否則這將永遠不會工作。 。 –