Only inserting a row if it's not already there

后端 未结 6 913
天涯浪人
天涯浪人 2020-11-22 01:17

I had always used something similar to the following to achieve it:

INSERT INTO TheTable
SELECT
    @primaryKey,
    @value1,
    @value2
WHERE
    NOT EXIST         


        
相关标签:
6条回答
  • 2020-11-22 01:52

    I've done a similar operation in past using a different method. First, I declare a variable to hold the primary key. Then I populate that variable with the output of a select statement which looks for a record with those values. Then I do and IF statement. If primary key is null, then do insert, else, return some error code.

         DECLARE @existing varchar(10)
        SET @existing = (SELECT primaryKey FROM TABLE WHERE param1field = @param1 AND param2field = @param2)
    
        IF @existing is not null
        BEGIN
        INSERT INTO Table(param1Field, param2Field) VALUES(param1, param2)
        END
        ELSE
        Return 0
    END
    
    0 讨论(0)
  • 2020-11-22 02:01

    Firstly, huge shout out to our man @gbn for his contributions to the community. Can't even begin to explain how often I find myself following his advice.

    Anyway, enough fanboy-ing.

    To add slightly to his answer, perhaps "enhance" it. For those, like me, left feeling unsettled with what to do in the <> 2627 scenario (and no an empty CATCH is not an option). I found this little nugget from technet.

        BEGIN TRY
           INSERT etc
        END TRY
        BEGIN CATCH
            IF ERROR_NUMBER() <> 2627
              BEGIN
                    DECLARE @ErrorMessage NVARCHAR(4000);
                    DECLARE @ErrorSeverity INT;
                    DECLARE @ErrorState INT;
    
                    SELECT @ErrorMessage = ERROR_MESSAGE(),
                    @ErrorSeverity = ERROR_SEVERITY(),
                    @ErrorState = ERROR_STATE();
    
                        RAISERROR (
                            @ErrorMessage,
                            @ErrorSeverity,
                            @ErrorState
                        );
              END
        END CATCH
    
    0 讨论(0)
  • 2020-11-22 02:09

    I added HOLDLOCK which wasn't present originally. Please disregard the version without this hint.

    As far as I'm concerned, this should be enough:

    INSERT INTO TheTable 
    SELECT 
        @primaryKey, 
        @value1, 
        @value2 
    WHERE 
        NOT EXISTS 
        (SELECT 0
         FROM TheTable WITH (UPDLOCK, HOLDLOCK)
         WHERE PrimaryKey = @primaryKey) 
    

    Also, if you actually want to update a row if it exists and insert if it doesn't, you might find this question useful.

    0 讨论(0)
  • 2020-11-22 02:13

    What about the "JFDI" pattern?

    BEGIN TRY
       INSERT etc
    END TRY
    BEGIN CATCH
        IF ERROR_NUMBER() <> 2627
          RAISERROR etc
    END CATCH
    

    Seriously, this is quickest and the most concurrent without locks, especially at high volumes. What if the UPDLOCK is escalated and the whole table is locked?

    Read lesson 4:

    Lesson 4: When developing the upsert proc prior to tuning the indexes, I first trusted that the If Exists(Select…) line would fire for any item and would prohibit duplicates. Nada. In a short time there were thousands of duplicates because the same item would hit the upsert at the same millisecond and both transactions would see a not exists and perform the insert. After much testing the solution was to use the unique index, catch the error, and retry allowing the transaction to see the row and perform an update instead an insert.

    0 讨论(0)
  • 2020-11-22 02:13

    I don't know if this is the "official" way, but you could try the INSERT, and fall back to UPDATE if it fails.

    0 讨论(0)
  • 2020-11-22 02:16

    You could use MERGE:

    MERGE INTO Target
    USING (VALUES (@primaryKey, @value1, @value2)) Source (key, value1, value2)
    ON Target.key = Source.key
    WHEN MATCHED THEN
        UPDATE SET value1 = Source.value1, value2 = Source.value2
    WHEN NOT MATCHED BY TARGET THEN
        INSERT (Name, ReasonType) VALUES (@primaryKey, @value1, @value2)
    
    0 讨论(0)
提交回复
热议问题