Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.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 Server_Sql Server 2008 - Fatal编程技术网

Sql server 使用表值参数将值插入表中的存储过程

Sql server 使用表值参数将值插入表中的存储过程,sql-server,sql-server-2008,Sql Server,Sql Server 2008,鉴于以下简单结构: TABLE: Product (ProductId, ProductName) TABLE: Category (CategoryId, CategoryName) LINK TABLE: ProductId,CategoryId 我有一个表类型,我想将它传递给存储过程,以便在不存在值的情况下将它们插入到另一个表中 CREATE TYPE StringList_TBLType AS TABLE (s NVARCHAR(255) NOT NULL PRIMARY KEY)

鉴于以下简单结构:

TABLE: Product (ProductId, ProductName)

TABLE: Category (CategoryId, CategoryName)

LINK TABLE: ProductId,CategoryId
我有一个表类型,我想将它传递给存储过程,以便在不存在值的情况下将它们插入到另一个表中

CREATE TYPE StringList_TBLType AS TABLE (s NVARCHAR(255) NOT NULL PRIMARY KEY)
我想在一个存储过程中执行以下操作,其中传入一个ProductName和类别名称的StringList\u TBLType

  • 从我的字符串列表中选择所有字符串\u TBLType
  • 如果该字符串不存在,请将其插入类别表中
  • 获取插入或已存在类别的ID
  • 将ProductId和CategoryId插入链接表

  • 我可能会努力工作,但我对MS SQL和一般的存储过程几乎没有经验,我担心我最终会编写一种效率非常低的方法来完成这项工作。

    您可以使用
    MERGE
    语句来捕获类别ID

    DECLARE @changes TABLE  (ChangeID VARCHAR(10), Id INTEGER);
    DECLARE @JustSomeRandomVariable INT;
    
    MERGE Category AS TARGET
    USING @data AS SOURCE
        ON TARGET.Category = SOURCE.s
    WHEN NOT MATCHED THEN
        INSERT ([Category])
        VALUES (SOURCE.s)
    WHEN MATCHED THEN 
        UPDATE SET @JustSomeRandomVariable = 1
    OUTPUT $action, inserted.Id INTO @changes;
    
    merge语句中的随机变量确保更新被记录到@changes表变量中

    现在您可以使用@changes更新链接表

    INSERT INTO Link SELECT ProductID, ChangeID FROM @changes
    
    只需通过简单的select查询检索所需的ProductID

    编辑:

    这可能会导致链接表中出现双记录。您可能需要对其进行一些调整,也可以使用MERGE语句插入到链接表中


    @数据是您的过程的StringList\u TBLType参数。

    这是我的建议(未测试)


    我会避免使用游标,除非没有其他方法。如果你真的需要游标,那么如果你想在T-SQL中解决它,你需要三思。一般来说,它们需要更多的代码(更难维护),而且性能更差。有趣的是。。。以前从未听说过merge,但经过一些阅读,@changes表似乎只有新类别的id?我还需要现有类别的ID,因为两者都需要进入链接表我为自己做了一个测试(SQL Server 2008 R2),通过添加分配的太
    @JustSomeRandomVariable
    进行更新,它还捕获@changes中的更新。啊,听起来我应该试一试,看看会发生什么!JodyT,我花了一段时间才让它工作起来,因为我的存储过程有141行长,而且我对它还不熟悉。这是令人沮丧的,但我学到了很多,并感谢您的帮助,这样一个优雅的解决方案!非常感谢。如果您使用相同的产品和一个或多个相同类别调用存储过程两次,那么它也会将它们插入
    链接
    表两次。除非您自己检查
    链接中是否已经存在该关系。
    
    CREATE PROCEDURE AddProductToCategories 
    @productname nvarchar(255),
    @categories StringList_TBLType READONLY
    AS
    BEGIN
    
    DECLARE @productId bigint --change to datatype of Product.ProductId
    SET @productId = (SELECT TOP 1 ProductId FROM Product WHERE ProductName = @productname) --What to do if your product names are not unique?
    
    IF @productId is not NULL
    BEGIN
    
    DECLARE cur CURSOR FOR (
        SELECT cat.CategoryName, cat.CategoryId, c.s
        FROM @categories c
            RIGHT OUTER JOIN Category cat on c.s = cat.CategoryName
    )
    
    DECLARE @id as bigint --change to datatype of Category.CategoryId
    DECLARE @name as nvarchar(255) --change to datatype of Category.CategoryName
    DECLARE @categoryNameToAdd as nvarchar(255)
    
    OPEN cur
    FETCH NEXT FROM cur INTO @name, @id, @categoryNameToAdd
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF @id is NULL
        BEGIN
            --category does not exist yet in table Category
            INSERT INTO Category (CategoryName) VALUES (@categoryNameToAdd)
            SET @id = SCOPE_IDENTITY()
        END
    
        INSERT INTO ProductsCategories --your link table
        (ProductId, CategoryId)
        VALUES
        (@productId, @id) 
    
    
        FETCH NEXT FROM cur INTO @name, @id, @categoryNameToAdd
    END --cursor
    
    
    CLOSE cur
    DEALLOCATE cur
    END --IF @productId
    END --sproc