这是一个具体例子的通用问题。
我有一个包含三个字段的表(genreID(PK IDENTITY),流派和subGenre)。该表对(genre,subGenre)组合有唯一约束。
我想知道如果表中不存在存储过程,我该如何修改存储过程,否则返回现有类型的genreID(如果存在的话)。
CREATE PROCEDURE spInsertGenre
@genreID int OUTPUT,
@genre varchar(100),
@subGenre varchar(100)= NULL
AS
BEGIN
INSERT INTO Genre
(
genre,
subGenre
)
Values (
@genre,
@subGenre
)
SELECT @genreID = SCOPE_IDENTITY()
END
GO
答案 0 :(得分:5)
在执行插入之前,您可以尝试选择SP将插入的行:
CREATE PROCEDURE spInsertGenre
@genreID int OUTPUT,
@genre varchar(100),
@subGenre varchar(100)= NULL
AS
BEGIN
-- if the row to be inserted already exists, put the genreID into the @genreID output parameter
SELECT @genreID = genreID
FROM Genre
WHERE genre = @genre
AND subGenre = @subGenre
IF @genreID IS NULL -- if the genreID was not found, do an insert and select the new genreID to the @genreID output parameter
BEGIN
INSERT INTO Genre
(
genre,
subGenre
)
Values (
@genre,
@subGenre
)
SELECT @genreID = SCOPE_IDENTITY()
END
END
GO
答案 1 :(得分:1)
编辑:根据Dan Guzman,MERGE statement has the same problem of conditional INSERT/UPDATE race condition。您需要使用HOLDLOCK表提示来避免此问题。
您可以使用带有HOLDLOCK表提示的MERGE语句:
CREATE PROCEDURE spInsertGenre
@GenreID int OUTPUT,
@Genre varchar(100),
@SubGenre varchar(100)= NULL
AS
BEGIN
DECLARE @IDs TABLE (GenreID INT PRIMARY KEY);
MERGE INTO Genre WITH (HOLDLOCK) AS g
USING (VALUES(@Genre,@SubGenre)) p(Genre,SubGenre) ON g.Genre = p.Genre AND g.SubGenre = p.SubGenre
WHEN NOT MATCHED
THEN
INSERT (Genre,SubGenre)
VALUES (p.Genre, p.SubGenre)
OUTPUT inserted.GenreID INTO @IDs (GenereID);
-- Above assigment is safe because this SP tries to insert only one row
SELECT @genreID = GenereID
FROM @IDs;
END
GO
或者,如果要插入多行,则可以使用表参数:
-- This table type is used to store the rows which should be inserted
CREATE TYPE dbo.GenreRows AS TABLE
(
Genre varchar(100),
SubGenre varchar(100),
PRIMARY KEY (Genre,SubGenre)
);
GO
CREATE PROCEDURE spInsertGenre
(
@pRows dbo.GenreRows READONLY -- p = parameter
)
AS
BEGIN
DECLARE @IDs TABLE(GenreID INT PRIMARY KEY);
MERGE INTO Genre WITH (HOLDLOCK) AS g
USING @pRows p ON g.Genre = p.Genre AND g.SubGenre = p.SubGenre
WHEN NOT MATCHED
THEN
INSERT (Genre,SubGenre)
VALUES (p.Genre, p.SubGenre)
OUTPUT inserted.GenreID INTO @IDs (GenereID);
SELECT GenereID
FROM @IDs;
END
GO