You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

避免PRIMARY KEY约束冲突需用Partition还是Distinct?仅更新指定ClientID

问题场景

现有表a_test1中,ProjectID=103的记录如下:

103 2
103 3

执行更新操作时触发主键冲突错误:

Violation of PRIMARY KEY constraint 'PK__GC_1234'. Cannot insert duplicate key in object 'dbo.a_test1'. The duplicate key value is (103, 1)

需求:仅更新上述两行中ClientID=3的记录,忽略ClientID=2的记录,避免主键冲突。

原T-SQL代码如下:

DROP TABLE IF EXISTS a_test1

CREATE TABLE a_test1 
(
    ProjectID int NOT NULL,
    ClientID int NOT NULL,

    CONSTRAINT [PK__GC_1234] 
        PRIMARY KEY CLUSTERED (ProjectID ASC, ClientID ASC)
                WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                      IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                      ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

INSERT INTO a_test1 VALUES (101, 1) 
INSERT INTO a_test1 VALUES (101, 2) 
INSERT INTO a_test1 VALUES (103, 2) 
INSERT INTO a_test1 VALUES (103, 3) 
INSERT INTO a_test1 VALUES (104, 1)
INSERT INTO a_test1 VALUES (104, 2)
INSERT INTO a_test1 VALUES (104, 3)

DECLARE @newClientID int = 1

UPDATE a1
SET a1.ClientID = @newClientID 
FROM a_test1 a1
WHERE a1.ClientID IN ( 2, 3 ) 
  AND NOT EXISTS (SELECT 1
                  FROM a_test1 a2
                  WHERE a2.ClientID = @newClientID
                    AND a2.projectID = a1.projectID)

错误根源:原语句会把同一ProjectID下所有ClientID为2、3的记录都改为1,导致同一ProjectID下出现多条(ProjectID, 1),触发联合主键冲突。

解决思路与代码

核心逻辑是每个ProjectID下仅选择一条符合条件的记录(即该分组内ClientID最大的那条)进行更新,以下两种方案均可实现:

方案1:使用ROW_NUMBER()窗口函数

通过ROW_NUMBER()按ProjectID分区、ClientID降序排序,筛选出每个分组内排序第一的记录(即该ProjectID下ClientID最大的条目),再结合原有的NOT EXISTS条件避免与已存在的(ProjectID,1)冲突:

DECLARE @newClientID int = 1

WITH TargetRecords AS (
    SELECT 
        ProjectID, 
        ClientID,
        -- 按ProjectID分组,ClientID降序排列,取每组第一条
        ROW_NUMBER() OVER (PARTITION BY ProjectID ORDER BY ClientID DESC) AS RowNum
    FROM a_test1
    WHERE ClientID IN (2, 3)
)
UPDATE a1
SET a1.ClientID = @newClientID
FROM a_test1 a1
JOIN TargetRecords tr ON a1.ProjectID = tr.ProjectID AND a1.ClientID = tr.ClientID
WHERE tr.RowNum = 1
  AND NOT EXISTS (
        SELECT 1
        FROM a_test1 a2
        WHERE a2.ProjectID = a1.ProjectID AND a2.ClientID = @newClientID
    )

方案2:使用MAX()聚合函数筛选

通过分组聚合找到每个ProjectID下最大的ClientID,再匹配到具体记录进行更新:

DECLARE @newClientID int = 1

WITH MaxClientPerProject AS (
    SELECT ProjectID, MAX(ClientID) AS MaxClientID
    FROM a_test1
    WHERE ClientID IN (2, 3)
    GROUP BY ProjectID
)
UPDATE a1
SET a1.ClientID = @newClientID
FROM a_test1 a1
JOIN MaxClientPerProject mc ON a1.ProjectID = mc.ProjectID AND a1.ClientID = mc.MaxClientID
WHERE NOT EXISTS (
        SELECT 1
        FROM a_test1 a2
        WHERE a2.ProjectID = a1.ProjectID AND a2.ClientID = @newClientID
    )

效果说明

两种方案都会仅更新每个ProjectID下ClientID最大的那条记录(比如103对应的ClientID=3),不会同时修改ClientID=2的条目,因此不会生成重复的(ProjectID,1)主键值,彻底避免冲突。


内容的提问来源于stack exchange,提问作者Kung Fu Ninja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 04:22:34