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
以仅包含新创建的访问。
我有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
以仅包含新创建的访问。