存储过程 - 游标 - 为游标末尾的记录字段和 select 赋值

Stored procedure - Cursor - assign a value to record field and select at the end of the cursor

我正在将联系人对象列表 (List<Contact>) 传递给来自 C# 的 SQL 服务器存储过程:

为了捕获此列表,我在 SQL 服务器中使用了用户定义的 table 类型,如下所示:

现在在我的存储过程中我需要做以下事情。

  1. 通过传递给存储过程的联系人列表循环(游标)
  2. 如果数据库中的 tblContact table 有一条包含当前电子邮件地址(当前联系人 record/iteration 的)的记录,则需要获取 tblContact记录ContactId并赋值给当前Contact迭代记录;否则使用该电子邮件地址(不存在)向 tblContact 插入一条新记录并将其 contactId 值分配给当前联系人 record/iterations tblContact 字段(因为 contactId 是 TblContact 的主键,我可以做

    SET @contactId = (SELECT SCOPE_IDENTITY()); 
    

    ).

  3. 最后select修改联系人记录

我需要一些帮助来实施上面列出的第二步,这是我到目前为止所写的内容,

ALTER PROCEDURE [dbo].[UpdateMailjetDetails] 
    @contacts Contact READONLY
AS
BEGIN
    SET NOCOUNT ON;

    -- 1. Loop (cursor) though contacts list passed to stored procedure
    DECLARE @contactEmail varchar(1000);

    DECLARE cur CURSOR FOR 
         SELECT Email FROM @contacts

    OPEN cur    
    FETCH NEXT FROM cur INTO @contactEmail; 

    WHILE @@FETCH_STATUS = 0 
    BEGIN
        DECLARE @contactId INT = (SELECT TOP(1) ContactId 
                                  FROM tblContact 
                                  WHERE EmailAddress = @contactEmail);

        IF (@contactId != '')
        BEGIN           
            SELECT 'Exists - ' + CONVERT(VARCHAR, @contactId);

        -- 2 assign contact Id to current contact.TblContactId
    END
    ELSE
    BEGIN
        INSERT INTO tblContact (EmailAddress, DateCreated) 
        VALUES (@contactEmail, GETDATE()); 

        SET @contactId = (SELECT SCOPE_IDENTITY()); 
        -- 2 new @contactId value to current contact.TblContactId 
    END

    FETCH NEXT FROM cur INTO @contactEmail;
END

CLOSE cur    
DEALLOCATE cur

-- 3
SELECT * FROM @contacts
END

这就是我执行存储过程的方式:

DECLARE @return_value int
DECLARE @input Contact;

INSERT INTO @input (Email, [Name], TblContactId, CompanyId, TblContactCompanyId) 
VALUES ('a@a.com', 'a', null, null, null),
       ('b@a.com', 'b', null, 1, 1),
       ('a@gmail.com', 'aa', null, 1, 1),
       ('b@hotmail.com', 'bb', null, 1, 1)


EXEC @return_value = [dbo].[UpdateMailjetDetails]
                     @contacts = @input

SELECT 'Return Value' = @return_value
GO

因此,如上所述,在执行存储过程后,它需要用它打印所有联系人记录TblContactId(现有的,或新插入的)值。

非常感谢对此的任何帮助或指导。谢谢。

我使用如下所示的 table 变量来完成此操作。

-- store the output in the below table
DECLARE @outputContacts TABLE (
    Email NVARCHAR(512) NULL, 
    [Name] NVARCHAR(512) NULL, 
    TblContactId bigint NULL, 
    CompanyId int null,
    TblContactCompanyId bigint null
);

现在,我使用光标循环 table 值的联系人列表,并在必要时进行插入,最后进行插入以输出 table,如下所示。下面是SP。

ALTER PROCEDURE [dbo].[UpdateMailjetDetails] 
@contacts Contact READONLY
AS
BEGIN

SET NOCOUNT ON;

-- store the output in the below table
DECLARE @outputContacts TABLE (
    Email NVARCHAR(512) NULL, 
    [Name] NVARCHAR(512) NULL, 
    TblContactId bigint NULL, 
    CompanyId int null,
    TblContactCompanyId bigint null
);

-- 1. Loop (cursor) though contacts list passed to stored procedure
DECLARE @contactEmail varchar(1000);
DECLARE @contactName NVARCHAR(512);
DECLARE @contactTblContactId bigint;
DECLARE @contactCompanyId int;
DECLARE @contactTblContactCompanyId bigint;

DECLARE cur CURSOR FOR SELECT Email, [Name], TblContactId, CompanyId, TblContactCompanyId FROM @contacts;
OPEN cur;   
FETCH NEXT FROM cur INTO @contactEmail, @contactName, @contactTblContactId, @contactCompanyId, @contactTblContactCompanyId; 
WHILE @@FETCH_STATUS = 0 BEGIN

    DECLARE @contactId int = (select top(1) ContactId from tblContact where EmailAddress = @contactEmail);

    IF (@contactId != '')
    BEGIN           

        select 'Exists - ' + convert(varchar, @contactId);  
    END
    ELSE
    BEGIN
        insert into tblContact (EmailAddress, DateCreated) values (@contactEmail, GETDATE()); 
        SET @contactId = (SELECT SCOPE_IDENTITY()); 
    END
    -- insert to output table
    insert into @outputContacts (Email, [Name], TblContactId, CompanyId, TblContactCompanyId) 
            values (@contactEmail, @contactName, @contactId, @contactCompanyId, @contactTblContactCompanyId);

    FETCH NEXT FROM cur INTO @contactEmail, @contactName, @contactTblContactId, @contactCompanyId, @contactTblContactCompanyId; 
END

CLOSE cur;    
DEALLOCATE cur;

-- 3
select * from @outputContacts;  
END

如果我没理解错的话,你想要一个输入电子邮件地址的列表,如果该电子邮件地址尚不存在,则将任意一个插入到目标 table 中,然后输出原始地址列表及其地址目标中对应的数据table?您根本不需要游标,以下应该可以满足您的需要,并且可能会表现得更好:

CREATE PROC dbo.UpdateMailjetDetails (
    @contacts dbo.Contact READONLY
)
AS

INSERT INTO dbo.tblContact (EmailAddress, DateCreated)
SELECT c.Email, SYSDATETIME()
FROM @contacts c
WHERE NOT EXISTS (
    SELECT 1
    FROM dbo.tblContact t
    WHERE t.EmailAddress = c.Email
);

SELECT c.Email, t.[Name], t.tblContactId, c.CompanyId, t.CompanyId AS tblContactCompanyId
FROM @contacts c
    LEFT OUTER JOIN dbo.tblContact t ON t.EmailAddress = c.Email;

我的一些假设在这里可能略有偏差,但这应该作为一个起点。请注意,如果您对目标 table 中的电子邮件地址列没有唯一约束,那么末尾的结果可能包含比您最初提供的行更多的行,因为可能有多个匹配行。注意,如果你想执行其他操作,比如如果行存在则更新,那么insert语句可以用merge语句代替。