Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL创建/写入存储过程时出现问题_Sql Server_Stored Procedures - Fatal编程技术网

Sql server SQL创建/写入存储过程时出现问题

Sql server SQL创建/写入存储过程时出现问题,sql-server,stored-procedures,Sql Server,Stored Procedures,我在创建存储过程以将项目插入数据库时遇到问题,存储过程还会检查项目是否存在,如果不存在,则会创建项目 这是我的数据库图 这是我用来创建表的SQL代码,例外是从表MenuItem.MenuGroupID添加了一个外键到MenuGroup.MenuGroupID,这将显示数据类型等 use MenuDatabase GO CREATE TABLE Menu ( MenuID int primary key identity (1,1), MenuTitle varchar(200) null, M

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

这是我的数据库图

这是我用来创建表的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
我当前在ManagementStudio中执行该过程时遇到以下错误

(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 | Get Menu.MenuID | Insert,Get Identity

Menu.MenuID | MenuGroupText varchar | MenuGroup.MenuGroupText |获取MenuGroup.MenuGroupID |插入,获取标识MenuGroup.MenuGroupID

MenuItem varchar | MenuItem.MenuItemTitle |不插入|插入

一个例子

菜单-午餐菜单

菜单组文本-三明治


MenuItem-California Chicken Sandwich

即使您解决了错误消息,您当前的存储过程也确实存在一些可以轻松修复的问题。 例如,您不需要对记录进行计数来确定它们是否存在于表中。 另外,您不应该使用@@Identity,您应该使用scope\u Identity。 原因是@@Identity将返回插入数据库中的最后一个标识值,因此您可能会将这些值插入到您的过程中甚至不相关的表中。但是,scope_identity将返回插入当前作用域中的最后一个标识值,即存储过程中的标识值

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
所以这一部分:

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_的意见:

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关于该主题的文章。

前两个错误是因为您没有在@MenuGroupCount上调用DECLARE。您在第36行的值后缺少了一个括号。OK谢谢,我将修复并编辑以反映更改Hanks一大堆似乎修复了问题的新错误:第一个错误是因为默认情况下您无法插入到表的主键列,使用SET INDENTITY_INSERT很容易修复第二个列,这是因为您有一些外键规则,可能是因为您复制了值