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

如何创建SQL Server存储过程:跳过已存在数据仅插入新数据

解决SQL Server存储过程跳过重复数据的问题

我来帮你搞定这个问题!你需要实现的是仅插入目标表中不存在的记录,避免重复数据。核心思路是在插入前先检查Prezente表里是否已经存在符合条件的记录,下面给你几种SQL Server中常用且靠谱的实现方式:

方法1:使用NOT EXISTS(推荐,可读性强)

这是最常用的方式,逻辑清晰,性能也不错。我们需要先确定判断重复的唯一字段组合(比如员工ID、日期、工时类型,这三个组合应该是唯一的,避免同一天同一员工同一工时类型重复插入),然后在SELECT语句后添加NOT EXISTS子句过滤已存在的记录。

修改后的存储过程代码如下:

ALTER PROCEDURE [dbo].[PrezentaImport2] 
    @CodAngajat INT, 
    @Data DATE, 
    @CodTipOra VARCHAR(50), 
    @R1DAL NUMERIC(10,1), 
    @R1ALL NUMERIC(10,1), 
    @R1TOT NUMERIC(10,1), 
    @IdUtilizatorAdaugare INT 
AS
INSERT INTO Prezente (
    IdAngajat, 
    IdTipPostDeLucru, 
    IdPostDeLucru, 
    IdDepartament, 
    IdEchipa, 
    IdLinie, 
    Data, 
    IdTipOra, 
    R1DAL, 
    R1ALL, 
    R1TOT, 
    IdUtilizatorAdaugare, 
    DataAdaugare
)
SELECT 
    Angajati.Id, 
    Angajati.IdTipPostDeLucru, 
    Angajati.IdPostDeLucru, 
    Angajati.IdDepartament, 
    Angajati.IdEchipa, 
    Angajati.IdLinie, 
    @Data, 
    TipuriOre.Id, 
    @R1DAL, 
    @R1ALL, 
    @R1TOT, 
    @IdUtilizatorAdaugare, 
    GETDATE()
FROM Angajati 
INNER JOIN TipuriOre ON TipuriOre.CodTipOra = @CodTipOra 
WHERE Angajati.CodAngajat = @CodAngajat
-- 关键:过滤已存在的记录
AND NOT EXISTS (
    SELECT 1 FROM Prezente p
    WHERE p.IdAngajat = Angajati.Id
      AND p.Data = @Data
      AND p.IdTipOra = TipuriOre.Id
)

方法2:使用MERGE语句(适合需同时处理插入/更新的场景)

如果以后你的需求扩展为“存在则更新,不存在则插入”,MERGE语句会更合适。即使现在只需要插入,也可以用它来实现:

ALTER PROCEDURE [dbo].[PrezentaImport2] 
    @CodAngajat INT, 
    @Data DATE, 
    @CodTipOra VARCHAR(50), 
    @R1DAL NUMERIC(10,1), 
    @R1ALL NUMERIC(10,1), 
    @R1TOT NUMERIC(10,1), 
    @IdUtilizatorAdaugare INT 
AS
MERGE INTO Prezente AS Target
USING (
    SELECT 
        Angajati.Id, 
        Angajati.IdTipPostDeLucru, 
        Angajati.IdPostDeLucru, 
        Angajati.IdDepartament, 
        Angajati.IdEchipa, 
        Angajati.IdLinie, 
        @Data AS Data, 
        TipuriOre.Id AS IdTipOra, 
        @R1DAL, 
        @R1ALL, 
        @R1TOT, 
        @IdUtilizatorAdaugare, 
        GETDATE() AS DataAdaugare
    FROM Angajati 
    INNER JOIN TipuriOre ON TipuriOre.CodTipOra = @CodTipOra 
    WHERE Angajati.CodAngajat = @CodAngajat
) AS Source
ON Target.IdAngajat = Source.Id
   AND Target.Data = Source.Data
   AND Target.IdTipOra = Source.IdTipOra
-- 当目标表中无匹配记录时插入
WHEN NOT MATCHED THEN
INSERT (
    IdAngajat, 
    IdTipPostDeLucru, 
    IdPostDeLucru, 
    IdDepartament, 
    IdEchipa, 
    IdLinie, 
    Data, 
    IdTipOra, 
    R1DAL, 
    R1ALL, 
    R1TOT, 
    IdUtilizatorAdaugare, 
    DataAdaugare
)
VALUES (
    Source.Id, 
    Source.IdTipPostDeLucru, 
    Source.IdPostDeLucru, 
    Source.IdDepartament, 
    Source.IdEchipa, 
    Source.IdLinie, 
    Source.Data, 
    Source.IdTipOra, 
    Source.R1DAL, 
    Source.R1ALL, 
    Source.R1TOT, 
    Source.IdUtilizatorAdaugare, 
    Source.DataAdaugare
);

方法3:使用LEFT JOIN + WHERE IS NULL

和NOT EXISTS逻辑类似,通过左连接判断目标表中无匹配记录:

ALTER PROCEDURE [dbo].[PrezentaImport2] 
    @CodAngajat INT, 
    @Data DATE, 
    @CodTipOra VARCHAR(50), 
    @R1DAL NUMERIC(10,1), 
    @R1ALL NUMERIC(10,1), 
    @R1TOT NUMERIC(10,1), 
    @IdUtilizatorAdaugare INT 
AS
INSERT INTO Prezente (
    IdAngajat, 
    IdTipPostDeLucru, 
    IdPostDeLucru, 
    IdDepartament, 
    IdEchipa, 
    IdLinie, 
    Data, 
    IdTipOra, 
    R1DAL, 
    R1ALL, 
    R1TOT, 
    IdUtilizatorAdaugare, 
    DataAdaugare
)
SELECT 
    Angajati.Id, 
    Angajati.IdTipPostDeLucru, 
    Angajati.IdPostDeLucru, 
    Angajati.IdDepartament, 
    Angajati.IdEchipa, 
    Angajati.IdLinie, 
    @Data, 
    TipuriOre.Id, 
    @R1DAL, 
    @R1ALL, 
    @R1TOT, 
    @IdUtilizatorAdaugare, 
    GETDATE()
FROM Angajati 
INNER JOIN TipuriOre ON TipuriOre.CodTipOra = @CodTipOra 
LEFT JOIN Prezente p 
    ON p.IdAngajat = Angajati.Id
    AND p.Data = @Data
    AND p.IdTipOra = TipuriOre.Id
WHERE Angajati.CodAngajat = @CodAngajat
  AND p.IdAngajat IS NULL -- 目标表中无匹配记录

额外建议

为了从根源上避免重复数据,建议在Prezente表上创建唯一约束或唯一索引,比如:

CREATE UNIQUE NONCLUSTERED INDEX IX_Prezente_Angajat_Data_TipOra
ON Prezente (IdAngajat, Data, IdTipOra);

这样即使存储过程的逻辑有疏漏,数据库也会直接阻止重复数据插入,同时还能提升查询判断重复的性能。

内容的提问来源于stack exchange,提问作者Peki Peki

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:08:20