복붙노트

[SQL] NOT이 존재하는 INSERT 값

SQL

NOT이 존재하는 INSERT 값

OK 그래서 난 내 데이터 테이블에 들어가는 항목이 고유한지 확인하기 위해 내 ASP 데이터 입력 페이지를 개선하기 위해 노력하고있어.

그래서이 표에 나는 SoftwareName 및 SoftwareType 있습니다. 나는 항목 페이지가 테이블에 일치 뭐죠 (그래서 같은 제목과 유형) 다음 오류가 발생하고 데이터가 입력되지 않도록 매개 변수와 함께 삽입 쿼리를 보내는 경우 그래서 그걸 얻기 위해 노력하고있어.

이 같은:

INSERT INTO tblSoftwareTitles( 
            SoftwareName,  
            SoftwareSystemType) 
            VALUES(@SoftwareName,@SoftwareType) 
            WHERE NOT EXISTS (SELECT SoftwareName 
            FROM tblSoftwareTitles 
            WHERE Softwarename = @SoftwareName 
            AND SoftwareType = @Softwaretype)

이 구문은 중복 입력하지 않고 다른에 하나 개의 테이블에서 열을 선택하는 위대한 작품을하지만 매개 변수화 삽입 쿼리 작업 할 것 같지 않습니다 그래서. 이와 캔 사람의 도움이 나를?

편집하다:

여기에 내가 내 ASP 삽입 방법에 사용하고 코드입니다

    private void ExecuteInsert(string name, string type)
{
    //Creates a new connection using the HWM string
    using (SqlConnection HWM = new SqlConnection(GetConnectionStringHWM()))
    {
        //Creates a sql string with parameters
        string sql = " INSERT INTO tblSoftwareTitles( "
                   + " SoftwareName, " 
                   + " SoftwareSystemType) "
                   + " SELECT "
                   + " @SoftwareName, "
                   + " @SoftwareType "
                   + " WHERE   NOT EXISTS  "
                   + " ( SELECT  1 "
                   + " FROM tblSoftwareTitles "
                   + " WHERE Softwarename = @SoftwareName "
                   + " AND SoftwareSystemType = @Softwaretype); ";         

        //Opens the connection
        HWM.Open();
        try
        {
            //Creates a Sql command
            using (SqlCommand addSoftware = new SqlCommand{
                CommandType = CommandType.Text,
                Connection = HWM,
                CommandTimeout = 300,
                CommandText = sql})
            {
                //adds parameters to the Sql command
                addSoftware.Parameters.Add("@SoftwareName", SqlDbType.NVarChar, 200).Value = name;
                addSoftware.Parameters.Add("@SoftwareType", SqlDbType.Int).Value = type;
                //Executes the Sql
                addSoftware.ExecuteNonQuery();
            }
            Alert.Show("Software title saved!");
        }
        catch (System.Data.SqlClient.SqlException ex)
        {
            string msg = "Insert Error:";
            msg += ex.Message;
            throw new Exception(msg);
        }

    }
}

해결법

  1. ==============================

    1.당신은 IF 문을 사용하여이 작업을 수행 할 수 있습니다 :

    당신은 IF 문을 사용하여이 작업을 수행 할 수 있습니다 :

    IF NOT EXISTS 
        (   SELECT  1
            FROM    tblSoftwareTitles 
            WHERE   Softwarename = @SoftwareName 
            AND     SoftwareSystemType = @Softwaretype
        )
        BEGIN
            INSERT tblSoftwareTitles (SoftwareName, SoftwareSystemType) 
            VALUES (@SoftwareName, @SoftwareType) 
        END;
    

    당신은 IF가 SELECT를 사용하지 않고 그것을 할 수

    INSERT  tblSoftwareTitles (SoftwareName, SoftwareSystemType) 
    SELECT  @SoftwareName,@SoftwareType
    WHERE   NOT EXISTS 
            (   SELECT  1
                FROM    tblSoftwareTitles 
                WHERE   Softwarename = @SoftwareName 
                AND     SoftwareSystemType = @Softwaretype
            );
    

    두 가지 방법 모두 나는 아직도 삽입 위 중 하나를 사용하는 것입니다,하지만 당신은 고유 제한 조건과 중복 삽입을 보호 할 수 있도록하면서, 경쟁 조건에 취약 :

    CREATE UNIQUE NONCLUSTERED INDEX UQ_tblSoftwareTitles_Softwarename_SoftwareSystemType
        ON tblSoftwareTitles (SoftwareName, SoftwareSystemType);
    

    SQL-바이올린에 예

    추가

    SQL Server 2008에서는 이상 당신은 (여전히 고유 제한 조건을 대신 할 수는 없습니다) 경쟁 조건의 가능성을 제거하기 위해 HOLDLOCK과 병합을 사용할 수 있습니다.

    MERGE tblSoftwareTitles WITH (HOLDLOCK) AS t
    USING (VALUES (@SoftwareName, @SoftwareType)) AS s (SoftwareName, SoftwareSystemType) 
        ON s.Softwarename = t.SoftwareName 
        AND s.SoftwareSystemType = t.SoftwareSystemType
    WHEN NOT MATCHED BY TARGET THEN 
        INSERT (SoftwareName, SoftwareSystemType) 
        VALUES (s.SoftwareName, s.SoftwareSystemType);
    

    SQL 바이올린에 병합의 예

  2. ==============================

    2.이 응답하지 않습니다. 난 그냥 IF NOT이 존재 함을 보여주고 싶은 (...) INSERT 방법은 안전하지 않습니다. 당신은 먼저 세션 1과 세션 2를 실행해야합니다. V # 2 후에는 UNIQUE 인덱스없이 중복 쌍 (SoftwareName, SoftwareSystemType)를 얻을 수있는 것을 볼 수 있습니다. 세션 1에서 지연은 당신에게 두 번째 스크립트 (세션 2)을 실행하기에 충분한 시간을 제공하는 데 사용됩니다. 이 지연 시간을 감소시킬 수있다.

    이 응답하지 않습니다. 난 그냥 IF NOT이 존재 함을 보여주고 싶은 (...) INSERT 방법은 안전하지 않습니다. 당신은 먼저 세션 1과 세션 2를 실행해야합니다. V # 2 후에는 UNIQUE 인덱스없이 중복 쌍 (SoftwareName, SoftwareSystemType)를 얻을 수있는 것을 볼 수 있습니다. 세션 1에서 지연은 당신에게 두 번째 스크립트 (세션 2)을 실행하기에 충분한 시간을 제공하는 데 사용됩니다. 이 지연 시간을 감소시킬 수있다.

    세션 # 1 (SSMS> 새 쿼리> F5는 (실행))

    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;
    

    세션 # 2 (SSMS> 새 쿼리> F5는 (실행))

    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;
    

    결과 :

    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)
    
  3. ==============================

    3.이 문제에 대한 훌륭한 솔루션이 있습니다, 당신은 SQL을 병합 키워드를 사용할 수 있습니다

    이 문제에 대한 훌륭한 솔루션이 있습니다, 당신은 SQL을 병합 키워드를 사용할 수 있습니다

    Merge MyTargetTable hba
    USING (SELECT Id = 8, Name = 'Product Listing Message') temp 
    ON temp.Id = hba.Id
    WHEN NOT matched THEN 
    INSERT (Id, Name) VALUES (temp.Id, temp.Name);
    

    샘플은 아래에 당신은 다음하기 전에이 작업을 확인할 수 있습니다

    IF OBJECT_ID ('dbo.TargetTable') IS NOT NULL
        DROP TABLE dbo.TargetTable
    GO
    
    CREATE TABLE dbo.TargetTable
        (
        Id   INT NOT NULL,
        Name VARCHAR (255) NOT NULL,
        CONSTRAINT PK_TargetTable PRIMARY KEY (Id)
        )
    GO
    
    
    
    INSERT INTO dbo.TargetTable (Name)
    VALUES ('Unknown')
    GO
    
    INSERT INTO dbo.TargetTable (Name)
    VALUES ('Mapping')
    GO
    
    INSERT INTO dbo.TargetTable (Name)
    VALUES ('Update')
    GO
    
    INSERT INTO dbo.TargetTable (Name)
    VALUES ('Message')
    GO
    
    INSERT INTO dbo.TargetTable (Name)
    VALUES ('Switch')
    GO
    
    INSERT INTO dbo.TargetTable (Name)
    VALUES ('Unmatched')
    GO
    
    INSERT INTO dbo.TargetTable (Name)
    VALUES ('ProductMessage')
    GO
    
    
    Merge MyTargetTable hba
    USING (SELECT Id = 8, Name = 'Listing Message') temp 
    ON temp.Id = hba.Id
    WHEN NOT matched THEN 
    INSERT (Id, Name) VALUES (temp.Id, temp.Name);
    
  4. ==============================

    4.더 많은 제안 추가 읽기 댓글 링크의 ...이 작업을 달성 다양한 방법을 벤치 마크 정말 좋은 블로그 문서는 여기에서 찾을 수 있습니다.

    더 많은 제안 추가 읽기 댓글 링크의 ...이 작업을 달성 다양한 방법을 벤치 마크 정말 좋은 블로그 문서는 여기에서 찾을 수 있습니다.

    "아니 존재 삽입", "병합"문 "을 제외하고 삽입", 그리고 당신의 전형적인가 가장 빠른이 작업을 수행하는 것입니다 어떤 방법으로 볼 "왼쪽 가입"그들은 몇 가지 기술을 사용합니다.

    (직선 복사 / 붙여 그 페이지에서) 다음과 같이 각각의 방법에 사용되는 예시적인 코드 :

    INSERT INTO #table1 (Id, guidd, TimeAdded, ExtraData)
    SELECT Id, guidd, TimeAdded, ExtraData
    FROM #table2
    WHERE NOT EXISTS (Select Id, guidd From #table1 WHERE #table1.id = #table2.id)
    -----------------------------------
    MERGE #table1 as [Target]
    USING  (select Id, guidd, TimeAdded, ExtraData from #table2) as [Source]
    (id, guidd, TimeAdded, ExtraData)
        on [Target].id =[Source].id
    WHEN NOT MATCHED THEN
        INSERT (id, guidd, TimeAdded, ExtraData)
        VALUES ([Source].id, [Source].guidd, [Source].TimeAdded, [Source].ExtraData);
    ------------------------------
    INSERT INTO #table1 (id, guidd, TimeAdded, ExtraData)
    SELECT id, guidd, TimeAdded, ExtraData from #table2
    EXCEPT
    SELECT id, guidd, TimeAdded, ExtraData from #table1
    ------------------------------
    INSERT INTO #table1 (id, guidd, TimeAdded, ExtraData)
    SELECT #table2.id, #table2.guidd, #table2.TimeAdded, #table2.ExtraData
    FROM #table2
    LEFT JOIN #table1 on #table1.id = #table2.id
    WHERE #table1.id is null
    

    그것은 속도를 찾고있는 사람들을 위해 읽기 좋은! SQL 2014에서 삽입을 제외한 방법은 5000 만 개 이상의 레코드에 대한 가장 빠른 것으로 밝혀졌다.

  5. ==============================

    5.중복 고유 제한 조건을 무시하는 것은 해결책이 아니다?

    중복 고유 제한 조건을 무시하는 것은 해결책이 아니다?

    INSERT IGNORE INTO tblSoftwareTitles...
    
  6. from https://stackoverflow.com/questions/17991479/insert-values-where-not-exists by cc-by-sa and MIT license