SQL 使用来自另一个插入的记录插入

SQL Insert Using Records From Another Insert

我有3个table,如下:

tblAgentVisit (VisitID auto-increments)
VisitID (PK) | StatusID | A bunch of other columns
--------------------------------------------------
1            | 1        | etc.
2            | 1        | etc.

tblAgentVisitAgents
VisitID | AgtID | Prime
-----------------------
1       | 8507  | 1
2       | 56    | 1

tblAgentVisitLoad
AgtID
-----
2077
3068
432

每个季度,我们都会选出前 20% 的代理,并将他们的 ID 加载到 tblAgentVisitLoad

我需要为 table 中的每个代理创建一个新的、唯一的访问。我需要 INSERT 我的 StatusID 和其他列到 tblAgentVisit,获取自动递增的 VisitID(使用 OUTPUT?),然后 INSERT VisitID、AgtID 和 Prime = 1 到 tblAgentVisitAgents。同样,每个代理的每次访问都必须是唯一的。

理想情况下,这就是我的 table 完成后的样子:

tblAgentVisit (VisitID auto-increments)
VisitID (PK) | StatusID | A bunch of other columns
--------------------------------------------------
1            | 1        | etc.
2            | 1        | etc.
3            | 1        | etc.
4            | 1        | etc.
5            | 1        | etc.

tblAgentVisitAgents
VisitID | AgtID | Prime
-----------------------
1       | 8507  | 1
2       | 56    | 1
3       | 2077  | 1
4       | 3068  | 1
5       | 432   | 1

有人对在 MS SQL Server 2005 中执行此操作有任何建议吗?我完全被难住了。

我有两个可能的解决方案给你。第一个交易一些 space 以获得稍微简单的方法,第二个更复杂但总体上可能更好。

使用OUTPUT也是一种替代方法,但它需要将分配写入临时table(因为接收table不能有约束)然后写入从那里进入 tblAgentVisitAgents。这是另一个 SO 问题,详细说明了如何做到这一点:

How can I INSERT data into two tables simultaneously in SQL Server?

解决方案 1:为第一个代理分配使用临时字段。

首先,添加一列(例如,FirstAgentID)到tblAgentVisit临时在创建每次访问时存储分配的代理:

ALTER TABLE tblAgentVisit ADD FirstAgentID int NULL;

如果您使用的是 MSSQL 2008 或更高版本,您可以将此列设为 SPARSE,这样任何 NULL 记录都不会占用 space,但这在 2005 中不可用。不过,希望额外的 NULL int 列对你来说不是问题。

接下来,创建新的访问记录,临时存储您打算分配给每次访问的代理:

INSERT INTO tblAgentVisit(Status, ..., FirstAgentID)
SELECT ..., AgtId FROM tblAgentVisitLoad;

现在,使用新访问记录(及其临时 FirstAgentID)创建附属记录,为每次新访问分配适当的代理:

INSERT INTO tblAgentVisitAgents(VisitID, AgtID, Prime)
SELECT VisitID, FirstAgentID, 1
FROM tblAgentVisit
WHERE FirstAgentID IS NOT NULL;

最后,清空临时字段,以免造成任何潜在的混淆或数据重复:

UPDATE tblAgentVisit
SET FirstAgentID=NULL
WHERE FirstAgentID IS NOT NULL;

解决方案 #2:使用 CTE 和 ROW_NUMBER() 按顺序将新访问分配给代理。

我相信您也可以使用 CTE 和 ROW_NUMBER() 在两个语句中执行此操作,而无需上述临时字段:

INSERT INTO tblAgentVisit(Status, ...) blah;

WITH a AS (
   SELECT AgtId, ROW_NUMBER() OVER(ORDER BY AgtId ASC) AS row
   FROM tblAgentVisitLoad
), b AS (
   SELECT VisitID, ROW_NUMBER() OVER(ORDER BY VisitID ASC) AS row
   FROM tblAgentVisit
   WHERE NOT EXISTS(SELECT NULL FROM tblAgentVisitAgents c WHERE
      c.VisitID = tblAgentVisit.VisitID
)
INSERT INTO tblAgentVisitAgents(VisitID, AgtID, Prime)
SELECT b.VisitID, a.AgtID, 1
FROM a, b
WHERE a.row = b.row;

这将利用这样一个事实,即在 INSERT 之后没有分配代理的唯一访问是新访问。如果在其他情况下访问可能没有任何对应的 tblAgentVisitAgents 记录,您需要以某种方式过滤 CTE b 以仅包含新创建的访问。