TSQL从XML字符串插入记录

时间:2014-10-29 23:14:23

标签: sql-server xml tsql stored-procedures

我有一个SQL查询,它将记录从我传递给它的XML字符串插入表中。该字符串可以包含1个节点或多个节点,因此每个节点都是一个新记录。

这是我的XML字符串:

<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>HUS123</empID>
            </trainer>
            <trainer>
               <empID>Dan123</empID>
            </trainer>
         </trainers>
      </segment>
   </data>
</root>

每个segment都是添加到表格中的新记录。

现在,我有一个名为trainers的单独表。对于每个培训师,我还需要在该表中插入记录,但它需要具有该段的last inserted record id

这是我的问题:

 INSERT INTO myTable(trainingEventID, localeID, segmentDate, numofTeammates, nonProdHrs)
    SELECT ParamValues.x1.value('trainingEventID[1]', 'INT'),
           ParamValues.x1.value('localeID[1]', 'INT'),
           ParamValues.x1.value('segmentDate[1]', 'DATE'),
           ParamValues.x1.value('numOfTeammates[1]', 'INT'),
           ParamValues.x1.value('nonProdHrs[1]', 'FLOAT')
    FROM   @xml.nodes('/root/data/segment') AS ParamValues(x1);

如何将训练器插入到具有从段插入创建的记录ID的另一个表中?

1 个答案:

答案 0 :(得分:1)

在问题中澄清了这一陈述:

  

对于每个培训师,我还需要在该表中插入一条记录,但它需要具有该段的最后一个插入记录ID。

存在(在问题的评论中找到):

  

教练表中总共有4条记录,2条段ID为1,另2条段ID为2。

以下内容将此数据插入到具有自动递增ID的相关表中。在示例数据中,我略微改变了EmpID值,以便更清楚地确实它按预期工作。

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];

输出:

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

参考文献: