我有数据准备插入到我的生产表中,但是ID列是NULL,需要在插入前预先填充ID。 我在另一个临时表里有这些ID......我只想简单地将这些ID应用到我的临时表里的记录。
例如... 假设我有10条记录都只需要IDs。 我在另一个临时表中有10个ID......它们只需要被应用到我的 "Ready to INSERT "临时表中的10条记录上。
我在Oracle工作了大约9年,我可以通过使用FORALL循环循环我的 "Collection "来完成这个任务......基本上,我会简单地循环循环我的 "Ready to INSERT "临时表,并为每一行应用我的另一个 "Collection "中的ID......在SQL Server中,我的工作对象是临时表而不是Collection,而且......在SQL Server中,除了WHILE之外,没有FORALL循环或任何花哨的循环。
我的目标是知道在SQL Server中用什么合适的方法来完成这个任务。 我了解到在SQL Server的世界里,很多DML操作都是基于SET的,而当我在oracle工作的时候,我们是通过arrayscollections来处理数据的,使用CURSORS或LOOPs我们会简单地对数据进行迭代。 我看到在SQL Server的世界里,使用CURSORS或者逐条记录地迭代数据是不受欢迎的。
帮我把我的头从我长期以来的 "Oracle "空间中解放出来,进入我需要的 "SQL Server "空间。 这一直是个小小的难题。
下面的代码是我目前实现的方法,然而它看起来很复杂。
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 Server中使用预生成键值 顺序 而不是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