SQL - 将XML字符串中的记录插入多个表中

时间:2018-01-31 15:35:51

标签: sql-server xml stored-procedures sql-server-2012

我有一个父和子表,我需要插入数据。对于创建的每个父任务,需要添加子任务,引用父ID。

XML结构:

<request>
   <task>
      <user>Q500</user>
      <tool>31</tool>
      <role>
         <roleID>w1234</roleID>
         <action>2</action>
      </role>
   </task>
   <task>
      <user>Q500</user>
      <tool>31</tool>
      <role>
         <roleID>w123456</roleID>
         <action>1</action>
      </role>
   </task>
</request>

插入父级(任务):

-- Add tasks
INSERT INTO Task
        ( RequestID ,
          ToolID ,
          QID 
        )
 SELECT  @requestID,
         ParamValues.x1.value('tool[1]', 'INT'),
         ParamValues.x1.value('user[1]', 'VARCHAR(10)')
 FROM @tasks.nodes('/request/task') AS ParamValues(x1);

插入儿童(角色):

INSERT INTO TaskRole
            ( TaskID, 
              RoleID, 
              ActionID )
 SELECT  t.TaskID,
         ParamValues.x1.value('roleID[1]', 'varchar(10)'),
         ParamValues.x1.value('action[1]', 'INT')
 FROM Task AS t
 JOIN @tasks.nodes('/request/task/role') AS ParamValues(x1)
 ON t.RequestID = @requestID
 AND t.ToolID =  ParamValues.x1.value('../tool[1]', 'INT')
 AND t.QID =  ParamValues.x1.value('../user[1]', 'VARCHAR(10)')

上述代码的问题是usertool在多个任务中可能相同,所以当需要加入时,我会收到大量重复的条目。

在这种情况下,子查询正在查找具有ToolID=31User=Q500的父任务。由于有两个,它插入两个不正确的记录,每个父母应该只有一个孩子。

我还有什么办法可以实现这个目标,因为我没有什么独特的东西可以加入?

更新1(任务表结构):

CREATE TABLE [Task](
    [TaskID] [INT] IDENTITY(1,1) NOT NULL,
    [RequestID] [INT] NOT NULL,
    [ToolID] [INT] NOT NULL,
    [QID] [VARCHAR](10) NOT NULL,
    [StatusID] [INT] NOT NULL CONSTRAINT [DF_Task_StatusID]  DEFAULT ((1)),
    [TaskOwner] [VARCHAR](10) NULL,
 CONSTRAINT [PK_Task] PRIMARY KEY CLUSTERED 
(
    [TaskID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [TaskRole](
    [TaskID] [INT] NOT NULL,
    [RoleID] [VARCHAR](10) NOT NULL,
    [ActionID] [INT] NOT NULL,
 CONSTRAINT [PK_TaskRoles] PRIMARY KEY CLUSTERED 
(
    [TaskID] ASC,
    [RoleID] ASC,
    [ActionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

更新2 - 示例代码:

这是我想要做的一个例子。在第一次传递时插入父(任务),以便为它们创建AI/PK。然后,我需要将子记录(角色)插入到另一个表中,引用它所属的任务。

DECLARE @parent TABLE (requestID INT IDENTITY,qid varchar(10), tool int)
DECLARE @child TABLE  (taskID INT IDENTITY, requestID INT, roleID VARCHAR(20), actionID int)

INSERT INTO @parent( qid, tool ) VALUES  ( 'Q500', 31) -- Task 1
INSERT INTO @parent( qid, tool ) VALUES  ( 'Q500', 31) -- Task 2

INSERT INTO @child( requestID, roleID, actionID ) VALUES  (1, 'w1234', 2) -- Role for Task 1
INSERT INTO @child( requestID, roleID, actionID ) VALUES  (1, 'w123456', 1) -- Role for Task 2

SELECT * 
FROM @parent AS p
JOIN @child AS c
ON p.requestID = c.requestID

enter image description here

2 个答案:

答案 0 :(得分:1)

使用Cross Apply跟随enter image description here可能有助于获取原始数据,然后可以将其插入到父子表中

information_schema.tables

以上SQL Select的输出如下

enter image description here

答案 1 :(得分:0)

所以问题是你需要将来自任务的身份TaskID与正确的角色相关联,但是你的源数据中没有任何与回归相关的独特信息。插入Task的行。您可以使用游标插入Task并输出每行的标识列,然后插入TaskRole,但这样效率非常低。

幸运的是,MERGE的一个技巧是你不仅可以OUTPUT插入列(TaskID),还可以使用源列 - 甚至是未使用过的列,例如RoleID和ActionID。因此,您可以使用MERGE作为内部查询的一部分插入Task,并使用输出插入TaskRole。

请注意ON 1 = 0。这基本上迫使MERGE表现得像INSERT

INSERT INTO TaskRole (TaskID, RoleID, ActionID)
SELECT TaskID, RoleID, ActionID
FROM (
    MERGE INTO Task
    USING (
        SELECT pv.item.value('../user[1]', 'VARCHAR(10)') AS QID
            , pv.item.value('../tool[1]', 'INT') AS ToolID
            , pv.item.value('roleID[1]', 'varchar(10)') RoleID
            , pv.item.value('action[1]', 'INT') ActionID
        FROM @tasks.nodes('/request/task/role') pv(item)
    ) AS src
    ON 1 = 0
    WHEN NOT MATCHED THEN INSERT (RequestID, ToolID, QID) VALUES (@RequestID, ToolID, QID)
    OUTPUT Inserted.TaskID, src.RoleID, src.ActionID
) src;