TSQL Inserting records from XML string

前端 未结 1 1237
無奈伤痛
無奈伤痛 2021-01-22 03:54

I have a SQL query that is inserting records into a table from an XML string that I pass to it. The string could contain 1 node or multiple so each one is a new record.

相关标签:
1条回答
  • 2021-01-22 04:29

    Given the clarification of this statement in the question:

    For each trainer, I need to also insert a record into that table but it needs to have the last inserted record id of the segment.

    being (as found in the comments on the question):

    There would be a total of 4 records inserted into the trainer table, 2 have the segment id of 1 and the other 2 with the segment id of 2.

    The following will insert this data into related tables that have auto-incrementing IDs. In the sample data, I varied the EmpID values slightly to make it clearer that it is indeed working as expected.

    DECLARE @DocumentID INT, @ImportData XML;
    
    SET @ImportData = N'
    <root>
        <data>
          <segment>
             <trainingEventID>9</trainingEventID>
             <localeID>641</localeID>
             <numOfTeammates>12</numOfTeammates>
             <nonProdHrs>21</nonProdHrs>
             <segmentDate>10/10/2014</segmentDate>
             <trainers>
                <trainer>
                   <empID>HUS123</empID>
                </trainer>
                <trainer>
                   <empID>Dan123</empID>
                </trainer>
             </trainers>
          </segment>
        </data>
        <data>
          <segment>
             <trainingEventID>9</trainingEventID>
             <localeID>641</localeID>
             <numOfTeammates>12</numOfTeammates>
             <nonProdHrs>21</nonProdHrs>
             <segmentDate>10/25/2014</segmentDate>
             <trainers>
                <trainer>
                   <empID>HUS1234</empID>
                </trainer>
                <trainer>
                   <empID>Dan1234</empID>
                </trainer>
             </trainers>
          </segment>
       </data>
    </root>';
    
    
    DECLARE @Segment TABLE (SegmentId INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
                            TrainingEventID INT NOT NULL, -- Unique
                            LocaleID INT NOT NULL, -- Unique
                            NumOfTeammates INT,
                            NonProdHrs INT,
                            SegmentDate DATE); -- Unique
    -- Ideally create UNIQUE INDEX with the 3 fields noted above
    DECLARE @Trainer TABLE (TrainerId INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
                            SegmentID INT NOT NULL, -- FK to Segment.SegmentID
                            EmpID VARCHAR(50) NOT NULL);
    
    EXEC sp_xml_preparedocument @DocumentID OUTPUT, @ImportData;
    
    -- First pass: extract "Segment" rows
    INSERT INTO @Segment
                (TrainingEventID, LocaleID, NumOfTeammates, NonProdHrs, SegmentDate)
       SELECT TrainingEventID, LocaleID, NumOfTeammates, NonProdHrs, SegmentDate
       FROM   OPENXML (@DocumentID, N'/root/data/segment', 2) 
                 WITH (TrainingEventID   INT  './trainingEventID/text()', 
                       LocaleID          INT  './localeID/text()',
                       NumOfTeammates    INT  './numOfTeammates/text()',
                       NonProdHrs        INT  './nonProdHrs/text()',
                       SegmentDate       DATE './segmentDate/text()');
    
    
    -- Second pass: extract "Trainer" rows
    INSERT INTO @Trainer (SegmentID, EmpID)
       SELECT seg.SegmentID, trnr.EmpID
       FROM   OPENXML (@DocumentID, N'/root/data/segment/trainers/trainer', 2) 
                 WITH (TrainingEventID   INT         '../../trainingEventID/text()',
                       LocaleID          INT         '../../localeID/text()',
                       SegmentDate       DATE        '../../segmentDate/text()',
                       EmpID             VARCHAR(50) './empID/text()') trnr
       INNER JOIN @Segment seg
               ON seg.[TrainingEventID] = trnr.[TrainingEventID]
              AND seg.[LocaleID] = trnr.[LocaleID]
              AND seg.[SegmentDate] = trnr.[SegmentDate];
    
    
    EXEC sp_xml_removedocument @DocumentID;
    -------------------
    
    SELECT * FROM @Segment ORDER BY [SegmentID];
    SELECT * FROM @Trainer ORDER BY [SegmentID];
    

    Output:

    SegmentId   TrainingEventID   LocaleID   NumOfTeammates   NonProdHrs   SegmentDate
    1           9                 641        12               21           2014-10-10
    2           9                 641        12               21           2014-10-25
    
    TrainerId   SegmentID   EmpID
    1           1           HUS123
    2           1           Dan123
    3           2           HUS1234
    4           2           Dan1234
    

    References:

    • OPENXML
    • sp_xml_preparedocument
    • sp_xml_removedocument
    0 讨论(0)
提交回复
热议问题