2015-05-21 39 views
0

在我的SP我有TVP類型包括產品信息,如,與臨時表中的行一樣多執行SP?

Name Desc Visible Tags 

這TVP包括n行。我將這n行插入到我的產品表中,並將帶有標籤列的插入的ID列放入臨時表中。插入後,我需要執行我的SP對每個插入的產品,

EXEC [InsertOrUpdateTags] 

意味着我需要執行該SP多次行的臨時表的數量,並通過插入的標識。我怎樣才能做到這一點?這裏是我的SP

  ALTER PROCEDURE [dbo].[InsertOrUpdateTags] 
      (
       @ProductId INT 
       ,@Tags NVARCHAR(225) 
      ) 
      AS 
      BEGIN 

       SET NOCOUNT ON; 
       DECLARE @TranCount INT; 
       SET @TranCount = @@TRANCOUNT; 

       BEGIN TRY 
        IF @TranCount = 0 
         BEGIN TRANSACTION 
        ELSE 
         SAVE TRANSACTION InsertOrUpdateTags; 


        DECLARE @Tag TABLE(Name NVARCHAR(50)); 

        DECLARE @TagIds TABLE(Id INT) 

        INSERT INTO @Tag 
        SELECT Items FROM dbo.Split(@Tags,','); 

        MERGE Tags AS D 
        USING (SELECT Name FROM @Tag) S 
         ON D.Name = S.Name 
        WHEN NOT MATCHED THEN 
         INSERT(Name) 
         VALUES(S.Name) 
        WHEN MATCHED THEN 
         UPDATE 
          SET Name = S.Name 
        OUTPUT INSERTED.ID INTO @TagIds; 

        -- Delete the one which was available before but not now 
        DELETE FROM ProductsTags WHERE BaseProductId = @ProductId AND TagId NOT IN (SELECT Id FROM @TagIds); 

        MERGE ProductsTags AS D 
        USING (SELECT Id FROM @TagIds) S 
         ON D.TagId = S.Id AND D.BaseProductId = @ProductId 
        WHEN NOT MATCHED THEN 
         INSERT(BaseProductId, TagId) 
         VALUES(@ProductId, S.Id); 


LBEXIT: 
        IF @TranCount = 0 
         COMMIT; 
        END TRY 
       BEGIN CATCH 
        DECLARE @Error INT, @Message VARCHAR(4000), @XState INT; 
        SELECT @Error = ERROR_NUMBER() ,@Message = ERROR_MESSAGE() ,@XState = XACT_STATE(); 

        IF @XState = -1 
         ROLLBACK; 
        IF @XState = 1 AND @TranCount = 0 
         rollback 
        IF @XState = 1 AND @TranCount > 0 
         ROLLBACK TRANSACTION InsertOrUpdateTags; 

        RAISERROR (' InsertOrUpdateTags: %d: %s', 16, 1, @error, @message) ; 
       END CATCH 
      END 
+1

我想你想要一個'while'循環:https://msdn.microsoft.com/en-us/library/ms178642.aspx。 –

+0

@GordonLinoff,你的意思是光標 – user960567

+0

要麼工作! – Ric

回答

2

你可以做一個CROSS APPLYSplit獲得的產品標籤所有列表表中的變量,並在所有的合併報表使用表變量。 就是這樣。

DECLARE @TempProduct TABLE(ProductID INTTagName VARCHAR(100)) 
    INSERT INTO @TempProduct(ProductID,TagName) 
    SELECT ProductID,S.Items 
    FROM #TempTable CROSS APPLY dbo.Split(Tags,',') S; 

    MERGE Tags AS D 
    USING (SELECT DISTINCT TagName FROM @TempProduct) S 
     ON D.Name = S.Name 
    WHEN NOT MATCHED THEN 
     INSERT(Name) 
     VALUES(S.Name) 
    WHEN MATCHED THEN 
     UPDATE 
      SET Name = S.Name 
    OUTPUT INSERTED.ID,Inserted.Name INTO @TagIds(ID,Name); 

    -- Delete the one which was available before but not now 
    DELETE FROM ProductsTags 
    WHERE NOT EXISTS (SELECT 1 FROM @TempProduct TP INNER JOIN @TagIds TS ON TP.TagName = TS.TagName WHERE TP.ProductID = BaseProductId AND TS.ID= ProductsTags.TagId); 

    MERGE ProductsTags AS D 
    USING (SELECT TP.ProductID,TS.ID FROM @TempProduct TP INNER JOIN @TagIds TS ON TP.TagName = TS.TagName) S 
     ON D.TagId = S.ID AND D.BaseProductId = ProductID 
    WHEN NOT MATCHED THEN 
     INSERT(BaseProductId, TagId) 
     VALUES(ProductID, TagID); 


LBEXIT: 
    IF @TranCount = 0 
     COMMIT; 
    END TRY 
BEGIN CATCH 
    DECLARE @Error INT, @Message VARCHAR(4000), @XState INT; 
    SELECT @Error = ERROR_NUMBER() ,@Message = ERROR_MESSAGE() ,@XState = XACT_STATE(); 

    IF @XState = -1 
     ROLLBACK; 
    IF @XState = 1 AND @TranCount = 0 
     rollback 
    IF @XState = 1 AND @TranCount > 0 
     ROLLBACK TRANSACTION InsertOrUpdateTags; 

    RAISERROR (' InsertOrUpdateTags: %d: %s', 16, 1, @error, @message) ; 
END CATCH 
END 

注:這是這裏直接寫入,可能有一些問題。

希望這會有所幫助。

+0

謝謝。但會檢查 – user960567

+0

WHERE NOT EXISTS(SELECT 1 FROM @TempProduct TP WHERE TP.ProductID = BaseProductId AND TP.TagId = TP.TagId); '此行有錯誤 – user960567

+0

但TempProduct不包含TagId – user960567