FOR XML PATH 不适用于 0x001E 字符
FOR XML PATH doesn't work with 0x001E character
我检查过:https://www.red-gate.com/simple-talk/sql/t-sql-programming/concatenating-row-values-in-transact-sql/
所以,我的查询是:
SELECT DISTINCT ID, NAME, DOCTEXT2
FROM DOC
CROSS APPLY (SELECT
Stuff((SELECT ' ' + RTRIM(LTRIM(DOCTEXT))
FROM DOC d
WHERE d.ID=DOC.ID AND d.NAME = DOC.NAME
FOR XML PATH (''), TYPE).value('.','varchar(max)'),1,1,'')
) D (DOCTEXT2)
错误是:
FOR XML could not serialize the data for node 'NoName' because it
contains a character (0x001E) which is not allowed in XML. To retrieve
this data using FOR XML, convert it to binary, varbinary or image data
type and use the BINARY BASE64 directive.
我知道数据中有 0x001E 个字符。我不想替换数据库中的这些数据。
我的数据是:
ID NAME DOCTEXT
12 AB ERROR INSTRUCTIONS
12 CC CRN 70 SS
12 CC DRF 77
12 CC
我想要的是:
ID NAME DOCTEXT
12 AB ERROR INSTRUCTIONS
12 CC CRN 70 SS DRF 77
如果数据不包含 0x001E 个字符,则查询有效。
编辑:
我试过:
CAST ( REPLACE( DOCTEXT, char(0), '') AS VARCHAR)
而不是 RTRIM(LTRIM(DOCTEXT))
,没有成功。
它很笨重,但您可以在十六进制字符串中的 VARBINARY(MAX)
和 NVARCHAR(MAX)
之间来回转换,以避免任何字符 XML 在文本中不喜欢的问题:
;WITH D1 AS (
SELECT ID, NAME
FROM DOC
GROUP BY ID, NAME
)
SELECT D1.ID, D1.NAME, DOCTEXT =
LTRIM(CONVERT(NVARCHAR(MAX), CONVERT(VARBINARY(MAX), D.DOCTEXT, 2)))
FROM D1 CROSS APPLY (
SELECT NULLIF(
CONVERT(VARCHAR(MAX), CONVERT(VARBINARY(MAX), ' ' + LTRIM(RTRIM(D2.DOCTEXT))), 2),
0x)
FROM DOC D2
WHERE D2.ID = D1.ID AND D2.[NAME] = D1.[NAME]
FOR XML PATH('')
) D(DOCTEXT)
我们不能在这里使用 BINARY BASE64
,因为连接两个 Base64 字符串不会(通常)产生另一个 Base64 字符串。外层 LTRIM()
负责删除初始的 space;如果您愿意,可以使用 STUFF
来获得更精确的结果,但由于我们正在修剪内部字符串的 space,所以这里并不重要。
请注意,还有其他连接字符串的方法(最著名的是 SQL Server 2017 中的 STRING_AGG
),您链接到的文章中提到了它们。这种方法在性能方面不一定是最好的,但我没有测量过。
我检查过:https://www.red-gate.com/simple-talk/sql/t-sql-programming/concatenating-row-values-in-transact-sql/ 所以,我的查询是:
SELECT DISTINCT ID, NAME, DOCTEXT2
FROM DOC
CROSS APPLY (SELECT
Stuff((SELECT ' ' + RTRIM(LTRIM(DOCTEXT))
FROM DOC d
WHERE d.ID=DOC.ID AND d.NAME = DOC.NAME
FOR XML PATH (''), TYPE).value('.','varchar(max)'),1,1,'')
) D (DOCTEXT2)
错误是:
FOR XML could not serialize the data for node 'NoName' because it contains a character (0x001E) which is not allowed in XML. To retrieve this data using FOR XML, convert it to binary, varbinary or image data type and use the BINARY BASE64 directive.
我知道数据中有 0x001E 个字符。我不想替换数据库中的这些数据。
我的数据是:
ID NAME DOCTEXT
12 AB ERROR INSTRUCTIONS
12 CC CRN 70 SS
12 CC DRF 77
12 CC
我想要的是:
ID NAME DOCTEXT
12 AB ERROR INSTRUCTIONS
12 CC CRN 70 SS DRF 77
如果数据不包含 0x001E 个字符,则查询有效。
编辑:
我试过:
CAST ( REPLACE( DOCTEXT, char(0), '') AS VARCHAR)
而不是 RTRIM(LTRIM(DOCTEXT))
,没有成功。
它很笨重,但您可以在十六进制字符串中的 VARBINARY(MAX)
和 NVARCHAR(MAX)
之间来回转换,以避免任何字符 XML 在文本中不喜欢的问题:
;WITH D1 AS (
SELECT ID, NAME
FROM DOC
GROUP BY ID, NAME
)
SELECT D1.ID, D1.NAME, DOCTEXT =
LTRIM(CONVERT(NVARCHAR(MAX), CONVERT(VARBINARY(MAX), D.DOCTEXT, 2)))
FROM D1 CROSS APPLY (
SELECT NULLIF(
CONVERT(VARCHAR(MAX), CONVERT(VARBINARY(MAX), ' ' + LTRIM(RTRIM(D2.DOCTEXT))), 2),
0x)
FROM DOC D2
WHERE D2.ID = D1.ID AND D2.[NAME] = D1.[NAME]
FOR XML PATH('')
) D(DOCTEXT)
我们不能在这里使用 BINARY BASE64
,因为连接两个 Base64 字符串不会(通常)产生另一个 Base64 字符串。外层 LTRIM()
负责删除初始的 space;如果您愿意,可以使用 STUFF
来获得更精确的结果,但由于我们正在修剪内部字符串的 space,所以这里并不重要。
请注意,还有其他连接字符串的方法(最著名的是 SQL Server 2017 中的 STRING_AGG
),您链接到的文章中提到了它们。这种方法在性能方面不一定是最好的,但我没有测量过。