Inserting Where values don't Exist

  • Hi ,

    I'm currently trying to create a insert statement that will only insert values if the value doesn't not exist

    which in my case is the [name] column, so if the name already exists do not insert.

    Currently ive mocked up something like this, but this doesn't allow me to run script at once, its expecting the values to be passed through manually... with the @name and @val

    declare

    @name AS VARCHAR(500),

    @val AS VARCHAR(500)

    set @name = 'Manual'

    SET @val = '-53'

    IF EXISTS(SELECT 'True' FROM u_apppreferences WHERE name = @name)

    BEGIN

    --Record Exists

    SELECT 'This record already exists!'

    END

    ELSE

    BEGIN

    --This means the record isn't in there already, let's go ahead and add it

    SELECT 'Record Added'

    INSERT into u_apppreferences(name, Val) VALUES(@name, @val)

    END

    the goal is to remove the parameters and just let the script run itself and pick up where the name is missing....

    any ideas?

  • INSERT into u_apppreferences(name, Val)

    SELECT @name, @val

    WHERE NOT EXISTS (SELECT 1 FROM u_apppreferences WHERE name = @name)

    as your current one is prone to concurrency problems (will cause duplicates under load)

    http://source.entelect.co.za/why-is-this-upsert-code-broken

    the goal is to remove the parameters and just let the script run itself and pick up where the name is missing....

    Where would the script get the names it needs to check, and where would it get the values to insert?

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • the values from the other table which exists on a different database

  • In that case, instead of SELECT @name, @val WHERE, it would be

    SELECT s.name, s.val

    FROM SomeOtherDatabase.dbo.SomeOtherTable s

    WHERE NOT EXISTS (SELECT 1 FROM u_apppreferences WHERE name = s.name)

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • For key value pairs, this is typically what you want. If name exists (@@rowcount = 1), then it's value is updated. If name doesn't exist (@@rowcount = 0), then it is inserted in a subsequent statement.

    update u_apppreferences

    set Val = @val

    where name = @name;

    if @@rowcount = 0

    insert into u_apppreferences ( name, Val )

    values ( @name, @val );

    Collisions can be mitigated by implementing ignore_dup_key option on the primary key.

    create table u_apppreferences

    (

    name varchar(20) not null

    primary key with (ignore_dup_key = on),

    Val varchar(20) not null

    );

    In any event, you'll most likely want name as the primary key.

    "Do not seek to follow in the footsteps of the wise. Instead, seek what they sought." - Matsuo Basho

  • USE dba

    GO

    CREATE TABLE u_apppreferences (

    NAME VARCHAR(500)

    ,val VARCHAR(500)

    );

    DECLARE @name AS VARCHAR(500),@VAL AS VARCHAR(500);

    SET @name = 'Manual';

    SET @val = '-53';

    IF NOT EXISTS (

    SELECT 1

    FROM u_apppreferences

    WHERE NAME = @name

    AND val = @val

    )

    BEGIN

    INSERT INTO u_apppreferences (NAME,Val)

    VALUES (@name,@VAL)

    END

    ELSE

    PRINT 'Name and Val exists';

  • sunita2912 (7/6/2016)


    IF NOT EXISTS (

    SELECT 1

    FROM u_apppreferences

    WHERE NAME = @name

    AND val = @val

    )

    BEGIN

    INSERT INTO u_apppreferences (NAME,Val)

    VALUES (@name,@VAL)

    END

    ELSE

    PRINT 'Name and Val exists';

    As with the OP's original code, that is prone to concurrency problems (will cause duplicates under load)

    http://source.entelect.co.za/why-is-this-upsert-code-broken

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • Eric M Russell (7/6/2016)


    For key value pairs, this is typically what you want. If name exists (@@rowcount = 1), then it's value is updated. If name doesn't exist (@@rowcount = 0), then it is inserted in a subsequent statement.

    update u_apppreferences

    set Val = @val

    where name = @name;

    if @@rowcount = 0

    insert into u_apppreferences ( name, Val )

    values ( @name, @val );

    Collisions can be mitigated by implementing ignore_dup_key option on the primary key.

    create table u_apppreferences

    (

    name varchar(20) not null

    primary key with (ignore_dup_key = on),

    Val varchar(20) not null

    );

    In any event, you'll most likely want name as the primary key.

    I'm just wondering if your code might also contain the same sort of race condition pointed out by Gilamonster?

  • patrickmcginnis59 10839 (7/7/2016)


    I'm just wondering if your code might also contain the same sort of race condition pointed out by Gilamonster?

    Yes it can.

    Two sessions start, one runs the update, it affects no rows. Second one runs the update as soon as it can get locks, it also affects no rows, first one inserts, second one inserts.

    Adding the ignore_dup_key will ensure no errors are thrown, but still two different sessions will think they inserted a row.

    With that structure, should be enough to just wrap the two in a transaction and switch the isolation level to serialisable for the duration. Locking hints shouldn't be necessary

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • Gail Shaw - As with the OP's original code, that is prone to concurrency problems (will cause duplicates under load)

    http://source.entelect.co.za/why-is-this-upsert-code-broken

    Sipping from the hydrant ... I doubt I would have been able to find this excellent article of yours in the T-SQL ocean. It was my luck you pointed to it while answering an (apparently) simple INSERT question.

  • You might want to look at using a global table for this work.

Viewing 11 posts - 1 through 10 (of 10 total)

You must be logged in to reply to this topic. Login to reply