2016-08-06 63 views
0

Lassen Sie das Zeichen s sein und Zeichenfolge mississsipisssss sein. Die SQL sollte zurückkehren 5.sql: So finden Sie die maximale Länge der aufeinander folgenden Sequenz von gegebenen Zeichen in einer Zeichenfolge mit sql

Ich war zu Make-up etwas denken

regexp_count(string,'s+') mit würde die Anzahl der Teil whith aufeinanderfolgende Sequenz von s zurückzukehren.

REGEXP_INSTR(string,'s',1,m) würde die Position des m-ten Auftreten von Rück char s (Startposition des m-ten Sequenz)

REGEXP_INSTR(string,'s[^s]',1,m) die Position des m-ten Auftreten von char s (Endposition mth Sequenz) zurückkehren

Ich bin immer noch zu keiner Lösung gekommen. Aber ich denke nicht, dass dies ein korrekter Weg ist, da die Strings beliebig lang sein könnten, und es könnte eine beliebige Anzahl solcher aufeinanderfolgender Sequenzen geben. Könnte jemand eine Idee zur Lösung geben (Ich bin Anfänger)

Antwort

0

Dies ist keine Operation, die gut von Datenbanken unterstützt wird, obwohl Postres definitiv Funktionalität in diesem Bereich hat.

Wenn Sie wissen, dass eine Begrenzung der Anzahl von Teil von „s“ s, dann könnte man so etwas tun:

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) 
       ) 

Dies würde die ersten 6 Substrings finden und berechnen dann die maximale Länge .

Die Alternative besteht im Wesentlichen darin, die Zeichenfolge selbst unter Verwendung von connect by oder eines rekursiven CTE zu teilen. Das obige könnte jedoch ausreichend sein.

1

Dies funktioniert in SQL Server 2008 +. Das gleiche Konzept wird in Oracle funktionieren, Sie müssen nur ein paar Syntaxunterschiede wie SUBSTR anstelle von SUBSTRING hinzufügen. Hier ist ein kurzer Versuch, Oracle Syntax der Umwandlung:

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 
; 

Und hier ist eine SQL-Server Version

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 

Es ist ein Recursive Common Table Expression [CTE], die die Zeichenfolge in Zeichen Token in der Reihenfolge der Index Position spaltet und Tests, um zu sehen, ob sie der Charakter sind, den Sie wünschen. Wenn das Token das Zeichen ist, dann baut es auf dem Zählwert vom vorherigen Token auf, wenn es ein Zeichen ist, also musst du nur die MAX() des Ergebnisses nehmen und du hast deine Antwort.

+0

Dies wird zumindest in Oracle fehlschlagen. Es gibt keine FROM-Klausel im ersten CTE, Oracle hat keine SUBSTRING-Funktion (es gibt eine SUBSTR-Funktion), das rekursive CTE muss eine Spaltenaliasliste haben ... Haben Sie die Abfrage in einem der RDBMS getestet? Wo kompiliert es ohne Fehler und gab die richtige Antwort? In jedem Fall ist der Beitrag eindeutig als Oracle gekennzeichnet und dies hat drei Oracle Fehler, die ich mit bloßem Auge in ein paar Sekunden sehen kann. Klares Defizit. – mathguy

+0

einige der Kommentar war nützlich und ich habe meine Antwort aktualisiert. ja das funktioniert und es wurde getestet.Auf jeden Fall Stahl die Idee und Aufräumen für Orakel-Syntax – Matt

+0

Es wurde in der Form getestet, die Sie ursprünglich gepostet? Und es hat funktioniert? "Ja wirklich?" – mathguy

1

Hier ist eine Standardlösung, die eine hierarchische Abfrage verwendet. Der CASE-Ausdruck in der äußeren Abfrage wird benötigt, um die Antwort "null" zu geben, wenn die Eingabezeichenfolge "null" ist (andernfalls wäre die Antwort 0, und das sollte nicht sein). Ich habe keine ORDER BY-Klausel hinzugefügt - Sie können dies bei Bedarf tun. Viel Glück!

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.