如何在sqlcmd中輸出超過4000個字元
我製作了一個儲存過程
restoredatabase
,它返回程式碼以恢復數據庫。輸出腳本如下所示:restore database [DB] from disk='F:\FULL1.bak' with norecovery restore database [DB] from disk='F:\DIFF1.bak' with norecovery restore log [DB] from disk='F:\log1.bak' with norecovery restore log [DB] from disk='F:\log2.bak' with norecovery ... restore log [DB] from disk='F:\logN.bak' with norecovery restore database [DB] with recovery
在整個 SP 中,這些行被添加到一個參數
@sql varchar(max)
中,最後用 列印print(@sql)
,如果使用者指定了正確的標誌,則用 執行exec(@sql)
。兩者都完美地工作。但是,當像這樣使用 sqlcmd 呼叫 SP 時:set restoresql=exec restoredatabase @DB='Databasename', @Execute='y' sqlcmd -h-1 -S SRV\T2 -U sa -P sa -d master -Q "%restoresql%" -o output.txt
輸出文件
output.txt
將始終最多包含 4002 個字元。我試過添加
-y 8000
,但這沒有幫助。如何獲取輸出文件以提供完整的生成腳本?
需要明確的是,問題實際上出在
SQLCMD
實用程序上。我猜你的變數實際上是
NVARCHAR(MAX)
,而不是VARCHAR(MAX)
因為NCHAR
/的 4000 個字元NVARCHAR
。NVARCHAR
否則,它可以使用/輸出最多 8000 個字元CHAR
。要查看VARCHAR
超過 4000 個字元但不超過 8000 個字元,請執行以下命令:sqlcmd -Q "DECLARE @Yo VARCHAR(MAX) = REPLICATE(CONVERT(VARCHAR(MAX), '#'), 9000); PRINT @Yo;" -o out.txt
如果您需要列印超過 8000 個字元,那麼您需要以最多 8000 個字元的塊迭代變數(該
CHAR
/個VARCHAR
字元)。但是您不想簡單地將其切成 8000 個字元塊,因為這可能位於不應拆分的內容的中間,例如單詞/對象名稱/編號等。因為該嘗試使用以下 proc 代替您的
print(@sql)
命令(僅供參考:您不需要像@sql
forEXEC
)。請注意,在字元串中查找最後一個換行符需要創建一個LastIndexOf
函式,因為 T-SQL 中沒有內置函式。您可以創建一個 T-SQL UDF 來執行此操作。您也可以使用 SQLCLR,在這種情況下,您可以自己編寫程式碼,或者直接獲取免費版本的SQL#庫(我是該庫的作者)。SET ANSI_NULLS, QUOTED_IDENTIFIER ON; IF (OBJECT_ID(N'dbo.Display') IS NOT NULL) BEGIN DROP PROCEDURE dbo.Display; END; GO CREATE PROCEDURE dbo.Display ( @TextToDisplay VARCHAR(MAX) ) AS SET NOCOUNT ON; DECLARE @Length INT = LEN(@TextToDisplay), @Buffer VARCHAR(8000), @BufferLength INT, @StartIndex INT = 1, @LastNewlineIndex INT; SET @TextToDisplay = REPLACE(@TextToDisplay, CHAR(13), ''); -- normalize WHILE (1 = 1) BEGIN SET @Buffer = SUBSTRING(@TextToDisplay, @StartIndex, 8000); SET @BufferLength = DATALENGTH(@Buffer); IF (@BufferLength < 8000) BEGIN BREAK; END; SET @LastNewlineIndex = SQL#.String_LastIndexOf(@Buffer, CHAR(10), @BufferLength, 1); IF (@LastNewlineIndex > 0) BEGIN PRINT SUBSTRING(@Buffer, 1, (@LastNewlineIndex - 1)); SET @StartIndex += @LastNewlineIndex; END; ELSE BEGIN PRINT @Buffer; SET @StartIndex += @BufferLength; END; END; -- WHILE (1 = 1) -- Don't print empty line if final chunk was 8000 chars leaving final loop with 0 IF (DATALENGTH(@Buffer) > 0) BEGIN PRINT @Buffer; END; GO
測試:
DECLARE @Test VARCHAR(MAX); SET @Test = ''; SET @Test = @Test + '1' + REPLICATE('a', 7998) + '1'; SET @Test = @Test + '2' + REPLICATE('b', 7998) + '2'; SET @Test = @Test + '3' + REPLICATE('c', 7998) + '3'; SELECT @Test; PRINT '============================='; EXEC dbo.Display @Test; PRINT '============================='; ---- SET @Test = ''; SET @Test = @Test + '1' + REPLICATE('a', 7998) + '1'; SET @Test = @Test + '2' + REPLICATE('b', 7998) + '2'; SET @Test = @Test + '3' + REPLICATE('c', 7000) + '3'; SELECT @Test; PRINT '============================='; EXEC dbo.Display @Test; PRINT '============================='; ---- SET @Test = ''; SET @Test = @Test + '1.1' + REPLICATE('a', 7000) + '1.1' + CHAR(13) + CHAR(10); SET @Test = @Test + '1.2' + REPLICATE('a', 400) + '1.2' + CHAR(13) + CHAR(10); SET @Test = @Test + '1.3' + REPLICATE('a', 4000) + '1.3' + CHAR(13) + CHAR(10); SET @Test = @Test + '2' + REPLICATE('b', 1798) + '2' + CHAR(13) + CHAR(10); SET @Test = @Test + '3' + REPLICATE('c', 7000) + '3'; SELECT @Test; PRINT '============================='; EXEC dbo.Display @Test; PRINT '=============================';
筆記:
- 您可以使用內置
CHARINDEX
函式來查找每個下一個換行符,在這方面它的功能幾乎就像使用字元串拆分函式一樣。此處需要的內容與在換行符上進行簡單拆分之間的區別在於,返回的任何超過 8000 個字元的元素仍需要拆分為不超過 8000 個字元的塊。- 為了處理
NVARCHAR(MAX)
而不是VARCHAR(MAX)
,請使用我發佈到 PasteBin 的程式碼:T-SQL Stored Proc to PRINT NVARCHAR(MAX) valuesUtil_Print
SQL# 庫中有一個儲存過程 ,它處理NVARCHAR(MAX)
並具有一些超出上面顯示的 T-SQL 程式碼的功能,但這僅在完整(即付費)版本中可用,在免費版本中不可用。但是這裡顯示的程式碼將處理大多數情況。