我在创建存储过程以将项目插入数据库时遇到问题,存储过程还会检查项目是否存在以及是否存在项目。
这是我的数据库图表
这是我用于创建表的SQL代码(除了从表MenuItem.MenuGroupID添加外键到MenuGroup.MenuGroupId之外),这将显示数据类型等。
use MenuDatabase
GO
CREATE TABLE Menu
(
MenuID int primary key identity (1,1),
MenuTitle varchar(200) null,
MenuDescriptionText varchar(200) null,
)
create table Menugroup
(
MenuGroupID int primary key identity (1,1),
MenuID int,
MenuGroupText varchar(200) null,
MenuGroupDescriptionText varchar(200) null,
)
create table MenuItem
(
MenuItemID int primary key identity (1,1),
MenuID int,
MenuGroupID varchar(200) null,
MenuItemCallNumber varchar(200) null,
MenuItemTitle varchar(200) null,
MenuItemDescriptionText varchar(200) null,
MenuItemNutritionText varchar(200) null,
MenuItemIngredientsText varchar(200) null,
MenuItemQuantity varchar(200) null,
MenuItemPreparationTime varchar(200) null,
MenuItmeCost varchar(200) null,
MenuItemTypeCode varchar(200) null,
MenuItemEthnicTypeCode varchar(200) null,
MenuItemAvailabilityBit varchar(200) null,
)
这是我正在为存储过程工作的SQL脚本。
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_InsertNewMenuItem] (
@MenuItemTitle VARCHAR(200),
@MenuGroupText VARCHAR(200),
@MenuTitle VARCHAR(200)
)
AS
BEGIN
DECLARE @MenuCount INT
SET @MenuCount = (SELECT COUNT(*) FROM Menu WHERE MenuTitle = @MenuTitle)
DECLARE @MenuID INT
IF @MenuCount= 1
BEGIN
SET @MenuID = (SELECT MenuID FROM Menu WHERE MenuTitle = @MenuTitle)
END
ELSE
BEGIN
INSERT INTO Menu (MenuTitle) VALUES (@MenuTitle)
SET @MenuID = @@IDENTITY
END
DECLARE @MenuGroupCount INT
SET @MenuGroupCount = (SELECT COUNT(*) FROM MenuGroup WHERE MenuGroupText = @MenuGroupText)
DECLARE @MenuGroupID INT
IF @MenuGroupCount = 1
BEGIN
SET @MenuGroupID = (SELECT MenuGroupID FROM MenuGroup WHERE MenuGroupText = @MenuGroupText)
END
ELSE
BEGIN
INSERT INTO MenuGroup (MenuGroupText, MenuGroupID) VALUES (@MenuGroupText, @MenuID)
SET @MenuGroupID = @@IDENTITY
END
INSERT INTO MenuItem (MenuItemTitle)
VALUES (@MenuItemTitle)
INSERT INTO MenuGroup (MenuGroupText)
VALUES (@MenuGroupText)
INSERT INTO Menu (MenuTitle)
VALUES (@MenuTitle)
SET IDENTITY_INSERT MenuGroup OFF
END
GO
我目前在执行程序时在管理工作室中收到以下错误
(1 row(s) affected)
Msg 544, Level 16, State 1, Procedure sp_InsertNewMenuItem, Line 36
Cannot insert explicit value for identity column in table 'MenuGroup' when IDENTITY_INSERT is set to OFF.
我需要尝试修复这些错误(我不明白它们发生的原因),并确保该功能可以执行检查以下内容所需的内容:
存储过程变量/字段|表场|如果存在|如果不存在
MenuTitle varchar | Menu.MenuTitle |获取Menu.MenuID |插入,获取身份
Menu.MenuID | MenuGroupText varchar | MenuGroup.MenuGroupText |获取MenuGroup.MenuGroupID |插入,获取Identity MenuGroup.MenuGroupID
MenuItem varchar | MenuItem.MenuItemTitle |不要插入|插入
一个例子;
MenuTitle - 午餐菜单
MenuGroupText - 三明治
MenuItem - 加州鸡肉三明治
答案 0 :(得分:1)
即使您解决了错误消息,您当前的存储过程确实存在一些可以轻松修复的问题。
例如,您不需要对记录进行计数以确定它们是否存在于表中
此外,您不应该使用@@Identity
,您应该使用scope_identity()
这样做的原因是@@Identity
将返回插入数据库中的最后一个标识值,因此您可能会将值插入到您甚至无法在过程中使用的表中。但是,scope_identity()
将返回当前作用域中插入的最后一个标识值 - 意味着存储过程内部。
所以这部分:
DECLARE @MenuCount INT
SET @MenuCount = (SELECT COUNT(*) FROM Menu WHERE MenuTitle = @MenuTitle)
DECLARE @MenuID INT
IF @MenuCount= 1
BEGIN
SET @MenuID = (SELECT MenuID FROM Menu WHERE MenuTitle = @MenuTitle)
END
ELSE
BEGIN
INSERT INTO Menu (MenuTitle) VALUES (@MenuTitle)
SET @MenuID = @@IDENTITY
END
可以这样写:
DECLARE @MenuID INT
SELECT @MenuID = MenuID FROM Menu WHERE MenuTitle = @MenuTitle;
IF @MenuID IS NULL
BEGIN
INSERT INTO Menu(MenuTitle) VALUES (@MenuTitle);
SET @MenuID = SCOPE_IDENTITY()
END
请注意,我的版本在您的版本中只有一个select语句而不是两个。
此外,整个过程应该在一个事务中,这样如果一个部件出现故障,将恢复故障点之前的所有更改。
以下是我建议您编写程序的方法(请注意我已将其名称从sp_InsertNewMenuItem
更改为stp_InsertNewMenuItem
以解决marc_s的评论:
DROP PROCEDURE [dbo].[sp_InsertNewMenuItem]
GO
CREATE PROCEDURE [dbo].[stp_InsertNewMenuItem]
(
@MenuItemTitle VARCHAR(200),
@MenuGroupText VARCHAR(200),
@MenuTitle VARCHAR(200)
)
AS
BEGIN
BEGIN TRANSACTION
BEGIN TRY
DECLARE @MenuID INT
SELECT @MenuID = MenuID
FROM Menu
WHERE MenuTitle = @MenuTitle
IF @MenuID IS NULL
BEGIN
INSERT INTO Menu(MenuTitle)
VALUES (@MenuTitle)
SET @MenuID = SCOPE_IDENTITY()
END
DECLARE @MenuGroupID INT
SELECT @MenuGroupID = MenuGroupID
FROM MenuGroup
WHERE MenuGroupText = @MenuGroupText
IF @MenuGroupID IS NULL
BEGIN
INSERT INTO MenuGroup(MenuID, MenuGroupText)
VALUES (@MenuID, @MenuGroupText)
SET @MenuGroupID = SCOPE_IDENTITY()
END
INSERT INTO MenuItem (MenuID, MenuGroupID, MenuItemTitle)
VALUES (@MenuID, @MenuGroupID, @MenuItemTitle)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION
END CATCH
END
GO
还有一件事 - 如果多个用户可能同时编辑菜单,则可能会得到错误的结果(因为竞争条件)。为避免这种情况,请阅读Dan Guzman关于这个主题的blog post。