MSSQL C#查询仅在值唯一的情况下添加行

时间:2018-07-12 11:08:45

标签: sql-server tsql upsert

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

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

2 个答案:

答案 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块。