我尝试过使用 patindex 和 charindex,但似乎它们都无法轻松实现我想要的功能。 Charindex 一次只想搜索一个符号,而 patindex 不允许“搜索”索引,不允许我循环查找符号的所有索引。我有什么选择?
最佳答案
由于没有关于“特殊符号”是什么、如何存储以及您期望什么输出的具体细节,因此涉及一些猜测工作,但我认为无论如何都可以应用我的答案的基本原则。获取所有事件的关键是使用递归 CTE 和 OUTER APPLY 。每次 CTE 循环时,它都会用空格替换特殊字符,直到没有特殊字符为止,并存储字符的位置。
示例数据:
DECLARE @SpecialSymbols TABLE (Symbol CHAR(1) NOT NULL PRIMARY KEY)
INSERT @SpecialSymbols VALUES ('@'), ('.'), ('['), (']')
DECLARE @TestData TABLE (StringToTest VARCHAR(100))
INSERT @TestData VALUES
('test 1 [Using Square Brackets]'),
('[<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="91c5f4e2e5a3d1d4fcf0f8fdd0f5f5e3f4e2e2bff2fefc" rel="noreferrer noopener nofollow">[email protected]</a>]'),
('No Special Symbols')
实际查询
;WITH CTE AS
( SELECT *, STUFF(StringToTest, Position, 1, ' ') [ReworkedString]
FROM @TestData
OUTER APPLY
( SELECT CHARINDEX(Symbol, StringToTest) [Position], Symbol
FROM @SpecialSymbols
) Symbols
WHERE Position > 0
UNION ALL
SELECT StringToTest, Symbols.Position, Symbols.Symbol, STUFF(ReworkedString, Symbols.Position, 1, ' ') [ReworkedString]
FROM CTE
OUTER APPLY
( SELECT CHARINDEX(Symbol, ReworkedString) [Position], Symbol
FROM @SpecialSymbols
WHERE Symbol = CTE.Symbol
) Symbols
WHERE Symbols.Position > 0
)
-- CTE NOW LOOKS LIKE:
-- | test 1 [[Using Square Brackets] | 8 | [ | test 1 [Using Square Brackets]
-- | test 1 [[Using Square Brackets] | 30 | ] | test 1 [[Using Square Brackets
-- | [<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f3a7968087c1b3b69e929a9fb2979781968080dd909c9e" rel="noreferrer noopener nofollow">[email protected]</a>] | 20 | . | [Test2@EmailAddress com]
-- | [<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a9fdccdadd9be9ecc4c8c0c5e8cdcddbccdada87cac6c4" rel="noreferrer noopener nofollow">[email protected]</a>] | 7 | @ | [Test2 EmailAddress.com]
-- | [<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ce9aabbdbafc8e8ba3afa7a28faaaabcabbdbde0ada1a3" rel="noreferrer noopener nofollow">[email protected]</a>] | 1 | [ | <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="72261701064032371f131b1e331616001701015c111d1f" rel="noreferrer noopener nofollow">[email protected]</a>]
-- | [<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="adf9c8ded99fede8c0ccc4c1ecc9c9dfc8dede83cec2c0" rel="noreferrer noopener nofollow">[email protected]</a>] | 24 | ] | [<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5b0f3e282f691b1e363a32371a3f3f293e282875383436" rel="noreferrer noopener nofollow">[email protected]</a>
-- | test 1 [[Using Square Brackets] | 9 | [ | test 1 Using Square Brackets]
SELECT a.StringToTest, COALESCE(Location, '') [SpecialSymbolLocations]
FROM @TestData a
LEFT JOIN
( SELECT DISTINCT
StringToTest,
-- THIS MERELY CONCATENATES ROWS INTO COLUMNS TO GET COMMA SEPARATED LIST
STUFF(( SELECT ', ' + CONVERT(VARCHAR, Position)
FROM CTE b
WHERE a.StringToTest = b.StringToTest
ORDER BY Position
FOR XML PATH('')
), 1, 2, '') [Location]
FROM CTE a
) b
ON a.StringToTest = b.StringToTest
实际上可以根据需要操纵 CTE,但是为了完整起见,我使用 SQL server XML Extension to concatenate 添加了最终查询将特殊符号的位置放入逗号分隔的列表中,并将它们放在每个原始字符串旁边。所以最终输出如下:
| StringToTest | SpecialSymbolLocations |
|-----------------------------------|---------------------------|
| test 1 [[Using Square Brackets] | 8, 9, 31 |
| [<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="dd89b8aea9ef9d98b0bcb4b19cb9b9afb8aeaef3beb2b0" rel="noreferrer noopener nofollow">[email protected]</a>] | 1, 7, 20, 24 |
| No Special Symbols | |
关于sql - 如何找到 varchar 中所有特殊符号的位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10203733/