sql - 如何找到 varchar 中所有特殊符号的位置?

标签 sql sql-server-2008

我尝试过使用 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/

相关文章:

java - 最佳 SQL 性能选项

xml - 使用完整声明将 xml 插入数据库

SQL Server 在单个表中添加两个时间列并将结果放入第三列

sql - 如何使此查询返回审核表中的最新记录(MSSQL 2008)

sql - Oracle SQL - DENSE_RANK

sql - 为什么SSIS中的Union All转换是部分/半阻塞转换?

sql-server - 带有连接字符串的 SQLCmd

java - 与 SQL Server : login failed for user x 的 JDBC 连接

sql - 打开的连接数和连接休眠状态的含义

mysql - 比较 now() 并返回最近的前一个日期和最近的下一个日期 SQL