存储过程 - 游标 - 为游标末尾的记录字段和 select 赋值
Stored procedure - Cursor - assign a value to record field and select at the end of the cursor
我正在将联系人对象列表 (List<Contact>
) 传递给来自 C# 的 SQL 服务器存储过程:
为了捕获此列表,我在 SQL 服务器中使用了用户定义的 table 类型,如下所示:
现在在我的存储过程中我需要做以下事情。
- 通过传递给存储过程的联系人列表循环(游标)
如果数据库中的 tblContact
table 有一条包含当前电子邮件地址(当前联系人 record/iteration 的)的记录,则需要获取 tblContact
记录ContactId
并赋值给当前Contact
迭代记录;否则使用该电子邮件地址(不存在)向 tblContact 插入一条新记录并将其 contactId 值分配给当前联系人 record/iterations tblContact 字段(因为 contactId 是 TblContact 的主键,我可以做
SET @contactId = (SELECT SCOPE_IDENTITY());
).
最后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语句代替。
我正在将联系人对象列表 (List<Contact>
) 传递给来自 C# 的 SQL 服务器存储过程:
为了捕获此列表,我在 SQL 服务器中使用了用户定义的 table 类型,如下所示:
现在在我的存储过程中我需要做以下事情。
- 通过传递给存储过程的联系人列表循环(游标)
如果数据库中的
tblContact
table 有一条包含当前电子邮件地址(当前联系人 record/iteration 的)的记录,则需要获取tblContact
记录ContactId
并赋值给当前Contact
迭代记录;否则使用该电子邮件地址(不存在)向 tblContact 插入一条新记录并将其 contactId 值分配给当前联系人 record/iterations tblContact 字段(因为 contactId 是 TblContact 的主键,我可以做SET @contactId = (SELECT SCOPE_IDENTITY());
).
最后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语句代替。