【问题标题】:primary key violation even though record doesn't exist即使记录不存在,主键违规
【发布时间】:2015-11-02 15:01:27
【问题描述】:

我使用的是 SQL Server 2012。

我已经创建了一个触发器,代码如下。

虽然在我的表上运行更新查询时我收到一条错误消息“违反主键约束”,但我有点困惑。但是,在我查询表的地方,我正在更新的值在表中不存在?目录是主键列。

update myTable
set directory = 'madeup2'
where directory = 'madeup'

所以上面的查询是导致违反主键约束的原因。

但我执行下面的选择查询,我的表中没有名为 madeup2 的目录 - 没有返回记录。

select * from myTable where directory = 'madeup2'

这和我的触发器有关吗?

create trigger trDefaultPath on mytable
instead of insert, update, delete
as
begin
declare @defCountIns int
declare @retVal int
declare @permission bit

select @defCountIns = count(userName) from inserted where userName = 'Default'
select @retVal = count(HostName) from UserHostName where HostName = HOST_NAME()

-- workout permissions
if @retVal = 0 and @defCountIns > 0
    set @permission = 0
else
    set @permission = 1

begin                                           
    if @permission = 1
        begin
            update mytable
            set directory = inserted.directory,
            pathNumber = inserted.pathNumber,
            userName = inserted.userName
            from inserted;
        end
    else
        begin
            update mytable
            set directory = inserted.directory,
            pathNumber = inserted.pathNumber,
            userName = inserted.userName
            from inserted
            where inserted.username <> 'Default';
            print 'Do not have permission to update directories'
        end
end         
end

更新

感谢 cmets 指出我的触发器中的更新语句缺少 where 子句。

我不明白的一件事是我使用 where 子句执行了更新查询。在插入的表中,虽然我将只有新的“目录”值,那么如何创建 where 子句?

这仅仅是使用已删除表的情况 - 所以从 mytable 中删除该表中的记录,然后将插入表中的记录添加到 mytable 中?

【问题讨论】:

  • 您的UPDATE 语句将更新整个 表——而不仅仅是那些已修改的行。这通常不是您想要的 - 您需要在您的 Inserted 伪表和您要更新的实际基础数据表之间添加一个 JOIN
  • 哦,当然!对了,谢谢-我不想更新整个表格。如果您将评论作为答案,我将使其正确

标签: sql sql-server triggers sql-server-2012


【解决方案1】:

在您的触发器中,您的第一个 UPDATE 没有 WHERE 子句。第二个有一个 WHERE 子句,它不引用正在更新的表。

这意味着它将尝试使用插入表中的相同值更新表中的每一行。

此外,您的触发器未编码为处理影响多行的插入/更新。

【讨论】:

  • 如何调整我的触发器,使其能够处理多行受到影响?
  • 通过将插入的表连接到适当列上的“mytable”表。由于 Directory 是您的 PK,因此您可能应该加入其中。但是当代码只进行更新时,我真的不清楚为什么您希望触发器处理插入、更新和删除。
  • 我删除了处理插入和删除的代码,以使我的示例更易于阅读
【解决方案2】:

此更新语句没有where 子句。它将尝试更新表中每条记录的directory 字段。只要表中有多个记录,这将导致主键冲突。

        update mytable
        set directory = inserted.directory,
        pathNumber = inserted.pathNumber,
        userName = inserted.userName
        from inserted;

【讨论】:

    【解决方案3】:

    您的UPDATE 语句将更新整个表 - 而不仅仅是那些已修改的行。这通常不是你想要的。

    您需要在您的Inserted 伪表和您要更新的实际基础数据表之间添加一个JOIN

     if @permission = 1
     begin
         update mytable
         set directory = inserted.directory,
             pathNumber = inserted.pathNumber,
             userName = inserted.userName
         from inserted i
         inner join mytable on i.ID = mytable.ID;  -- or whatever column is your PK
        end
    

    【讨论】:

      猜你喜欢
      • 2011-05-20
      • 2011-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多