SQL无法创建/编写存储过程

时间:2018-02-12 03:28:04

标签: sql-server stored-procedures

我在创建存储过程以将项目插入数据库时​​遇到问题,存储过程还会检查项目是否存在以及是否存在项目。

这是我的数据库图表

enter image description here

这是我用于创建表的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 - 加州鸡肉三明治

1 个答案:

答案 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