INSERT VALUES WHERE NOT EXISTS

后端 未结 5 1495
我寻月下人不归
我寻月下人不归 2020-12-03 04:17

OK so I\'m trying to improve my asp data entry page to ensure that the entry going into my data table is unique.

So in this table I have SoftwareName and SoftwareTyp

5条回答
  •  夕颜
    夕颜 (楼主)
    2020-12-03 05:21

    This isn't an answer. I just want to show that IF NOT EXISTS(...) INSERT method isn't safe. You have to execute first Session #1 and then Session #2. After v #2 you will see that without an UNIQUE index you could get duplicate pairs (SoftwareName,SoftwareSystemType). Delay from session #1 is used to give you enough time to execute the second script (session #2). You could reduce this delay.

    Session #1 (SSMS > New Query > F5 (Execute))

    CREATE DATABASE DemoEXISTS;
    GO
    USE DemoEXISTS;
    GO
    CREATE TABLE dbo.Software(
        SoftwareID INT PRIMARY KEY,
        SoftwareName NCHAR(400) NOT NULL,  
        SoftwareSystemType NVARCHAR(50) NOT NULL
    );
    GO
    
    INSERT INTO dbo.Software(SoftwareID,SoftwareName,SoftwareSystemType)
    VALUES (1,'Dynamics AX 2009','ERP');
    INSERT INTO dbo.Software(SoftwareID,SoftwareName,SoftwareSystemType)
    VALUES (2,'Dynamics NAV 2009','SCM');
    INSERT INTO dbo.Software(SoftwareID,SoftwareName,SoftwareSystemType)
    VALUES (3,'Dynamics CRM 2011','CRM');
    INSERT INTO dbo.Software(SoftwareID,SoftwareName,SoftwareSystemType)
    VALUES (4,'Dynamics CRM 2013','CRM');
    INSERT INTO dbo.Software(SoftwareID,SoftwareName,SoftwareSystemType)
    VALUES (5,'Dynamics CRM 2015','CRM');
    GO
    /*
    CREATE UNIQUE INDEX IUN_Software_SoftwareName_SoftareSystemType
    ON dbo.Software(SoftwareName,SoftwareSystemType);
    GO
    */
    
    -- Session #1
    BEGIN TRANSACTION;
        UPDATE  dbo.Software
        SET     SoftwareName='Dynamics CRM',
                SoftwareSystemType='CRM'    
        WHERE   SoftwareID=5;
    
        WAITFOR DELAY '00:00:15' -- 15 seconds delay; you have less than 15 seconds to switch SSMS window to session #2
    
        UPDATE  dbo.Software
        SET     SoftwareName='Dynamics AX',
                SoftwareSystemType='ERP'
        WHERE   SoftwareID=1;
    COMMIT
    --ROLLBACK
    PRINT 'Session #1 results:';
    SELECT *
    FROM dbo.Software;
    

    Session #2 (SSMS > New Query > F5 (Execute))

    USE DemoEXISTS;
    GO
    -- Session #2
    DECLARE 
        @SoftwareName NVARCHAR(100),  
        @SoftwareSystemType NVARCHAR(50);
    SELECT
        @SoftwareName=N'Dynamics AX',
        @SoftwareSystemType=N'ERP';
    
    PRINT 'Session #2 results:';
    IF NOT EXISTS(SELECT *
        FROM dbo.Software s
        WHERE s.SoftwareName=@SoftwareName 
        AND s.SoftwareSystemType=@SoftwareSystemType)
    BEGIN
        PRINT 'Session #2: INSERT';
    
        INSERT INTO dbo.Software(SoftwareID,SoftwareName,SoftwareSystemType)
        VALUES (6,@SoftwareName,@SoftwareSystemType);
    END 
    PRINT 'Session #2: FINISH';
    SELECT  * 
    FROM    dbo.Software;
    

    Results:

    Session #1 results:
    SoftwareID  SoftwareName      SoftwareSystemType
    ----------- ----------------- ------------------
    1           Dynamics AX       ERP
    2           Dynamics NAV 2009 SCM
    3           Dynamics CRM 2011 CRM
    4           Dynamics CRM 2013 CRM
    5           Dynamics CRM      CRM
    
    Session #2 results:
    Session #2: INSERT
    Session #2: FINISH
    SoftwareID  SoftwareName      SoftwareSystemType
    ----------- ----------------- ------------------
    1           Dynamics AX       ERP <-- duplicate (row updated by session #1)
    2           Dynamics NAV 2009 SCM
    3           Dynamics CRM 2011 CRM
    4           Dynamics CRM 2013 CRM
    5           Dynamics CRM      CRM
    6           Dynamics AX       ERP <-- duplicate (row inserted by session #2)
    

提交回复
热议问题