SQL Server:将复杂的xml操作到表中

时间:2013-05-16 15:38:14

标签: sql xml sql-server-2005 xquery

我有一些XML需要插入到两个数据库表中。第二个表(TblSales)必须包含第一个表(TblDetails.Id)的PK。

我可以使用XQuery将数据插入到这些表中,但我想不出将TblDetails的PK转换为DetailsId的FK(TblSales)的好方法吗?

我正在使用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 个答案:

答案 0 :(得分: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)在{{1}}中唯一时,此方法才有效。也许你需要稍微调整一下 - 但它应该是一个很好的起点,我希望!