【问题标题】:Primary Key Insert violation sometimes happening, but statement checks this有时会发生主键插入违规,但语句会检查这一点
【发布时间】:2021-02-03 11:26:29
【问题描述】:

也许有人知道我可以检查什么:

      using (var cnn = new SqlConnection(connection))
      {
        cnn.Open();
        using (var cmd = new SqlCommand())
        {
          cmd.Connection = cnn;
          cmd.CommandText = "IF EXISTS (SELECT * FROM kruserprofile WHERE lactorid=@1 AND strname=@2) " +
                            "  UPDATE kruserprofile SET txtvalue=@3 WHERE lactorid=@1 AND strname=@2 " +
                            "ELSE " +
                            "  INSERT INTO kruserprofile (lactorid, strname, txtvalue) " +
                            "  VALUES (@1, @2, @3)";
          cmd.CommandTimeout = 120;
          cmd.Parameters.AddWithValue("@1", actorId);
          cmd.Parameters.AddWithValue("@2", ident);
          cmd.Parameters.AddWithValue("@3", _mXml.ToString());
          cmd.ExecuteNonQuery();
        }
        cnn.Close();
      }

正如您在这段代码中看到的那样,我会检查记录是否存在并更新或插入。 这在 SQL Server 系统上运行良好。 在 Azure SQL 上,我有时会这样做但无法重现错误: Violation on PRIMARY KEY...,其中约束位于 lactoridstrname

表:

CREATE TABLE dbo.kruserprofile (
    lactorid int NOT NULL,
    strname nvarchar(254) NOT NULL,
    txtvalue nvarchar(max) NULL
);
GO

ALTER TABLE dbo.kruserprofile ADD CONSTRAINT PK__kruserpr__6E092EE804688C07 PRIMARY KEY (lactorid, strname);
GO

所以我没有找到任何原因,但有时似乎EXISTSreturns false 所以它尝试插入然后失败。知道我可以检查什么吗?

【问题讨论】:

标签: sql-server azure-sql-database


【解决方案1】:

更新:

解决方案 1:

我们也找到了解决方案here


解决方案 2:

我创建了一个关于在 Azure SQL 中使用 MERGE 的测试。

  1. 创建表:
CREATE TABLE dbo.kruserprofile (
    lactorid int NOT NULL,
    strname nvarchar(254) NOT NULL,
    txtvalue nvarchar(max) NULL
);
GO

ALTER TABLE dbo.kruserprofile ADD CONSTRAINT PK__kruserpr__6E092EE804688C07 PRIMARY KEY (lactorid, strname);
GO
  1. 创建一个名为dbo.kruserprofile_type的表值参数,它将在我的存储过程中使用:
create TYPE dbo.kruserprofile_type AS TABLE(
    lactorid int NOT NULL,
    strname nvarchar(254) NOT NULL,
    txtvalue nvarchar(max)
)
GO
  1. 创建一个存储过程,它将合并相同的记录并根据主键插入新记录:
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

create PROCEDURE [dbo].[spUpsertKruserprofile]

@profile dbo.kruserprofile_type READONLY

AS

BEGIN

    MERGE dbo.kruserprofile AS target_sqldb

    USING @profile AS source_tblstg

    ON (target_sqldb.lactorid = source_tblstg.lactorid and target_sqldb.strname = source_tblstg.strname )

    WHEN MATCHED THEN

    UPDATE SET

    txtvalue = source_tblstg.txtvalue


    WHEN NOT MATCHED THEN

    INSERT (

        lactorid,

        strname,

        txtvalue

    )

    VALUES (

        source_tblstg.lactorid,

        source_tblstg.strname,

        source_tblstg.txtvalue
    );

END
GO
  1. 之后,我们可以通过以下代码执行存储过程:
DECLARE @profileVar AS dbo.kruserprofile_type;
/* Add data to the table variable. */
INSERT INTO @profileVar (lactorid, strname, txtvalue) values (1, 'tom','wednesday');
exec  [dbo].[spUpsertKruserprofile] @profileVar

就是这样。

【讨论】:

  • 谢谢,我会在您的解决方案有效时投票。但即使我不会使用它,因为如果没有真正需要它,我不想使用程序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-22
  • 2019-09-28
  • 1970-01-01
  • 2019-07-23
  • 1970-01-01
相关资源
最近更新 更多