存储过程-游标-为记录字段分配一个值并在游标的末尾选择

时间:2018-07-26 10:23:09

标签: sql-server tsql stored-procedures cursor user-defined-types

我正在将联系人对象列表(List<Contact>从C#传递到SQL Server存储过程:

enter image description here

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

enter image description here

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

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

    SET @contactId = (SELECT SCOPE_IDENTITY()); 
    

    )。

  3. 最后选择修改后的联系人记录

在实现上面列出的第二步时,我需要一些帮助,这是我到目前为止所写的,

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(现有或新插入的)值来打印所有联系人记录。

对此表示感谢的任何帮助或指导。谢谢。

2 个答案:

答案 0 :(得分:3)

如果我理解正确,则希望获取输入电子邮件地址的列表,如果该电子邮件地址尚不存在,请在目标表中插入任何电子邮件地址,然后在目标表中输出原始地址列表及其对应的数据?您根本不需要游标,以下应该可以满足您的需要,并且可能会更好地执行:

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;

我的某些假设可能在此处稍有偏离,但这应作为起点。请注意,如果您对目标表的电子邮件地址列没有唯一的约束,那么末尾的结果可能会包含比您最初提供的更多的行,因为匹配的行可能会超过一个。请注意,如果您要执行其他操作(例如,如果该行存在则进行更新),则可以用merge语句替换insert语句。

答案 1 :(得分:0)

我使用如下表变量来完成此操作。

-- 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
);

现在,我使用光标循环表值联系列表,并在必要时进行插入,最后插入插入到输出表,如下所示。以下是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