SQL 服务器中的多对多关系 - 在基础 table 中未发生插入时在外部 table 中添加引用

Many to many relationship in SQL server - To add reference in foreign table when insertion does not happen in base table

我有两个 tables UserItem。用户 table 将拥有用户详细信息,项目 table 将拥有该项目的唯一条目。

现在我正在创建多对多关系,其中有一个名为 List 的单独 table,它引用两个 table 的主键作为外键。现在每个用户将传递一个 csv 字符串,其中包含他想要的所有项目。这些项目将添加到项目 table 中,其 ID 和用户 ID 将放在列表 table.

table 是这样创建的....

CREATE TABLE dbo.Item
(
Item_Id int identity(1,1) not null,
Item_Name varchar(30) not null,
PRIMARY KEY (Item_Id)
);

CREATE TABLE dbo.List
(
Item_Id int not null,
Users_Id varchar(11) not null,
);

存储过程看起来像这样...

ALTER procedure [dbo].[Entry] 
    @User_Id varchar(11)
    @Items VARCHAR(MAX)=NULL
as 
begin
    INSERT INTO dbo.Item
    OUTPUT INSERTED.Item_Id INTO @OutputTbl(Item_Id) 
       SELECT Item_Name
       FROM [dbo].[Split] ( @Items, ',')  -- call the split function 

    INSERT INTO dbo.List
       SELECT Item_Id, @User_Id 
       FROM @OutputTbl
end
GO

现在,当 Item 名称重复时,我想跳过 Item table 中的插入,但单独的条目应该放在 List table。

例如,如果 User1 给出了列表 "Soap,Shampoo" 并且它插入了 ID 1 和 2,并且引用将添加到列表 table 中。 现在,当 User2 列出 "Brush,Soap" 时,名称 Soap 不应在项目 table 中重复,但肥皂的 ID 应添加到引用 table 中,如

    UserID    |   ItemID
  ---------------------------
    User1         1 
    User1         2 
    User2         3 
    User2         1

这对我来说似乎很难,因为我检索了插入记录的 ID 并将它们放在列表 table 中。如何在名称已存在时将它们放入列表 table。

ALTER procedure [dbo].[Entry] 
    @User_Id varchar(11)
    @Items VARCHAR(MAX)=NULL
as 
begin
    DECLARE @Items TABLE (Name VARCHAR(150));

    -- call the split function 
    INSERT INTO @ItemNames
       SELECT Item_Name
       FROM [dbo].[Split] ( @Items, ',');

    -- insert all new items into items
    INSERT INTO dbo.Item
    SELECT Item_Name
       FROM @Items
    except 
    select item_name from dbo.Item;

    -- insert user/item into list
    INSERT INTO dbo.List
    SELECT distinct Item_Id, @User_Id 
    from @Items iu
    join dbo.Item i on iu.item_name=i.item_name;
end
GO

这样你只插入不在 table 中的名称并且必须加入整个项目列表并插入映射 table

我相信您可能一次尝试做太多事情。 PROC 似乎有以下 3 个问题:

  1. 从@Items 输入的逗号分隔字符串中分离出项目名称列表
  2. 使用一组唯一的所有 'seen' 项目名称维护 dbo.Item table(即将新项目添加到 table)
  3. 使用 User : ItemId 映射维护 dbo.List,无论项目是 'new' 还是 'existing'。

我会相应地分解问题:

CREATE PROCEDURE [dbo].[Entry] 
    @User_Id varchar(11),
    @Items VARCHAR(MAX)=NULL
AS BEGIN
    DECLARE @ItemNames TABLE (Name NVARCHAR(50));
    DECLARE @ItemIds TABLE (Item_Id INT);

    INSERT INTO @ItemNames(Name)
        SELECT Item_Name FROM [dbo].[Split] ( @Items, ',');

    INSERT INTO dbo.Item(Item_Id)
        SELECT Name
        FROM @ItemNames new
        WHERE NOT EXISTS(SELECT 1 FROM dbo.Item i WHERE i.Item_Id = new.Name);

    INSERT INTO dbo.List(itm.Item_Id, User_Id)
       SELECT Item_Id, @User_Id 
       FROM @ItemNames new
        INNER JOIN dbo.Item itm
        ON itm.Item_Id = new.Name;
END;

SqlFiddle here

我编辑了我的代码以实际将名称存储为 temptable 而不是 ID,然后我使用 Inner join 从适合我的 temptable.The 存储过程中的相应名称将 Id 插入到列表中。 ..

CREATE procedure [dbo].[Entry]
@Users_Id varchar(11),
@Items VARCHAR(MAX)=NULL
as 
begin
DECLARE @ItemNames TABLE (Item_Names VARCHAR(150));

INSERT INTO @ItemNames 
SELECT Item_Name  
FROM [dbo].[Split] ( @Items, ',')  -- call the split function 

INSERT INTO dbo.Item
SELECT Item_Names
FROM @ItemNames list
WHERE NOT EXISTS(SELECT 1 FROM dbo.Item i WHERE i.Item_Name = list.Item_Names);

INSERT INTO dbo.List(Item_Id,Users_Id)
SELECT  Item_Id,@Users_Id 
FROM @ItemNames list
INNER JOIN dbo.Item 
    ON list.Item_Names = dbo.Item.Item_Name;
end
GO