存储过程 - 混乱不堪

问题描述 投票:0回答:1

目标是创建 2 个存储过程。

sp_InsertNewMenuItem
,检查
MenuTitle
MenuGroupText
是否存在。如果有,请使用
id
,如果没有,请为每个创建一个新菜单项。

它的目标是为第二个过程创建一个新的菜单项:

sp_InsertIngredient
,它从第一个过程中创建并将成分插入到菜单项中。

我已经解决了大部分问题。第一个过程检查它是否存在并执行其操作。我可以插入第二个程序中的成分。

问题出在创建的表上。

条目混杂在几个不同的行中

this is an example

所以支票有效。我尝试弄乱身份,因为我们必须使用身份来完成这项任务。即使我只有主ID为identity(1,1),也会出现同样的问题。我不知道该怎么办。

我不是在找人帮我做这件事,我只是在寻求帮助。尽管我进行了研究和其他尝试,但我真的不知道该怎么做。

这是我的代码。

表格:

CREATE TABLE [dbo].[Menu]
(
    [ID] INT PRIMARY KEY IDENTITY(1,1),
    [MenuTitle] [nvarchar](50) NULL,
    [MenuDescriptionText] [nvarchar](50) NULL
)
  
CREATE TABLE [dbo].[MenuGroups]
(
    [ID] INT PRIMARY KEY IDENTITY(1,1),
    [MenuID] INT NULL,
    [MenuGroupText] [nvarchar](50) NULL,
    [MenuGroupDescriptionText] [nvarchar](50) NULL, 
    FOREIGN KEY (MenuID) REFERENCES Menu(ID)
)

CREATE TABLE [dbo].[MenuItems]
(
    [ID] INT PRIMARY KEY IDENTITY(1,1),
    [MenuGroupsID] INT NULL,
    [MenuItemTitle] [nvarchar](50) NULL,
    [MenuItemDescriptionText] [nvarchar](50) NULL,
    FOREIGN KEY (MenuGroupsID) REFERENCES MenuGroups(ID)
)

CREATE TABLE [dbo].[Ingredients]
(
    [ID] INT PRIMARY KEY IDENTITY(1,1),
    [IngredientTitleText] [NVARCHAR](50) NULL,
    [IngredientDescriptionText] [NVARCHAR](200) NULL
)

CREATE TABLE [dbo].[IngredientsInItems]
(
    [ID] INT PRIMARY KEY IDENTITY(1,1),
    [IngredientsID] INT NULL,
    [MenuItemID] INT NULL, 
    [DescriptionText] [NVARCHAR](200), 
    FOREIGN KEY (IngredientsID) REFERENCES Ingredients(ID),
    FOREIGN KEY (MenuItemID) REFERENCES MenuItems(ID)
)

程序:

CREATE PROCEDURE Sp_insertnewmenuitem 
    (@MenuTitle     NVARCHAR(50),
     @MenuGroupText NVARCHAR(50),
     @MenuItemTitle NVARCHAR(50))
AS
BEGIN
    DECLARE @MenuID      INT,
            @MenuGroupID INT

    IF NOT EXISTS (SELECT 1
                   FROM [dbo].[menu]
                   WHERE [menutitle] = @MenuTitle)
    BEGIN
        INSERT INTO [dbo].[menu] ([menutitle])
        VALUES (@MenuTitle)

        SET @MenuID = SCOPE_IDENTITY()
    END
    ELSE
    BEGIN
        SET @MenuID = (SELECT [id]
                       FROM [dbo].[menu]
                       WHERE [menutitle] = @MenuTitle)
    END

    IF NOT EXISTS (SELECT 1
                   FROM [dbo].[menugroups]
                   WHERE [menugrouptext] = @MenuGroupText
                     AND [menuid] = @MenuID)
    BEGIN
        INSERT INTO [dbo].[menugroups] ([menuid], [menugrouptext])
        VALUES (@MenuID, @MenuGroupText)

        SET @MenuGroupID = SCOPE_IDENTITY()
    END
    ELSE
    BEGIN
        SET @MenuGroupID = (SELECT [id]
                            FROM [dbo].[menugroups]
                            WHERE [menugrouptext] = @MenuGroupText
                              AND [menuid] = @MenuID)
    END

    INSERT INTO [dbo].[menuitems] ([menugroupsid], [menuitemtitle])
    VALUES (@MenuGroupID, @MenuItemTitle)
END 
CREATE PROCEDURE Sp_insertingredient 
    (@IngredientTitleText NVARCHAR(50))
AS
BEGIN
    DECLARE @IngredientID INT,
            @MenuItemID   INT

    IF NOT EXISTS (SELECT 1
                   FROM [dbo].[ingredients]
                   WHERE [ingredienttitletext] = @IngredientTitleText)
    BEGIN
        INSERT INTO [dbo].[ingredients] ([ingredienttitletext])
        VALUES (@IngredientTitleText)

        SET @IngredientID = SCOPE_IDENTITY()
    END
    ELSE
    BEGIN
        SET @IngredientID = (SELECT [id]
                             FROM [dbo].[ingredients]
                             WHERE [ingredienttitletext] = @IngredientTitleText)
    END

    INSERT INTO [dbo].[ingredientsinitems] ([ingredientsid], [menuitemid])
    VALUES (@IngredientID, @MenuItemID)
END 
sql sql-server stored-procedures
1个回答
0
投票

您的程序不正确,会产生一些误报数据...

开发人员在开发数据库过程时总是忘记两个基本的事情:

并发:如果两个不同的用户同时启动同一个程序会发生什么

基于集合的处理:数据库不根据迭代代码进行操作,而是作为集合转换

举个例子,这段代码:

    IF NOT EXISTS (SELECT 1
                   FROM [dbo].[ingredients]
                   WHERE [ingredienttitletext] = @IngredientTitleText)
    BEGIN
        INSERT INTO [dbo].[ingredients] ([ingredienttitletext])
        VALUES (@IngredientTitleText)

同时执行将插入两行...

Time 0 | User A                         | User B
       | SELECT 1                       | SELECT 1 
       | FROM ingredients               | FROM ingredients 
       | WHERE ...                      | WHERE ... 

Time 1 | INSERT INTO ingredients        | < wait because INSERT locks>
       | VALUES (@IngredientTitleText)  | ...

Time 2 |                                | INSERT INTO ingredients
       |                                | VALUES (@IngredientTitleText)

将给出重复条目。因为读者可以多个人同时阅读....

避免重复的唯一方法是使用 UNIQUE 约束。没有别的办法了!

© www.soinside.com 2019 - 2024. All rights reserved.