如何将一组键 (UniqueID) 添加到临时 table 以便稍后插入到生产中 Table
How to Add a Set of Keys (UniqueIDs) to a Temp table to later INSERT into Production Table
我已准备好将数据插入到我的作品中 table,但是 ID 列为 NULL,需要在插入之前预先填充 ID。我在另一个 Temp Table 中有这些 ID...我只想将这些 ID 应用到我的 Temp Table.
中的记录
例如...假设我有 10 条记录都只需要 ID。我在另一个临时 table 正好有 10 个 ID...它们只需要应用到我的 'Ready to INSERT' 临时 Table.
中的 10 条记录
我在 Oracle 工作了大约 9 年,我可以简单地通过使用 FORALL 循环遍历我的 'Collection' 来做到这一点...基本上我会简单地遍历我的 'Ready to INSERT' temp table 并为每一行应用我的其他 'Collection' 的 ID... 在 SQL 服务器中 我正在使用 Temp Tables NOT Collections 并且...没有FORALL 循环或 SQL 服务器中除 WHILE 之外的任何奇特循环。
我的目标是了解在 SQL 服务器中完成此操作的适当方法。我了解到,在 SQL 服务器世界中,许多 DML 操作都是基于 SET 的,而当我在 oracle 中工作时,我们通过 arrays/collections 处理数据并使用 CURSORS 或 LOOP,我们将简单地遍历数据.我在 SQL 服务器世界中看到使用 CURSORS and/or 逐条遍历数据记录是不受欢迎的。
帮我把头从 'Oracle' space 中解脱出来,进入我需要进入的 'SQL Server' space 中。这有有点挣扎。
下面的代码是我目前实现它的方式,但它看起来很复杂。
SET NOCOUNT ON;
DECLARE @KeyValueNewMAX INT,
@KeyValueINuse INT,
@ClientID INT,
@Count INT;
DROP TABLE IF EXISTS #InterOtherSourceData;
DROP TABLE IF EXISTS #InterOtherActual;
DROP TABLE IF EXISTS #InterOtherIDs;
CREATE TABLE #InterOtherSourceData -- Data stored here for DML until data is ready for INSERT
(
UniqueID INT IDENTITY( 1, 1 ),
NewIntOtherID INT,
ClientID INT
);
CREATE TABLE #InterOtherActual -- Prod Table where the data will be INSERTED Into
(
IntOtherID INT,
ClientID INT
);
CREATE TABLE #InterOtherIDs -- Store IDs needing to be applied to Data
(
UniqueID INT IDENTITY( 1, 1 ),
NewIntOtherID INT
);
BEGIN
/* TEST Create Fake Data and store it in temp table */
WITH fakeIntOtherRecs AS
(
SELECT 1001 AS ClientID, 'Jake' AS fName, 'Jilly' AS lName UNION ALL
SELECT 2002 AS ClientID, 'Jason' AS fName, 'Bateman' AS lName UNION ALL
SELECT 3003 AS ClientID, 'Brain' AS fName, 'Man' AS lName
)
INSERT INTO #InterOtherSourceData (ClientID)
SELECT fc.ClientID--, fc.fName, fc.lName
FROM fakeIntOtherRecs fc
;
/* END TEST Prep Fake Data */
/* Obtain count so we know how many IDs we need to create */
SELECT @Count = COUNT(*) FROM #InterOtherSourceData;
PRINT 'Count: ' + CAST(@Count AS VARCHAR);
/* For testing set value OF KeyValuePre to the max key currently in use by Table */
SELECT @KeyValueINuse = 13;
/* Using the @Count let's obtain the new MAX ID... basically Existing_Key + SourceRecordCount = New_MaxKey */
SELECT @KeyValueNewMAX = @KeyValueINuse + @Count /* STORE new MAX ID in variable */
/* Print both keys for testing purposes to review */
PRINT 'KeyValue Current: ' + CAST(@KeyValueINuse AS VARCHAR) + ' KeyValue Max: ' + CAST(@KeyValueNewMAX AS VARCHAR);
/* Using recursive CTE generate a fake table containing all of the IDs we want to INSERT into Prod Table */
WITH CTE AS
(
SELECT (@KeyValueNewMAX - @Count) + 1 AS STARTMINID, @KeyValueNewMAX AS ENDMAXID UNION ALL
/* SELECT FROM CTE to create Recursion */
SELECT STARTMINID + 1 AS STARTMINID, ENDMAXID FROM CTE
WHERE (STARTMINID + 1) < (@KeyValueNewMAX + 1)
)
INSERT INTO #InterOtherIDs (NewIntOtherID)
SELECT c.STARTMINID AS NewIntOtherID
FROM CTE c
;
/* Apply New IDs : Using the IDENTITY fields on both Temp Tables I can JOIN the tables by the IDENTITY columns
| Is there a BETTER Way to do this?... like LOOP over each record rather than having to build up common IDs in both tables using IDENTITY columns?
*/
UPDATE #InterOtherSourceData SET NewIntOtherID = oi.NewIntOtherID
FROM #InterOtherIDs oi
JOIN #InterOtherSourceData o ON o.UniqueID = oi.UniqueID
;
/* View data that is ready for insert */
--SELECT *
--FROM #InterOtherSourceData
--;
/* INSERT DATA INTO PRODUCTION TABLE */
INSERT INTO #InterOtherActual (IntOtherID, ClientId)
SELECT NewIntOtherID, ClientID
FROM #InterOtherSourceData
;
SELECT * FROM #InterOtherActual;
END
要在 SQL 服务器中预生成键值,请使用 sequence 而不是 IDENTITY 列。
例如
drop table if exists t
drop table if exists #t_stg
drop sequence t_seq
go
create sequence t_seq start with 1 increment by 1
create table t(id int primary key default (next value for t_seq),a int, b int)
create table #t_stg(id int, a int, b int)
insert into #t_stg(a,b) values (1,2),(3,3),(4,5)
update #t_stg set id = next value for t_seq
--select * from #t_stg
insert into t(id,a,b)
select * from #t_stg
我已准备好将数据插入到我的作品中 table,但是 ID 列为 NULL,需要在插入之前预先填充 ID。我在另一个 Temp Table 中有这些 ID...我只想将这些 ID 应用到我的 Temp Table.
中的记录例如...假设我有 10 条记录都只需要 ID。我在另一个临时 table 正好有 10 个 ID...它们只需要应用到我的 'Ready to INSERT' 临时 Table.
中的 10 条记录我在 Oracle 工作了大约 9 年,我可以简单地通过使用 FORALL 循环遍历我的 'Collection' 来做到这一点...基本上我会简单地遍历我的 'Ready to INSERT' temp table 并为每一行应用我的其他 'Collection' 的 ID... 在 SQL 服务器中 我正在使用 Temp Tables NOT Collections 并且...没有FORALL 循环或 SQL 服务器中除 WHILE 之外的任何奇特循环。
我的目标是了解在 SQL 服务器中完成此操作的适当方法。我了解到,在 SQL 服务器世界中,许多 DML 操作都是基于 SET 的,而当我在 oracle 中工作时,我们通过 arrays/collections 处理数据并使用 CURSORS 或 LOOP,我们将简单地遍历数据.我在 SQL 服务器世界中看到使用 CURSORS and/or 逐条遍历数据记录是不受欢迎的。
帮我把头从 'Oracle' space 中解脱出来,进入我需要进入的 'SQL Server' space 中。这有有点挣扎。
下面的代码是我目前实现它的方式,但它看起来很复杂。
SET NOCOUNT ON;
DECLARE @KeyValueNewMAX INT,
@KeyValueINuse INT,
@ClientID INT,
@Count INT;
DROP TABLE IF EXISTS #InterOtherSourceData;
DROP TABLE IF EXISTS #InterOtherActual;
DROP TABLE IF EXISTS #InterOtherIDs;
CREATE TABLE #InterOtherSourceData -- Data stored here for DML until data is ready for INSERT
(
UniqueID INT IDENTITY( 1, 1 ),
NewIntOtherID INT,
ClientID INT
);
CREATE TABLE #InterOtherActual -- Prod Table where the data will be INSERTED Into
(
IntOtherID INT,
ClientID INT
);
CREATE TABLE #InterOtherIDs -- Store IDs needing to be applied to Data
(
UniqueID INT IDENTITY( 1, 1 ),
NewIntOtherID INT
);
BEGIN
/* TEST Create Fake Data and store it in temp table */
WITH fakeIntOtherRecs AS
(
SELECT 1001 AS ClientID, 'Jake' AS fName, 'Jilly' AS lName UNION ALL
SELECT 2002 AS ClientID, 'Jason' AS fName, 'Bateman' AS lName UNION ALL
SELECT 3003 AS ClientID, 'Brain' AS fName, 'Man' AS lName
)
INSERT INTO #InterOtherSourceData (ClientID)
SELECT fc.ClientID--, fc.fName, fc.lName
FROM fakeIntOtherRecs fc
;
/* END TEST Prep Fake Data */
/* Obtain count so we know how many IDs we need to create */
SELECT @Count = COUNT(*) FROM #InterOtherSourceData;
PRINT 'Count: ' + CAST(@Count AS VARCHAR);
/* For testing set value OF KeyValuePre to the max key currently in use by Table */
SELECT @KeyValueINuse = 13;
/* Using the @Count let's obtain the new MAX ID... basically Existing_Key + SourceRecordCount = New_MaxKey */
SELECT @KeyValueNewMAX = @KeyValueINuse + @Count /* STORE new MAX ID in variable */
/* Print both keys for testing purposes to review */
PRINT 'KeyValue Current: ' + CAST(@KeyValueINuse AS VARCHAR) + ' KeyValue Max: ' + CAST(@KeyValueNewMAX AS VARCHAR);
/* Using recursive CTE generate a fake table containing all of the IDs we want to INSERT into Prod Table */
WITH CTE AS
(
SELECT (@KeyValueNewMAX - @Count) + 1 AS STARTMINID, @KeyValueNewMAX AS ENDMAXID UNION ALL
/* SELECT FROM CTE to create Recursion */
SELECT STARTMINID + 1 AS STARTMINID, ENDMAXID FROM CTE
WHERE (STARTMINID + 1) < (@KeyValueNewMAX + 1)
)
INSERT INTO #InterOtherIDs (NewIntOtherID)
SELECT c.STARTMINID AS NewIntOtherID
FROM CTE c
;
/* Apply New IDs : Using the IDENTITY fields on both Temp Tables I can JOIN the tables by the IDENTITY columns
| Is there a BETTER Way to do this?... like LOOP over each record rather than having to build up common IDs in both tables using IDENTITY columns?
*/
UPDATE #InterOtherSourceData SET NewIntOtherID = oi.NewIntOtherID
FROM #InterOtherIDs oi
JOIN #InterOtherSourceData o ON o.UniqueID = oi.UniqueID
;
/* View data that is ready for insert */
--SELECT *
--FROM #InterOtherSourceData
--;
/* INSERT DATA INTO PRODUCTION TABLE */
INSERT INTO #InterOtherActual (IntOtherID, ClientId)
SELECT NewIntOtherID, ClientID
FROM #InterOtherSourceData
;
SELECT * FROM #InterOtherActual;
END
要在 SQL 服务器中预生成键值,请使用 sequence 而不是 IDENTITY 列。
例如
drop table if exists t
drop table if exists #t_stg
drop sequence t_seq
go
create sequence t_seq start with 1 increment by 1
create table t(id int primary key default (next value for t_seq),a int, b int)
create table #t_stg(id int, a int, b int)
insert into #t_stg(a,b) values (1,2),(3,3),(4,5)
update #t_stg set id = next value for t_seq
--select * from #t_stg
insert into t(id,a,b)
select * from #t_stg