Equivalent of MySQL ON DUPLICATE KEY UPDATE in Sql Server

后端 未结 5 1108
走了就别回头了
走了就别回头了 2020-12-03 04:41

I am trying to find an equivalent of the following MySql query in Sql Server (2012)?

INSERT INTO mytable (COL_A, COL_B, COL_C, COL_D)
VALUES ( \'VAL_A\',\'VA         


        
5条回答
  •  Happy的楠姐
    2020-12-03 05:24

    You can simulate a near identitical behaviour using an INSTEAD OF TRIGGER:

    CREATE TRIGGER tMyTable ON MyTable
    INSTEAD OF INSERT
    AS
        BEGIN
            SET NOCOUNT ON;
    
            SELECT i.COL_A, i.COL_B, i.COL_C, i.COL_D, 
                CASE WHEN mt.COL_D IS NULL THEN 0 ELSE 1 END AS KeyExists 
                INTO #tmpMyTable
                FROM INSERTED i
                LEFT JOIN MyTable mt
                ON i.COL_D = mt.COL_D;
    
            INSERT INTO MyTable(COL_A, COL_B, COL_C, COL_D)
                SELECT COL_A, COL_B, COL_C, COL_D
                    FROM #tmpMyTable
                    WHERE KeyExists = 0;
    
            UPDATE mt
                SET mt.COL_A = t.COL_A, mt.COL_B = t.COL_B, mt.COL_C = t.COL_C
                FROM MyTable mt 
                    INNER JOIN #tmpMyTable t 
                    ON mt.COL_D = t.COL_D AND t.KeyExists = 1;
        END;
    

    SqlFiddle here

    How it works

    • We first project a list of all rows being attempted to be inserted into the table into a #temp table, noting which of those ARE already in the underlying table via a LEFT OUTER JOIN on the key column(s) COL_D which detect the duplication criteria.
    • We then need to repeat the actual work of an INSERT statement, by inserting those rows which are not already in the table (because of the INSTEAD OF, we have removed the responsibility of insertion from the engine and need to do this ourselves).
    • Finally, we update all non-key columns in the matched rows with the newly 'inserted' data.

    Salient Points

    • It works under the covers, i.e. any insert into the table while the trigger is enabled will be subject to the trigger (e.g. Application ORM, other stored procedures etc). The caller will generally be UNAWARE that the INSTEAD OF trigger is in place.
    • There must be a key of sorts to detect the duplicate criterion (natural or surrogate). I've assumed COL_D in this case, but it could be a composite key. (Key but cannot be IDENTITY for obvious reasons, since the client wouldn't be inserting an Identity)
    • The trigger works for both single and multiple row INSERTS

    NB

    • The standard disclaimers with triggers apply, and more so with INSTEAD OF triggers - as this can cause surprising changes in observable behaviour of Sql Server, such as this - even well intended INSTEAD OF triggers can cause hours of wasted effort and frustration for developers and DBA's who are not aware of their presence on your table.
    • This will affect ALL inserts into the table. Not just yours.

提交回复
热议问题