簡體   English   中英

無法使用NVARCHAR(Max)創建完整的動態查詢

[英]Unable to Create the Complete Dynamic Query using NVARCHAR(Max)

我正在使用NVARCHAR(MAX)創建動態查詢。由於NVARCHAR每個字符使用2個字節,因此NVARCHAR(MAX)變量(鏈接參考)中可以包含大約10億個字符。

我嘗試通過在SQL Server本身中執行存儲過程,然后通過應用程序執行存儲過程來進行嘗試。

兩種情況的動態查詢都不會超過那些字符的長度。 但是只執行動態查詢的一部分,因為該存儲過程向應用程序拋出錯誤。

我是否缺少任何代碼?

USE [MyDemoDB]
GO

ALTER PROCEDURE [dbo].[sp_Apply]
(
        @scenarioId INT,
        @userId INT,
        @bookId INT
) 
AS

        DECLARE @BucketId           INT
        DECLARE @HierarchyId        NVARCHAR(10)
        DECLARE @Year               INT
        DECLARE @Month              INT
        DECLARE @PlanningSeason     NVARCHAR(20)
        DECLARE @StructureId        INT = 9
        DECLARE @AllocStructureId   INT = 11
        DECLARE @UpdatedUser        INT = 2
        DECLARE @InsertOne          NVARCHAR(MAX)=''
        DECLARE @AreaSchema         NVARCHAR(40)
        DECLARE @AreaCode           NVARCHAR(20)
        DECLARE @EmptyValue         NVARCHAR(20)

        SET @AreaCode   = ''
        SET @AreaSchema = '[dbo]'


          SET @InsertOne =      '
                                   DECLARE @FGSupplySeqId      INT
                                   DECLARE @FGSupplyId         NVARCHAR(10)
                                   DECLARE @PlannedQty         DECIMAL(18,2)
                                   DECLARE @ConfirmdQty        DECIMAL(18,2)
                                   DECLARE @Year                INT 
                                   DECLARE @Month               INT
                                   DECLARE @Season              NVARCHAR(20)
                                   DECLARE @MerchantId          NVARCHAR(50) 
                                   DECLARE @UpdatedUser     INT 
                                   DECLARE @HierarchyId     NVARCHAR(10) 
                                   DECLARE @BucketId        INT
                                   DECLARE @ProductNo       NVARCHAR(100)
                                   DECLARE @LocationNo      NVARCHAR(100) 

                                   SET @BucketId            = '+ CAST(@BucketId AS VARCHAR) + '
                                   SET @UpdatedUser         = '+ CAST(@userId AS VARCHAR) + '

                       IF @BucketId = 1 
                       BEGIN
                                   DECLARE Supplys
                                   CURSOR FOR 
                                   SELECT [FGSupplySeqId],[FGSupplyId] FROM ' + @AreaSchema + '.[FGSupply]
                                   WHERE  PlanningScenarioId ='+ CONVERT(VARCHAR(10),@scenarioId)+ '

                                   OPEN Supplys
                                   FETCH NEXT 
                                   FROM Supplys 
                                   INTO @FGSupplySeqId,@FGSupplyId

                                           WHILE @@FETCH_STATUS = 0 
                                           BEGIN

                                                DECLARE Allocations
                                                CURSOR FOR  
                                                SELECT @FGSupplyId,FGHierarchyId,MerchantNo,PlannedQty,ConfirmedQty,Year,Season,ProductNo,LocationNo
                                                FROM  '+ @AreaSchema +'.[FGAllocation]
                                                WHERE FGSupplySeqId = @FGSupplySeqId

                                                OPEN Allocations
                                                FETCH NEXT 
                                                FROM Allocations 
                                                INTO @FGSupplyId,@HierarchyId,@MerchantId,@PlannedQty,@ConfirmdQty,@Year,@Season,@ProductNo,@LocationNo

                                                     WHILE @@FETCH_STATUS = 0 
                                                     BEGIN

                                                         DECLARE @FGAllocationId  NVARCHAR(10)
                                                         DECLARE @AllocStatus  INT
                                                         SET @FGAllocationId = ''E''
                                                         SET @AllocStatus= 0

                                                          SELECT @FGAllocationId = FGAllocationId,@AllocStatus=Status
                                                          FROM ' + @AreaSchema+'.[SN_PLANNING_FGAllocation]
                                                          WHERE [HierarchyId]=@HierarchyId AND  [MerchantNo]=@MerchantId AND YEAR = @Year AND [Month] IS NULL


                                                          IF @FGAllocationId = ''E''
                                                          BEGIN

                                                          -- IF  @AllocStatus <> 5

                                                          INSERT INTO'+ @AreaSchema+'.[SN_PLANNING_FGAllocation]
                                                         (FinishedGoodSupplyId,FGHierarchyId,MerchantNo,PlannedQty,Year,Season,Status,IsActive,CreatedBy,UpdatedBy,CreatedOn,UpdatedOn,ProductNo,LocationNo)
                                                         VALUES(@FGSupplyId,@HierarchyId,@MerchantId,@PlannedQty,@Year,@Season,0,1,@UpdatedUser,@UpdatedUser,GETDATE(),GETDATE(),@ProductNo,@LocationNo)

                                                         END
                                                         ELSE 
                                                         BEGIN
                                                            -- IF  @AllocStatus <> 5
                                                                    UPDATE ' + @AreaSchema + '.[SN_PLANNING_FGAllocation] 
                                                                    SET PlannedQty = @PlannedQty ,ConfirmedQty=@ConfirmdQty,UpdatedBy=@UpdatedUser, UpdatedOn=GETDATE()
                                                                    WHERE FGAllocationId = @FGAllocationId

                                                         END
                                                           FETCH NEXT 
                                                           FROM Allocations 
                                                           INTO @FGSupplyId,@HierarchyId,@MerchantId,@PlannedQty,@ConfirmdQty,@Year,@Season,@ProductNo,@LocationNo
                                                     END

                                                 CLOSE Allocations
                                                 DEALLOCATE Allocations

                                               FETCH NEXT 
                                               FROM Supplys 
                                               INTO @FGSupplySeqId,@FGSupplyId
                                          END

                                   CLOSE Supplys
                                   DEALLOCATE Supplys
                    END

                    IF @BucketId = 2 
                       BEGIN
                                   DECLARE Supplys
                                   CURSOR FOR 
                                   SELECT [FGSupplySeqId],[FGSupplyId] FROM ' + @AreaSchema + '.[FGSupply]
                                   WHERE  PlanningScenarioId ='+ CONVERT(VARCHAR(10),@scenarioId)+ 'AND Month IS NOT NULL

                                   OPEN Supplys
                                   FETCH NEXT 
                                   FROM Supplys 
                                   INTO @FGSupplySeqId,@FGSupplyId

                                           WHILE @@FETCH_STATUS = 0 
                                           BEGIN

                                                DECLARE Allocations
                                                CURSOR FOR  
                                                SELECT @FGSupplyId,FGHierarchyId,MerchantNo,PlannedQty,ConfirmedQty,Year, Month,Season,@ProductNo,@LocationNo
                                                FROM  '+ @AreaSchema +'.[FGAllocation]
                                                WHERE FGSupplySeqId = @FGSupplySeqId AND Month IS NOT NULL

                                                OPEN Allocations
                                                FETCH NEXT 
                                                FROM Allocations 
                                                INTO @FGSupplyId,@HierarchyId,@MerchantId,@PlannedQty,@ConfirmdQty,@Year,@Month,@Season,@ProductNo,@LocationNo

                                                     WHILE @@FETCH_STATUS = 0 
                                                     BEGIN

                                                          DECLARE @FGAllocationId1  NVARCHAR(10)
                                                         SET @FGAllocationId1 = ''E''

                                                          SELECT @FGAllocationId1 = FGAllocationId,@AllocStatus=Status
                                                          FROM ' + @AreaSchema+'.[SN_PLANNING_FGAllocation]
                                                          WHERE [HierarchyId]=@HierarchyId AND  [MerchantNo]=@MerchantId AND YEAR = @Year AND [Month] = @Month

                                                          IF @FGAllocationId1 = ''E''

                                                          BEGIN
                                                         --  IF  @AllocStatus <> 5
                                                          INSERT INTO'+ @AreaSchema+'.[SN_PLANNING_FGAllocation]
                                                         (FGSupplyId,FGHierarchyId,MerchantNo,PlannedQty,Year,Month,Season,Status,IsActive,CreatedBy,UpdatedBy,CreatedOn,UpdatedOn,ProductNo,LocationNo)
                                                         VALUES(@FGSupplyId,@HierarchyId,@MerchantId,@PlannedQty,@Year,@Month,@Season,0,1,@UpdatedUser,@UpdatedUser,GETDATE(),GETDATE(),@ProductNo,@LocationNo)
                                                          END
                                                         ELSE 
                                                         BEGIN
                                                         -- IF  @AllocStatus <> 5
                                                                    UPDATE ' + @AreaSchema + '.[SN_PLANNING_FGAllocation] 
                                                                    SET PlannedQty = @PlannedQty ,ConfirmedQty=@ConfirmdQty,UpdatedBy=@UpdatedUser, UpdatedOn=GETDATE()
                                                                    WHERE FGAllocationId = @FGAllocationId1

                                                         END
                                                           FETCH NEXT 
                                                           FROM Allocations 
                                                           INTO @FGSupplyId,@HierarchyId,@MerchantId,@PlannedQty,@ConfirmdQty,@Year,@Month,@Season,@ProductNo,@LocationNo
                                                     END

                                                 CLOSE Allocations
                                                 DEALLOCATE Allocations

                                               FETCH NEXT 
                                               FROM Supplys 
                                               INTO @FGSupplySeqId,@FGSupplyId
                                          END

                                   CLOSE Supplys
                                   DEALLOCATE Supplys
                    END'

         print @InsertOne
        EXEC(@InsertOne)
  • 確保您的變量不包含引號或雙引號。

     declare @value nvarchar(100) = 'abcd''efgh' declare @sql nvarchar(max) -- tons of QUOTE !!! Set @sql = N'select ''' + REPLACE(@value, '''', '''''') + ''''; print @sql exec sp_executesql @sql 
  • 在您的對象名稱周圍加上括號,並在into和DB之間至少留一個空格:

     INSERT INTO'+ @AreaSchema+'.[SN_PLANNING_FGAllocation] -- space is missing 

    或者您可以使用QUOTENAME函數QUOTENAME(@AreaSchema)

  • 使用N''和NVARCHAR(...)或''和VARCHAR()但不要混合使用

您將所有內容聲明為NVARCHAR,然后將其與''連接。 它應該是N''。 您還可以將所有內容轉換/轉換為VARCHAR。 它應該是NVARCHAR(...)。 動態SQL使用NVARCHAR字符串。

  • 確保設置了變量或具有默認值

     SET @BucketId = '+ CAST(@BucketId AS nVARCHAR) + ' 

由於未在存儲過程中設置@BucketId,因此將返回NULL。 使用ISNULL,設置它或給它一個默認值

僅在需要時才進行串聯(動態對象名稱)

  • 最后

在嘗試執行它之前,請確保您的打印輸出正確的查詢(打印僅顯示第1個4000個字符)。 如果查詢不完整,則可能意味着您在停止行附近的代碼中有錯誤。 我嘗試了您的proc,除非我首先初始化所有變量,否則它將不返回任何內容(NULL)。 由於不使用N,也存在截斷現象''

是的,由於nvarchar限制為4000個字符,您可能會遇到此問題。

我也遇到這個問題,並通過連接字符串然后執行來解決。

如果選擇或打印,則僅顯示4000個字符,但是如果連接或附加字符串,則必須附加(直到8000個字符)。 因此,不必為此而煩惱,您不會打印或選擇僅追加並執行及其絕對有效的方法。

在此鏈接中進行解釋。

declare @sql Nvarchar(max),
   @a nvarchar(max),
   @b nvarchar(max);

select @sql =N'', @a = N'a', @b = N'b';

select @sql = @sql +replicate(@a,4000) + replicate(@b, 6000);

select len(@sql)

一個規則

SET @dynamicSQL = [連接各種unicode字符串和總共超過4000個字符的nvarchar變量] –確保UNICODE字符串中至少有一個是NVARCHAR(MAX),您可以使用任何一個參數。

您也可以檢查此鏈接。

https://dba.stackexchange.com/questions/18483/varcharmax-field-cutting-off-data-after-8000-characters-sql-server-2008

更新后,我將顯示您的整個代碼,並希望解釋一些事情。

  1. 首先,為什么要動態查詢。 代碼顯示您可以在沒有動態查詢的情況下執行此操作,並且嵌套的游標太多(嘗試通過簡單查詢忽略它)

  2. 仍然,如果您想去,那么我將為您刪除多余的代碼(我認為刪除空間將不起作用,我有4個聯合查詢,其長度非常大,並且在單獨的窗口中驗證了每個部分后使用了該策略)

在您閱讀以下內容之前,這里是另一種選擇。 而不是在查詢中定義參數,您也可以傳遞此參數。

begin tran
create table table1 ( id int, value varchar(10) )
insert into table1 values( 1,'001')
insert into table1 values(2, '002')
insert into table1 values( 3,'003')
insert into table1 values( 4,'004')

declare @sql nvarchar(max) , @temp nvarchar(50) = '1,2,3', @tempIntSingleValue nvarchar(50) = '2'
select * from table1

set @sql = 'select * from table1 where id in ( ' + @temp + ')'
print @sql
exec sp_executesql @sql 

set @sql = 'select * from table1 where id in ( @tempInner)'
print @sql
exec sp_executesql @sql , N'@tempInner int', @tempInner = @tempIntSingleValue

rollback

您在動態查詢中使用了相同的參數。 所以我認為您的問題是必須在運行時提供默認值或分配值。 因此在連接字符串時不會變為null。 請參見下面的示例。 我將所有字符定義為'',並將int定義為數值,最后打印出可打印內容的字符。 如果沒有定義,則由於連接設置為null值,因此永遠不要打印空白。

declare @scenarioId INT = 1 ,
        @userId INT = 5,
        @bookId INT = 1

 DECLARE @BucketId           INT = 0
        DECLARE @HierarchyId        NVARCHAR(10)
        DECLARE @Year               INT
        DECLARE @Month              INT
        DECLARE @PlanningSeason     NVARCHAR(20)
        DECLARE @StructureId        INT = 9
        DECLARE @AllocStructureId   INT = 11
        DECLARE @UpdatedUser        INT = 2
        DECLARE @InsertOne          NVARCHAR(MAX) =''
        DECLARE @AreaSchema         NVARCHAR(40)
        DECLARE @AreaCode           NVARCHAR(20)
        DECLARE @EmptyValue         NVARCHAR(20)

        SET @AreaCode = ''
        SET @AreaSchema = '[dbo]'

         SET @InsertOne =      
         'DECLARE @FGSupplySeqId INT = 5
         DECLARE @FGSupplyId NVARCHAR(10) = ''''
         DECLARE @PlannedQty DECIMAL(18,2) = ''''
         DECLARE @ConfirmdQty DECIMAL(18,2) = ''''
         DECLARE @Year INT = 2015
         DECLARE @Month INT = 7
         DECLARE @Season NVARCHAR(20) = ''''
         DECLARE @MerchantId NVARCHAR(50)  = ''''
         DECLARE @UpdatedUser INT 
         DECLARE @HierarchyId NVARCHAR(10) = ''''
         DECLARE @BucketId INT = 0
         DECLARE @ProductNo NVARCHAR(100)= ''''
         DECLARE @LocationNo NVARCHAR(100) 

         SET @BucketId = '+ CAST(@BucketId AS VARCHAR) + '
         SET @UpdatedUser = '+ CAST(@userId AS VARCHAR) + '

         IF @BucketId = 1 
         BEGIN
          DECLARE Supplys
          CURSOR FOR 
          SELECT [FGSupplySeqId],[FGSupplyId] FROM ' + @AreaSchema + '.[FGSupply]
          WHERE  PlanningScenarioId ='+ CONVERT(VARCHAR(10),@scenarioId)+ '

          OPEN Supplys
          FETCH NEXT 
          FROM Supplys 
          INTO @FGSupplySeqId,@FGSupplyId

                  WHILE @@FETCH_STATUS = 0 
                  BEGIN

                       DECLARE Allocations
                       CURSOR FOR  
                       SELECT @FGSupplyId,FGHierarchyId,MerchantNo,PlannedQty,ConfirmedQty,Year,Season,ProductNo,LocationNo
                       FROM  '+ @AreaSchema +'.[FGAllocation]
                       WHERE FGSupplySeqId = @FGSupplySeqId

                       OPEN Allocations
                       FETCH NEXT 
                       FROM Allocations 
                       INTO @FGSupplyId,@HierarchyId,@MerchantId,@PlannedQty,@ConfirmdQty,@Year,@Season,@ProductNo,@LocationNo

   WHILE @@FETCH_STATUS = 0 
   BEGIN

       DECLARE @FGAllocationId  NVARCHAR(10)
       DECLARE @AllocStatus  INT
       SET @FGAllocationId = ''E''
       SET @AllocStatus= 0

        SELECT @FGAllocationId = FGAllocationId,@AllocStatus=Status
        FROM ' + @AreaSchema+'.[SN_PLANNING_FGAllocation]
        WHERE [HierarchyId]=@HierarchyId AND  [MerchantNo]=@MerchantId AND YEAR = @Year AND [Month] IS NULL


        IF @FGAllocationId = ''E''
        BEGIN

        -- IF  @AllocStatus <> 5

        INSERT INTO'+ @AreaSchema+'.[SN_PLANNING_FGAllocation]
       (FinishedGoodSupplyId,FGHierarchyId,MerchantNo,PlannedQty,Year,Season,Status,IsActive,CreatedBy,UpdatedBy,CreatedOn,UpdatedOn,ProductNo,LocationNo)
       VALUES(@FGSupplyId,@HierarchyId,@MerchantId,@PlannedQty,@Year,@Season,0,1,@UpdatedUser,@UpdatedUser,GETDATE(),GETDATE(),@ProductNo,@LocationNo)

       END
       ELSE 
       BEGIN
          -- IF  @AllocStatus <> 5
                  UPDATE ' + @AreaSchema + '.[SN_PLANNING_FGAllocation] 
                  SET PlannedQty = @PlannedQty ,ConfirmedQty=@ConfirmdQty,UpdatedBy=@UpdatedUser, UpdatedOn=GETDATE()
                  WHERE FGAllocationId = @FGAllocationId

       END
         FETCH NEXT 
         FROM Allocations 
         INTO @FGSupplyId,@HierarchyId,@MerchantId,@PlannedQty,@ConfirmdQty,@Year,@Season,@ProductNo,@LocationNo
   END

                        CLOSE Allocations
                        DEALLOCATE Allocations

                      FETCH NEXT 
                      FROM Supplys 
                      INTO @FGSupplySeqId,@FGSupplyId
                 END

          CLOSE Supplys
          DEALLOCATE Supplys
                    END

                    IF @BucketId = 2 
                       BEGIN
          DECLARE Supplys
          CURSOR FOR 
          SELECT [FGSupplySeqId],[FGSupplyId] FROM ' + @AreaSchema + '.[FGSupply]
          WHERE  PlanningScenarioId ='+ CONVERT(VARCHAR(10),@scenarioId)+ 'AND Month IS NOT NULL

          OPEN Supplys
          FETCH NEXT 
          FROM Supplys 
          INTO @FGSupplySeqId,@FGSupplyId

                  WHILE @@FETCH_STATUS = 0 
                  BEGIN

                       DECLARE Allocations
                       CURSOR FOR  
                       SELECT @FGSupplyId,FGHierarchyId,MerchantNo,PlannedQty,ConfirmedQty,Year, Month,Season,@ProductNo,@LocationNo
                       FROM  '+ @AreaSchema +'.[FGAllocation]
                       WHERE FGSupplySeqId = @FGSupplySeqId AND Month IS NOT NULL

                       OPEN Allocations
                       FETCH NEXT 
                       FROM Allocations 
                       INTO @FGSupplyId,@HierarchyId,@MerchantId,@PlannedQty,@ConfirmdQty,@Year,@Month,@Season,@ProductNo,@LocationNo

                       WHILE @@FETCH_STATUS = 0 
                       BEGIN

                            DECLARE @FGAllocationId1  NVARCHAR(10)
                           SET @FGAllocationId1 = ''E''

                            SELECT @FGAllocationId1 = FGAllocationId,@AllocStatus=Status
                            FROM ' + @AreaSchema+'.[SN_PLANNING_FGAllocation]
                            WHERE [HierarchyId]=@HierarchyId AND  [MerchantNo]=@MerchantId AND YEAR = @Year AND [Month] = @Month

                            IF @FGAllocationId1 = ''E''

                            BEGIN
                           --  IF  @AllocStatus <> 5
                            INSERT INTO'+ @AreaSchema+'.[SN_PLANNING_FGAllocation]
                           (FGSupplyId,FGHierarchyId,MerchantNo,PlannedQty,Year,Month,Season,Status,IsActive,CreatedBy,UpdatedBy,CreatedOn,UpdatedOn,ProductNo,LocationNo)
                           VALUES(@FGSupplyId,@HierarchyId,@MerchantId,@PlannedQty,@Year,@Month,@Season,0,1,@UpdatedUser,@UpdatedUser,GETDATE(),GETDATE(),@ProductNo,@LocationNo)
                            END
                           ELSE 
                           BEGIN
                           -- IF  @AllocStatus <> 5
                                      UPDATE ' + @AreaSchema + '.[SN_PLANNING_FGAllocation] 
                                      SET PlannedQty = @PlannedQty ,ConfirmedQty=@ConfirmdQty,UpdatedBy=@UpdatedUser, UpdatedOn=GETDATE()
                                      WHERE FGAllocationId = @FGAllocationId1

                           END
                             FETCH NEXT 
                             FROM Allocations 
                             INTO @FGSupplyId,@HierarchyId,@MerchantId,@PlannedQty,@ConfirmdQty,@Year,@Month,@Season,@ProductNo,@LocationNo
                       END

                        CLOSE Allocations
                        DEALLOCATE Allocations

                      FETCH NEXT 
                      FROM Supplys 
                      INTO @FGSupplySeqId,@FGSupplyId
                 END

      CLOSE Supplys
      DEALLOCATE Supplys
     END'

    print @InsertOne 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM