sql:如何使用sql查找字符串中给定char的连续序列的最大长度

时间:2016-08-06 15:21:25

标签: sql oracle oracle11g

让char为s,字符串为mississsipisssss。 sql应返回5.

我正在考虑使用

来化妆

regexp_count(string,'s+')将返回连续序列s的子串数。

REGEXP_INSTR(string,'s',1,m)将返回char s的第m个位置(第m个序列的起始位置)

REGEXP_INSTR(string,'s[^s]',1,m)将返回char s的第m个位置(第m个序列的结束位置)

我还没有找到任何解决方案。但我不认为这是一种正确的方法,因为字符串可以是任何长度,并且可以有任意数量的这种连续序列。有人可以提出任何解决方案的想法(我是初学者)

3 个答案:

答案 0 :(得分:1)

这将在sql-server 2008 +中运行。相同的概念在Oracle中可以使用,您只需要添加一些语法差异,例如SUBSTR而不是SUBSTRING。以下是转换为Oracle语法的快速尝试:

CREATE GLOBAL TEMPORARY TABLE TempTable
    (String VARCHAR(100)) ON COMMIT PRESERVE ROWS;

INSERT INTO TempTable (String) VALUES ('mississsipisssss');
INSERT INTO #TempTable (String) VALUES ('ssasdfs');

WITH cteTokens (String, IndexNum, Token, CharCount) AS  (
    SELECT
       String
       ,1 as IndexNum
       ,SUBSTR(t.String,1,1) as Token
       ,CASE WHEN SUBSTR(t.String,1,1) = 's' THEN 1 ELSE 0 END As CharCount
    FROM
       #TempTable t

    UNION ALL

    SELECT
       t.String
       IndexNum + 1 as IndexNum
       ,SUBSTR(t.String,IndexNum + 1,1) as Token
       ,CASE WHEN SUBSTR(t.String,IndexNum + 1,1) = 's' THEN t.CharCount + 1 ELSE 0 END AS CharCount
    FROM
       #TempTable s
       INNER JOIN cteTokens t
       ON s.String = t.String
       AND LENGTH(s.String) >= t.IndexNum + 1
)

SELECT
    String
    ,MAX(CharCount)
FROM
    cteTokens
GROUP BY
    String
;

这是一个SQL-Server版本

CREATE TABLE #TempTable (String VARCHAR(100))
INSERT INTO #TempTable (String) VALUES ('mississsipisssss')
INSERT INTO #TempTable (String) VALUES ('ssasdfs')

;WITH cteTokens (String, IndexNum, Token, CharCount) AS  (
    SELECT
       t.String
       ,1 as IndexNum
       ,SUBSTRING(t.String,1,1) as Token
       ,CASE WHEN SUBSTRING(t.String,1,1) = 's' THEN 1 ELSE 0 END As CharCount
    FROM
       #TempTable t

    UNION ALL

    SELECT
       t.String
       ,IndexNum + 1 as IndexNum
       ,SUBSTRING(t.String,IndexNum + 1,1) as Token
       ,CASE WHEN SUBSTRING(t.String,IndexNum + 1,1) = 's' THEN t.CharCount + 1 ELSE 0 END As CharCount
    FROM
       #TempTable s
       INNER JOIN cteTokens t
       ON s.String = t.String
       AND LEN(s.String) >= t.IndexNum + 1
)

SELECT
    String
    ,MAX(CharCount)
FROM
    cteTokens
GROUP BY
    String

它是一个Recursive Common Table Expression [CTE],它按照索引位置的顺序将字符串拆分为字符标记,并测试它们是否是您想要的字符。如果令牌是角色,那么它建立在前一个令牌上的计数的基础上,如果是角色,那么你所要做的就是取结果的MAX()并得到答案。

答案 1 :(得分:1)

这是使用分层查询的标准解决方案。当输入字符串为“null”时,外部查询中的CASE表达式需要给出答案“null”(否则答案将为0,而不应该是)。我没有添加ORDER BY子句 - 如果需要,您可以这样做。祝你好运!

with
     inputs ( str ) as (
       select 'mississsipisssss' from dual union all
       select null               from dual union all
       select 'stress'           from dual union all
       select 'alphabeta'        from dual
     ),
     prep ( str, lvl ) as (
     select str, level
     from   inputs
     connect by  prior str = str
             and prior sys_guid() is not null
             and regexp_instr(str, 's{' || to_char(level-1) || '}') != 0
     )
select   str, case when str is not null then max(lvl) - 1 end as max_len
from     prep
group by str
;


STR                 MAX_LEN
---------------- ----------
(null)               (null)
alphabeta                 0
stress                    2
mississsipisssss          5

4 rows selected.

答案 2 :(得分:0)

这不是数据库支持的操作,尽管Postres肯定在这个领域有功能。

如果您知道" s" s的子串数量有限制,那么您可以这样做:

select greatest(coalesce(length(regexp(substr(string, '[s]+', 1, 1)), 0),
                coalesce(length(regexp(substr(string, '[s]+', 1, 2)), 0),
                coalesce(length(regexp(substr(string, '[s]+', 1, 3)), 0),
                coalesce(length(regexp(substr(string, '[s]+', 1, 4)), 0),
                coalesce(length(regexp(substr(string, '[s]+', 1, 5)), 0),
                coalesce(length(regexp(substr(string, '[s]+', 1, 6)), 0)
               )

这将找到前6个子串,然后计算最大长度。

替代方案主要是使用connect by或递归CTE自行拆分字符串。但是,上述内容可能就足够了。