查詢中的大字元串連接
我正在嘗試在 T-SQL 中連接字元串,例如
'This is a test ' + CHAR(13) + CHAR(10) + ' string'
當字元串很長時(我不知道限制),我得到一個錯誤:
您的 SQL 語句的某些部分嵌套得太深。重寫查詢或將其分解為更小的查詢。
我該如何解決這個問題?SQL 語句是如何“嵌套”的?
我應該切換到 0x 嗎????如果字元串長度超過某個值,則表示法?
這個問題在 10 年前被問到
沒有得到滿意的答复。
編輯
- 要插入的總字元串(帶有連接和 ‘:s)是 369711 個字元長。
- 有 6301 個
char(13)
和相同的實例char(10)
。- 有 19050 個實例
+
,不一定都用作連接運算符。
這可能取決於“太長”的含義:
- **長度:**如果您的意思是許多字元的字元串,那麼嘗試將其中一些轉換為一種
MAX
類型(即NVARCHAR(MAX)
或VARCHAR(MAX)
)。例如:CONVERT(VARCHAR(MAX), 'This is a test ') + CHAR(13) + CHAR(10) + ' string'
- **連接:**如果您的意思是涉及許多連接的操作,那麼在單個語句中肯定有一個最大數量可以完成。我前段時間對此進行了測試,並打算在部落格上討論它,但分心了;-)。我剛剛回顧了我的測試,雖然有幾種不同的連接方法,但最簡單的方法(這就是你正在做的)每個語句的限制約為 3300。我說“大約” 3300 是因為它會根據與記憶體相關的其他一些因素而有所不同。有時我可以得到 3310,然後我嘗試了 3311,它可以工作,再試一次,它失敗,用 3310 再試一次,它失敗,再用 3309 再試一次,它可以工作。
如果你有超過這個數量,那麼你別無選擇,只能將操作分成多個步驟(即多個
SET
/SELECT
語句)。雖然,這里達到最大值的錯誤是:消息 8631,級別 17,狀態 1,行 XXXX
內部錯誤:已達到伺服器堆棧限制。請在您的查詢中尋找潛在的深層嵌套,並嘗試簡化它。
而且您並沒有完全做到這一點,因此在您進行更多測試或至少提供錯誤號之前還不能完全確定。在任何一種情況下,您都可以通過將“\r”和“\n”組合成單個變數或
VARBINARY
文字來減少串聯的數量。以下範例顯示兩種方法產生相同的輸出:PRINT 'This is a test ' + CHAR(13) + CHAR(10) + ' string'; PRINT '-----------------------------'; PRINT 'This is a test ' + CONVERT(CHAR(2), 0x0D0A) + ' string'; PRINT '-----------------------------'; DECLARE @CRLF CHAR(2) = CHAR(13) + CHAR(10); PRINT 'This is a test ' + @CRLF + ' string';
該變數的好處是它更短,這有助於使大型腳本更具可讀性而不是那麼大。但是,您不能突出顯示一條或多條隨機行並執行,除非您還突出顯示
DECLARE
但可能並不總是有效。文字的好處VARBINARY
是您可以輕鬆執行隨機分組的語句,或將語句移動到該腳本的其他腳本/部分,而不必擔心忘記DECLARE
. 在任何一種情況下,這可能會減少數百個串聯(假設您已經有大約 3300 個串聯),但如果您獲得需要數百個串聯的字元串值,它不會阻止錯誤。也很可能有一種不同和/或更簡單的方法來完成您最終嘗試完成的工作,而不依賴於串聯。因此,如果您可以更新問題以指定您首先這樣做的原因,這將有所幫助:-)。
有 6301 個
char(13)
和相同的實例char(10)
。給定每組“CR”+“LF”的三個串聯(即
+ CHAR(13)
一個、+ CHAR(10)
兩個和+ '...'
第三個),即有 18,903 個串聯。是的,這有點超過 3300 ;-)。我希望這些
insert into
陳述是單行的。行。但為什麼?你實際上從中獲得了什麼?嵌入式 CRLF 非常適合插入。
還:
- 這些數據的來源是什麼?它來自 SQL Server 嗎?
- 是字元串
VARCHAR
還是NVARCHAR
?在問題的範例中,它只是VARCHAR
,但在對問題的評論中,您給出了將VARBINARY
文字轉換為 的範例NVARCHAR
。在任何一種情況下,執行我上面提到的兩種方法中的任何一種來減少每個 CRLF 的兩個部分之一的連接都無濟於事,因為這仍然會給您留下 12,602 個連接。所以,你有兩個選擇:
使用替換/轉義序列在對該問題的評論中,Martin Smith 建議使用
{crlf}
. 我的偏好是以下之一:
CHAR(31)
:這是不可列印的“單位分隔符”字元。它只是一個字節,不太可能出現在您的字元串數據中,如果您不小心更改了編碼,也不會轉換為其他內容。不幸的是,它的可讀性不是很好,因為它甚至不會顯示為空格,因此它分隔的單詞之間似乎沒有任何內容。PRINT REPLACE('one' + CHAR(31) + 'two', CHAR(31), CHAR(13)+CHAR(10));
`'\n'`:這是幾乎通用的“換行符”轉義序列。這是兩個字節,絕對更具可讀性。
INT REPLACE('one\ntwo', '\n', CHAR(13)+CHAR(10)); `無論哪種情況,您只需`INSERT INTO Schema.Table (Column) VALUES (REPLACE(....));` 2. 將整個字元串轉換為`VARBINARY`: 這會產生一個非常便攜的單行值。這是不可讀的,但也不會有任何意外的字元轉換,您可以使用標準的 ANSI/程式碼頁 1252 文件編碼,而您需要使用 UTF-8(帶簽名/BOM)或 Unicode / UTF-16(帶簽名 / BOM)用於文件編碼,如果字元串數據是 Unicode / `NVARCHAR`. 您在對該問題的評論中提到了有關擁有字節數組的內容。如果數據的來源是 .NET,那麼字元串數據已經是 UTF-16 LE(即`NVARCHAR`),所以只要做`INSERT INTO Schema.Table (Column) VALUES (0x{hex_from_byte[]});`就可以了。如果目標是一`VARCHAR`列,那麼您可以: 使用以下內容在 .NET 中進行轉換:`Encoding.GetEncoding(1252).GetBytes(_StringVariable)` 使用 T-SQL 轉換:`INSERT INTO Schema.Table (Column) VALUES (CONVERT(NVARCHAR(MAX), 0x{hex_from_byte[]}));`. 請注意,我們正在轉換為,`NVARCHAR`因為十六進製表示是 UTF-16 LE。函式的返回值將在插入列時`CONVERT`隱式轉換為。`VARCHAR`