MSSQL C# 查询仅在值唯一时添加行

MSSQL C# query Only add row if value is unique

我有一个简单的 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 条重复记录。

是否有更好的方法来确保永远不会创建具有相同设备名称的两行?

Is there a better way of ensuring that two rows with the same device name are never created ?

是,让数据库使用唯一的 constraint/index:

确保数据完整性
alter table t add constraint unq_t_deviceName unique (deviceName);

您需要调整代码以捕获 insert 上的错误。如果这是 T-SQL 代码,您可以使用 try/catch 块。

问题出在您的更新语句上 - 您正在更新两列,而不是使用 Where 子句中的 DeviceName 列。它应该是这样的:

UPDATE HeartBeat
SET LastConnect = 'DATETIMEDATA'
WHERE DeviceName = 'DEVICENAMEDATA'

话虽如此,您可能应该将 DeviceName 用作 table 的 primary key,这将使其不可能具有多个值。

此外,关于 "upsert" 的主题,您应该阅读 Dan Guzman 的 blog post 关于如何在 SQL 服务器中避免 "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