【问题标题】:Count number of repeated character in a given string计算给定字符串中重复字符的数量
【发布时间】:2021-05-05 19:07:23
【问题描述】:

如何计算给定字符串中重复 $ 字符的出现次数。

例如:

  1. String = '$$$$ABC$$$DE$$$' --> 答案是 4,3,3
  2. String = '###$$%%ANE$$$$$' --> 答案是 2,5

我不知道怎么做所以没有做任何尝试。

感谢您的帮助。

用于复制:

  1. DDL 和插入:
Create table xyz(text varchar(200));
Insert into xyz values('$$$$ABC$$$DE$$$');
Insert into xyz values('###$$%%ANE$$$$$');
  1. 我需要做的:统计'$'的重复次数

  2. 所需的输出,基于上面 #1 中的示例数据。

    text = '$$$$ABC$$$DE$$$' --> 答案是 4,3,3
    text = '###$$%%ANE$$$$$' --> 答案是 2,5

  3. SQL Server 版本:Microsoft SQL Server 2019 (RTM) - 15.0.2000.5

【问题讨论】:

  • 在提出问题时,您需要提供一个可重现的最小示例。请参考以下链接:stackoverflow.com/help/minimal-reproducible-example 请提供以下内容: (1) DDL 和样本数据填充,即 CREATE table(s) 加上 INSERT T-SQL 语句。 (2) 你需要做什么,即逻辑和你的代码尝试在 T-SQL 中实现它。 (3) 期望的输出,基于上面#1 中的样本数据。 (4) 你的 SQL Server 版本 (SELECT @@version;)
  • 请发布您迄今为止尝试过的内容。
  • "SQL Server 版本:Microsoft SQL Server 2019 (RTM) - 15.0.2000.5" 为什么您将近 2 年没有修补您的 SQL Server 了..?有多个错误和安全修复。如果您不更新您的应用程序,我害怕认为您的操作系统已经过时了。

标签: sql sql-server tsql


【解决方案1】:

请尝试以下解决方案。它将从 SQL Server 2017 开始工作。

它基于 TRANSLATE() 函数以及 XML 和 XQuery 的使用。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, tokens VARCHAR(30));
INSERT INTO @tbl (tokens) VALUES
('$$$$ABC$$$DE$$$'), --> Answer is 4,3,3
('###$$%%ANE$$$$$'); --> Answer is 2,5
-- DDL and sample data population, end

DECLARE @separator CHAR(1) = SPACE(1);

;WITH cte AS 
(
    SELECT *
        , REPLACE(TRANSLATE(tokens, '$', SPACE(1)),' ','') AS JunkCharacters
    FROM @tbl
)
SELECT *
, REPLACE(TRY_CAST('<root><r><![CDATA[' +
    REPLACE(TRANSLATE(tokens, TRIM(JunkCharacters), SPACE(LEN(TRIM(JunkCharacters)))), @separator, ']]></r><r><![CDATA[') + 
    ']]></r></root>' AS XML)
        .query('
        for $x in /root/r[text()]
        return data(string-length($x))
        ').value('.', 'VARCHAR(20)'), SPACE(1), ',') AS CleansedTokensCounter
FROM cte;

输出

+----+-----------------+----------------+-----------------------+
| ID |     tokens      | JunkCharacters | CleansedTokensCounter |
+----+-----------------+----------------+-----------------------+
|  1 | $$$$ABC$$$DE$$$ | ABCDE          |                 4,3,3 |
|  2 | ###$$%%ANE$$$$$ | ###%%ANE       |                   2,5 |
+----+-----------------+----------------+-----------------------+

【讨论】:

    【解决方案2】:

    我们可以通过以下几个步骤来做到这一点:

    • 我们使用计数/数字表将字符串分解为单个字符。计数是通过几个交叉连接和ROW_NUMBER 即时计算的
    • 然后我们为每组字符计算一个分组 ID,使用标准的间隙和岛技术:每个起始行的窗口总和
    • 过滤到我们想要的字符,按 ID 分组并返回每组中的行数。

    这将为每组 $ 字符返回一个新行

    Create table xyz(text varchar(200));
    Insert into xyz values('$$$$ABC$$$DE$$$');
    Insert into xyz values('###$$%%ANE$$$$$');
    
    WITH
        L0 AS ( SELECT 1 AS c
                FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),
                            (1),(1),(1),(1),(1),(1),(1),(1)) AS D(c) ),
        L1 AS ( SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B ),
        -- you can allow for larger strings with more cross-joins
        Nums AS ( SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rownum
                  FROM L1 )
    
    SELECT
        xyz.[text],
        r.numRepetitions
    FROM xyz
    CROSS APPLY (
        SELECT numRepetitions = COUNT(*)
        FROM (
            SELECT TOP(LEN(xyz.[text]))
                thisChar = SUBSTRING(xyz.[text], rownum, 1),
                groupId = SUM(CASE WHEN rownum = 1 OR SUBSTRING(xyz.[text], rownum, 1) <> SUBSTRING(xyz.[text], rownum - 1, 1) THEN 1 ELSE 0 END)
                   OVER (ORDER BY rownum ROWS UNBOUNDED PRECEDING)
            FROM Nums
            ORDER BY rownum
        ) AS chars
        WHERE thisChar = '$'
        GROUP BY groupId
    ) AS r;
    

    如果你想要一个逗号分隔的行计数列表,你需要再次子查询

    CROSS APPLY (
        SELECT numRepetitions = STRING_AGG(CAST(numRepetitions AS varchar(10)), ',')
        FROM (
            SELECT numRepetitions = COUNT(*)
            FROM (
                SELECT TOP(LEN(xyz.[text]))
                    thisChar = SUBSTRING(xyz.[text], rownum, 1),
                    groupId = SUM(CASE WHEN rownum = 1 OR SUBSTRING(xyz.[text], rownum, 1) <> SUBSTRING(xyz.[text], rownum - 1, 1) THEN 1 ELSE 0 END)
                       OVER (ORDER BY rownum ROWS UNBOUNDED PRECEDING)
                FROM Nums
                ORDER BY rownum
            ) AS chars
            WHERE thisChar = '$'
            GROUP BY groupId
        ) AS groups
    ) AS r;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-12-05
      • 1970-01-01
      • 2011-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-09
      相关资源
      最近更新 更多