我有一个简单的c#应用程序,它使用以下内容写入数据库。
IF EXISTS (SELECT * FROM Table WHERE deviceName='deviceNAMEDATA')
UPDATE HeartBeat
SET DeviceName = 'DEVICENAMEDATA',
LastConnect = 'DATETIMEDATA'
ELSE
INSERT INTO HeartBeat
VALUES('DeviceNAMEDATA', 'DATETIMEDATA')
使用字符串生成器将DEVICENAMEDATA和DATETIMEDATA替换为设备名称和时间。
我让它运行了一个小时,一切似乎都正常了,但是我并没有得到任何重复的记录,但是让它运行24小时后,数据库中大约有20条重复记录。
是否有更好的方法来确保不会创建具有相同设备名称的两行?
答案 0 :(得分:1)
问题在于您的更新语句-您正在更新两个列,而不是使用DeviceName
子句中的Where
列。它应该看起来像这样:
UPDATE HeartBeat
SET LastConnect = 'DATETIMEDATA'
WHERE DeviceName = 'DEVICENAMEDATA'
话虽如此,您应该将DeviceName
用作表的primary key,这将使其不可能具有多个值。
此外,在讨论“ upsert”时,您应该阅读Dan Guzman的blog post,有关如何避免SQL Server中“ upsert”中的竞争条件。
还有一件事情-您应该始终在插入语句中指定列列表。
这是我的写法:
SET NOCOUNT, XACT_ABORT ON
BEGIN TRY
BEGIN TRANSACTION
IF EXISTS
(
SELECT *
FROM Table
WITH (UPDLOCK, HOLDLOCK)
WHERE deviceName='deviceNAMEDATA'
)
UPDATE HeartBeat
SET LastConnect = 'DATETIMEDATA'
WHERE DeviceName = 'DEVICENAMEDATA'
ELSE
INSERT INTO HeartBeat (DeviceName, LastConnect)
VALUES('DeviceNAMEDATA', 'DATETIMEDATA')
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION
END CATCH
答案 1 :(得分:0)
是否有更好的方法来确保不会创建具有相同设备名称的两行?
是的,让数据库使用唯一的约束/索引来确保数据完整性:
alter table t add constraint unq_t_deviceName unique (deviceName);
您需要调整代码以捕获insert
上的错误。如果这是T-SQL代码,则可以使用try
/ catch
块。