如果行违反主键,则插入错误 table

Insert into error table if the rows violates primary key

我有这个 table:

CREATE TABLE TEST 
(
    ID INT NOT NULL,
    C_status INT NOT NULL,
    SS VARCHAR(10),

    CONSTRAINT [PK_TBL] 
        PRIMARY KEY CLUSTERED ([ID] ASC, [C_status ] ASC, [SS ] ASC)
)

现在我正在尝试使用

向这个table中插入一些值
INSERT INTO SELECT ...

数据中会有重复项。如何仅在一个 table 中插入唯一值并在另一个 table 中插入重复值。例如,如果我执行以下

INSERT INTO TEST
SELECT '1','90','PARIS'
UNION ALL
SELECT '1','90','PARIS'
UNION ALL
SELECT '2','90','PARIS'

我想在 TEST 中插入 1st 行和 3rd 行,在 TEST_ERROR 中插入 2nd row 行。 SQL 查询是否可行。我的预期输出是

TEST

ID C_STATUS SS
1 90 PARIS
2 90 PARIS

TEST_ERROR

ID C_STATUS SS
1 90 PARIS

我试过类似下面的方法,但显然没有用

BEGIN TRY
insert into test
SELECT '1','90','PARIS'
UNION ALL
SELECT '1','90','PARIS'
UNION ALL
SELECT '2','90','PARIS'
END TRY
BEGIN CATCH
insert into test
.........
END CATCH

批量插入时,是全有或全无操作。您不能专门将错误行发送到错误文件。如果你想在行级别做,你必须有 CURSOR 来发送错误行。

但是,您可以应用 ROW_NUMBER() 并过滤重复数据并发送至错误 table。

--duplicate data 
;with cte_alldata(id, c_status, ss) as
(
SELECT '1','90','PARIS'
UNION ALL
SELECT '1','90','PARIS'
UNION ALL
SELECT '2','90','PARIS'
)
, cte_distinctdata as
(
SELECT *, row_number() over(partition by id, c_status, ss order by id) as rnk
FROM cte_alldata
)
INSERT INTO Error_Table
SELECT id, c_status, ss from cte_distinctdata where rnk >1
id c_status ss
1 90 PARIS

您可以在 TEST 上创建 INSTEAD OF INSERT 触发器。使用 ROW_NUMBER() window 函数来识别那些重复项,并且仅将其中一行插入 TEST 并将这些重复项插入 TEST_ERROR

CREATE TRIGGER TR_TEST 
ON TEST
INSTEAD OF INSERT
AS
BEGIN
    INSERT INTO TEST (ID, C_status, SS)
    SELECT  ID, C_status, SS
    FROM
    (
        SELECT  ID, C_status, SS
                RN = ROW_NUMBER() OVER(PARTITION BY ID, C_status, SS ORDER BY ID)
        FROM    INSERTED
    ) i
    WHERE   i.RN    = 1

    INSERT INTO TEST_ERROR (ID, C_status, SS)
    SELECT  ID, C_status, SS
    FROM
    (
        SELECT  ID, C_status, SS, 
                RN = ROW_NUMBER() OVER(PARTITION BY ID, C_status, SS ORDER BY ID)
        FROM    INSERTED
    ) i
    WHERE   i.RN    > 1
END