我有一个用于创建单个用户的查询事务。
comapny_id + email
应该是唯一的
BEGIN TRANSACTION
IF NOT EXISTS(
SELECT * FROM user WHERE email = @email AND company = 'company_id'
) BEGIN
INSERT INTO user (id, company_id, email, password)
VALUES ( NEWID(), 'company_id', 'email');
INSERT INTO user_log( id, date, type) VALUES ( 'user_id', SYSUTCDATETIME(), 'created');
SELECT @i as 'id', 'email' as 'email';
END ELSE BEGIN
SELECT NULL as 'id', 'email' as email;
END
END TRANSACTION
COMMIT TRANSACTION
如何修改此查询以支持多次插入,以便丢弃重复值并仅插入非重复项。
我有大量用户(5000-10000)。我正在循环user object
并使用上面的查询。但它很慢,所以我需要使用多个插入。
所以查询可能是
// transaction
INSERT INTO user(id, company_id, email, password) VALUES (),(),(),() .....
And also return the ids of the inserted rows
答案 0 :(得分:3)
您可以使用表值参数将多个值作为参数传递。第一步是创建表类型:
CREATE TYPE dbo.ListOfString AS TABLE (Value VARCHAR(MAX));
然后,您可以创建接受多个电子邮件地址的程序:
CREATE PROCEDURE dbo.InsertUsers @Emails dbo.ListOfString READONLY
AS
BEGIN
...
END
然后仅在不存在的情况下执行UPSERT,我所知道的最安全的方法是将MERGE
与HOLDLOCK
一起使用:
MERGE [user] WITH (HOLDLOCK) AS u
USING @Emails AS e
ON e.Email = u.Email
AND u.Company = 'company_id'
WHEN NOT MATCHED THEN
INSERT (id, company, email)
VALUES (NEWID(), 'company_id', e.Email)
OUTPUT inserted.id, SYSUTCDATETIME(), 'created' INTO user_log( id, date, type);
output子句也处理日志中事件的添加。
您可以使用以下内容调用此过程:
DECLARE @NewUser dbo.ListOfString;
INSERT @NewUser (Value)
VALUES ('Test@Test.com'), ('Test2@test.com');
EXECUTE dbo.InsertUser @NewUser;
我可能倾向于将公司作为参数,使您的完整程序如下:
CREATE PROCEDURE dbo.InsertUsers @Emails dbo.ListOfString READONLY, @Company VARCHAR(50)
AS
BEGIN
MERGE [user] WITH (HOLDLOCK) AS u
USING @Emails AS e
ON e.Email = u.Email
AND u.Company = @Company
WHEN NOT MATCHED THEN
INSERT (id, company, email)
VALUES (NEWID(), @Company, e.Email)
OUTPUT inserted.id, SYSUTCDATETIME(), 'created' INTO user_log( id, date, type);
END
或者,您可以使您的表值参数也包含公司:
CREATE TYPE dbo.NewUser AS TABLE (Email VARCHAR(255), Company VARCHAR(100));
这允许一次将用户添加到两个不同的公司:
CREATE PROCEDURE dbo.InsertUsers @Emails dbo.NewUser READONLY
AS
BEGIN
MERGE [user] WITH (HOLDLOCK) AS u
USING @Emails AS e
ON e.Email = u.Email
AND u.Company = e.Company
WHEN NOT MATCHED THEN
INSERT (id, company, email)
VALUES (NEWID(), e.Company, e.Email)
OUTPUT inserted.id, SYSUTCDATETIME(), 'created' INTO user_log( id, date, type);
END
最后,如评论中所述。所有这些确保唯一性的工作都很好,但它不能取代独特的约束!无论您的插入方法如何,这都应该到位:
ALTER TABLE dbo.[User]
ADD CONSTRAINT UQ_User__Company_Email UNIQUE (Company, Email);