2014-12-01 61 views
0

我開始使用sql數據庫並嘗試對其進行修改以使其使用批量插入(而不是逐個)的現有程序,並且還防止重複輸入。SQL:編寫忽略現有條目的批量插入腳本

下面是我得到了什麼,我的函數添加一個用戶(只要該用戶不存在),這應該是工作:

use [DebugDatabase] 
go 

set ansi_nulls on 
go 

set quoted_identifier on 
go 

create procedure [dbo].[AddUser] 
    @Id bigint, @Login nvarchar(100), @ConsoleName nvarchar(100), @Ip nvarchar(50) 
as 
begin 
    set nocount on; 

    declare @FoundId bigint = (select Id from [User] where Id = @Id) 

    if @FoundId is null 
     begin 
      insert into [User] (Id, Login, ConsoleName, Ip) values (@Id, @Login, @ConsoleName, @Ip) 
     end 
    else 
     begin 
      update [User] 
      set [Id] = @Id, 
       [Login] = @Login, 
       [ConsoleName] = @ConsoleName, 
       [Ip] = @Ip 
      where Id = @Id 
     end 
    select top 1 * from [User] where Id = @Id; 
end 
go 

現在我想寫一個函數用於批量插入,該函數調用上述函數來檢查每個條目。我表現出的方​​式,這需要一個自定義的表類型:

use [DebugDatabase] 
go 

create type [dbo].[UserTableType] as table 
    (
    [Id] [bigint] not null, 
    [Login] [nvarchar](100) not null default 'Unknown', 
    [ConsoleName] [nvarchar](100) not null default 'Unknown', 
    [Ip] [nvarchar](50) not null default '0.0.0.0' 
    ) 
go 

,並添加多個條目的功能(這是我遇到的麻煩之一):

use [DebugDatabase] 
go 

set ansi_nulls on 
go 

set quoted_identifier on 
go 

create procedure [AddMultipleUsers] 
    @users UserTableType readonly 

as 

declare 
    @Id bigint, 
    @Login nvarchar(100), 
    @ConsoleName nvarchar(100), 
    @Ip nvarchar(50) 

begin 
    insert into @Id select Id from @users 
    insert into @Login select Login from @users 
    insert into @ConsoleName select ConsoleName from @users 
    insert into @Ip select Ip from @users 

    exec AddUser @Id, @Login, @ConsoleName, @Ip 
end 
go 

我得到「必須聲明表變量」@Id「我不知道如何從表類型中提取各個值,以便將它們傳遞給AddUser函數,但我真正喜歡的是某種方式在一個函數調用中做到這一切,但我還沒有遇到過這樣的事情。

+0

您INSERT INTO「@id」將無法工作,因爲「@Id」是一個BIGINT不是表。你應該像這樣設置@Id參數:'設置@ Id =(從@users選擇最高1個ID)' – Jt2ouan 2014-12-02 00:46:07

回答

3

這種類型的操作可以使用單個查詢來完成,而無需使用存儲過程。 (順便說一句,請使用正確的術語:您的AddUser是一個存儲過程,而不是一個函數)。請看看在MERGE命令

MERGE [User] AS target 
    USING (SELECT [Id], [Login], [ConsoleName], [Ip] FROM @users) AS source 
    (Id, Login, ConsoleName, Ip) 
    ON (target.Id = source.Id) 
WHEN MATCHED THEN 
     UPDATE SET [Login] = source.Login, 
        [ConsoleName] = source.ConsoleName, 
        [Ip] = source.Ip 
WHEN NOT MATCHED THEN 
    INSERT (Id, Login, ConsoleName, Ip) 
    VALUES (source.Id, source.Login, source.ConsoleName, source.Ip); 
+0

謝謝,這似乎迄今爲止工作良好。由於長期目標是使用實體框架從c#程序中調用它,我相信它必須作爲一個過程存儲。 – 2014-12-02 01:19:18

+0

只需放入'[AddMultipleUsers]'的內部並擺脫您的DECLARE語句 – cha 2014-12-02 02:48:10

+0

這正是我所做的。謝謝你的幫助,cha。 – 2014-12-02 18:41:25

0
create procedure [AddMultipleUsers] 
    @users UserTableType readonly 

as 

declare 
    @Id bigint, 
    @Login nvarchar(100), 
    @ConsoleName nvarchar(100), 
    @Ip nvarchar(50) 

-- A opcion ... 
-- Declare the cursor for the list of users to be processed. 
DECLARE userT CURSOR FOR SELECT * FROM UserTableType ; 

-- Open the cursor. 
OPEN userT; 

-- Loop through the users. 
FETCH NEXT 
    FROM userT 
    INTO @Id, @Login, @ConsoleName, @Ip; 

WHILE @@FETCH_STATUS = 0 
BEGIN; 
    exec AddUser @Id, @Login, @ConsoleName, @Ip 

    FETCH NEXT FROM userT INTO @Id, @Login, @ConsoleName, @Ip; 
END; 

-- Close and deallocate the cursor. 
CLOSE partitions; 
DEALLOCATE partitions;