我有两个表,如下所示:
我需要通过存储过程插入一些数据,如下代码:
ALTER PROCEDURE [dbo].[DeviceInvoiceInsert]
@dt AS DeviceInvoiceArray READONLY
AS
DECLARE @customerDeviceId BIGINT
DECLARE @customerId BIGINT
DECLARE @filterChangeDate DATE
BEGIN
SET @customerId = (SELECT TOP 1 CustomerId FROM @dt
WHERE CustomerId IS NOT NULL)
SET @filterChangeDate = (SELECT TOP 1 filterChangeDate FROM @dt)
INSERT INTO CustomerDevice (customerId, deviceId, deviceBuyDate, devicePrice)
SELECT customerId, deviceId, deviceBuyDate, devicePrice
FROM @dt
WHERE CustomerId IS NOT NULL
SET @customerDeviceId = SCOPE_IDENTITY()
INSERT INTO FilterChange (customerId, filterId, customerDeviceId, filterChangeDate)
SELECT @customerId, dt.filterId, @customerDeviceId, @filterChangeDate
FROM @dt AS dt
END
Run Code Online (Sandbox Code Playgroud)
问题在于,当过程想要将数据插入表中时FilterChange,@customerDeviceId总是具有最后一个 IDENTITY Id。
我怎样才能解决这个问题?
更新
感谢您的@T N回答,但他的解决方案只是为每个设备插入一个过滤器,所以就我而言,每个设备可以有多个过滤器
如上所述,使用OUTPUT子句是捕获插入的 IDENTITY 或其他隐式分配值的最佳方法。但是,您还需要将此数据与源表中的其他值关联起来。据我所知,使用常规语句无法做到这一点,常规语句只能通过伪表INSERT从目标表中捕获数据。INSERTED
我假设第一个目标表中显式插入的值都不能用于可靠地唯一标识源记录。
解决方法是使用该MERGE语句执行插入。然后该OUTPUT子句可用于捕获源数据和插入的目标数据的组合。
ALTER PROCEDURE [dbo].[DeviceInvoiceInsert]
@dt AS DeviceInvoiceArray READONLY
AS
BEGIN
-- Temp table to receive captured data from output clause
DECLARE @FilterChangeData TABLE (
customerId INT,
filterId INT,
customerDeviceId INT,
filterChangeDate DATETIME2
)
-- Merge is used instead of a plain INSERT so that we can capture
-- a combination of source and inserted data
MERGE CustomerDevice AS TGT
USING (SELECT * FROM @dt WHERE CustomerId IS NOT NULL) AS SRC
ON 1 = 0 -- Never match
WHEN NOT MATCHED THEN
INSERT (customerId, deviceId, deviceBuyDate, devicePrice)
VALUES (SRC.customerId, SRC.deviceId, SRC.deviceBuyDate, SRC.devicePrice)
OUTPUT SRC.customerId, SRC.filterId, INSERTED.customerDeviceId, SRC.filterChangeDate
INTO @FilterChangeData
;
INSERT INTO FilterChange (customerId, filterId, customerDeviceId, filterChangeDate)
SELECT customerId, filterId, customerDeviceId, filterChangeDate
FROM @FilterChangeData
END
Run Code Online (Sandbox Code Playgroud)
给定以下@dt源数据:
| 客户ID | 设备ID | 设备购买日期 | 设备价格 | 过滤器ID | 过滤器更改日期 |
|---|---|---|---|---|---|
| 11 | 111 | 2023-01-01 | 111.1100 | 1111 | 2023-02-01 |
| 22 | 222 | 2023-01-02 | 222.2200 | 2222 | 2023-02-02 |
| 33 | 第333章 | 2023-01-03 | 333.3300 | 3333 | 2023-02-03 |
| 11 | 222 | 2023-01-04 | 333.3300 | 1111 | 2023-02-04 |
以下内容被插入到 CustomerDevice 中:
| 客户设备ID | 客户ID | 设备ID | 设备购买日期 | 设备价格 |
|---|---|---|---|---|
| 1 | 11 | 111 | 2023-01-01 | 111.1100 |
| 2 | 22 | 222 | 2023-01-02 | 222.2200 |
| 3 | 33 | 第333章 | 2023-01-03 | 333.3300 |
| 4 | 11 | 222 | 2023-01-04 | 333.3300 |
以下内容被插入到 FilterChange 中:
| 客户ID | 过滤器ID | 客户设备ID | 过滤器更改日期 |
|---|---|---|---|
| 11 | 1111 | 1 | 2023-02-01 |
| 22 | 2222 | 2 | 2023-02-02 |
| 33 | 3333 | 3 | 2023-02-03 |
| 11 | 1111 | 4 | 2023-02-04 |
请参阅此 db<>fiddle。