多亲子插入

时间:2015-11-09 22:00:44

标签: sql xml stored-procedures

我试图编写一个存储过程来从XML字符串中提取信息并使用它来创建多个父子关系。我试图将此XML推送到实际的数据库表中。基本上,本地客户端将XML文件发送到数据库并将其存储为字符串。然后我需要从该字符串中提取信息并更新相应的表。如果这只是表-A到表-B,这将不会那么困难。我遇到的问题是需要从适用的表A到表-B到表-C到表-D。以下是XML示例:

<RunRecordFile>
    <Competition>
        <Name>Daily</Name>
        <StartDate>11/9/2015 12:40:07 AM</StartDate>
        <Runs>
            <Id>123</Id>
            <Name>Daily Run</Name>
            <RunDate>11/9/2015 12:40:07 AM</RunDate>
            <CompetitionId>1</CompetitionId>
            <RunRecords>
                <Id>001</Id>
                <Number>007</Number>
                <ElapsedTime>23.007</ElapsedTime>
                <RunId>123</RunId>
            </RunRecords>
        </Runs>
        <Runs>
            <Id>456</Id>
            <Name>Daily Run</Name>
            <RunDate>11/9/2015 12:47:07 AM</RunDate>
            <CompetitionId>1</CompetitionId>
            <RunRecords>
                <Id>002</Id>
                <Number>700</Number>
                <ElapsedTime>23.707</ElapsedTime>
                <RunId>456</RunId>
                <RunRecordSpecialty>
                    <Id>1</Id>
                    <Handicap>17</Handicap>
                    <TeamPoints>50000</TeamPoints>
                    <RunRecordId>002</RunRecordId>
                </RunRecordSpecialty>
            </RunRecords>
        </Runs>
    </Competition>
</RunRecordFile>

我试图使用DECLARED表来保存每个创建的主键,并使用SQL OUTPUT来收集它们。当我运行我的SQL时,我得到了(0)行更新。这是我在SQL中尝试过的内容:

CREATE PROC [dbo].[RaceFilePush]
AS
DECLARE @CompetitionIdMapping TABLE ( CompetitionId bigint )
DECLARE @RunIdMapping TABLE ( RunId bigint )
DECLARE @RunRecordIdMapping TABLE ( RunRecordId bigint )
BEGIN
    DECLARE @rrXML AS XML
    DECLARE @rrfId AS BIGINT

    SET @rrfId = (SELECT TOP 1 Id FROM RunRecordFile WHERE Submitted IS NULL)
    SET @rrXML = (SELECT TOP 1 RaceFile FROM RunRecordFile WHERE Id = @rrfId)

    BEGIN TRAN Competitions
    BEGIN TRY

        INSERT INTO Competition (
            Name
            ,StartDate
        )
        OUTPUT INSERTED.Id INTO @CompetitionIdMapping(CompetitionId)
        SELECT
            xCompetition.value('(Name)[1]', 'varchar(225)') AS Name
            ,xCompetition.value('(StartDate)[1]', 'datetime') AS StartDate
            ,@rrfId AS RunRecordFileId
        FROM
            @rrXML.nodes('/RunRecordFile/Competition') AS E(xCompetition)

        INSERT INTO Run (
            Name
            ,RunDate
            ,CompetitionId
        )
        OUTPUT INSERTED.Id INTO @RunIdMapping(RunId)
        SELECT
            xRuns.value('(Name)[1]','varchar(80)') AS Name
            ,xRuns.value('(RunDate)[1]','datetime') AS RunDate
            ,(SELECT CompetitionId FROM @CompetitionIdMapping)
        FROM
            @rrXML.nodes('/RunRecordFile/Competition/Runs') AS E(xRuns)

        INSERT INTO RunRecord (
            Number
            ,ElapsedTime
            ,RunId
        )
        OUTPUT INSERTED.Id INTO @RunRecordIdMapping(RunRecordId)
        SELECT
            xRunRecords.value('(Number)[1]','varchar(10)') AS Number
            ,xRunRecords.value('(ElapsedTime)[1]','numeric(10,5)') AS ElapsedTime
            ,(SELECT RunId FROM @RunIdMapping)
        FROM
            @rrXML.nodes('/RunRecordFile/Competition/Runs/RunRecords') AS E(xRunRecords)

        INSERT INTO RunRecordSpecialty (
            Handicap
            ,TeamPoints
            ,RunRecordId
        )
        SELECT
            xRunRecordSpecialty.value('(Handicap)[1]','numeric(10,5)') AS Handicap
            ,xRunRecordSpecialty.value('(TeamPoints)[1]','numeric(10,5)') AS TeamPoints
            ,(SELECT RunRecordId FROM @RunRecordIdMapping)
        FROM
            @rrXML.nodes('/RunRecordFile/Competition/Runs/RunRecordSpecialty') AS E(xRunRecordSpecialty)

        UPDATE RunRecordFile SET Submitted = GETDATE() WHERE Id = @rrfId

    COMMIT TRAN Competitions
    END TRY
    BEGIN CATCH
        ROLLBACK TRAN Competitions
    END CATCH
END

1 个答案:

答案 0 :(得分:0)

使用这个SQL,您可以将整个事物放入一个平坦的声明表@tbl

备注:我将您问题中的XML放入名为@xml的变量中。根据您的需要进行调整......

DECLARE @tbl TABLE (
    [Competition_Name] [varchar](max) NULL,
    [Competition_StartDate] [datetime] NULL,
    [Run_Id] [int] NULL,
    [Run_Name] [varchar](max) NULL,
    [Run_RunDate] [datetime] NULL,
    [Run_CompetitionId] [int] NULL,
    [RunRecords_Id] [int] NULL,
    [RunRecords_Number] [int] NULL,
    [RunRecords_ElapsedTime] [float] NULL,
    [RunRecords_RunId] [int] NULL,
    [RunRecordSpecialty_Id] [int] NULL,
    [RunRecordSpecialty_Handicap] [int] NULL,
    [RunRecordSpecialty_TeamPoints] [int] NULL,
    [RunRecordSpecialty_RunRecordId] [int] NULL
); 

INSERT INTO @tbl
SELECT Competition.value('Name[1]','varchar(max)') AS Competition_Name
      ,Competition.value('StartDate[1]','datetime') AS Competition_StartDate

      ,Run.value('Id[1]','int') AS Run_Id 
      ,Run.value('Name[1]','varchar(max)') AS Run_Name 
      ,Run.value('RunDate[1]','datetime') AS Run_RunDate 
      ,Run.value('CompetitionId[1]','int') AS Run_CompetitionId 

      ,RunRecords.value('Id[1]','int') AS RunRecords_Id 
      ,RunRecords.value('Number[1]','int') AS RunRecords_Number
      ,RunRecords.value('ElapsedTime[1]','float') AS RunRecords_ElapsedTime 
      ,RunRecords.value('RunId[1]','int') AS RunRecords_RunId

      ,RunRecordSpecialty.value('Id[1]','int') AS RunRecordSpecialty_Id 
      ,RunRecordSpecialty.value('Handicap[1]','int') AS RunRecordSpecialty_Handicap 
      ,RunRecordSpecialty.value('TeamPoints[1]','int') AS RunRecordSpecialty_TeamPoints
      ,RunRecordSpecialty.value('RunRecordId[1]','int') AS RunRecordSpecialty_RunRecordId

FROM @xml.nodes('/RunRecordFile/Competition') AS A(Competition)
OUTER APPLY Competition.nodes('Runs') AS B(Run)
OUTER APPLY Run.nodes('RunRecords') AS C(RunRecords)
OUTER APPLY RunRecords.nodes('RunRecordSpecialty') AS D(RunRecordSpecialty)
;
SELECT * FROM @tbl

如果您需要生成ID,只需将列添加到@tbl并在那里写入,“在流程上”或之后用UPDATE语句。

通过这个平面表工作应该很容易,只需用DISTINCT选择所需的数据级别并插入行,然后插入下一级等等......

祝你好运!