2016-03-30 17 views
4

以下の例に基づいて問題を説明してください。 文字列 "abc12345"(あれば何でもよい!!!)があり、テーブルmytableにvarchar(100)の列​​mycolumnがあるとします。文字列の最長部分文字列を持つ行を選択

は、最後の文字で終わるいくつかの行があります。5.
最後の文字で終わるいくつかの行があります45
最後の文字で終わるいくつかの行があります345
行がないこと最後の文字がこれらの行を選択する必要があります。この場合は2345

で終了します。

「345」が発生している「ABC12345」の最長右サブあるためだ
SELECT * FROM mytable WHERE mycolumn LIKE "%345" 

少なくとも1つはmycolumn列の少なくとも1つの文字列の右部分文字列として少なくとも1回使用します。 1つのクエリでそれを書く方法はありますか? ありがとうございます。

答えて

2

これは強引な方法である。その後、

select t.* 
from (select t.*, 
      dense_rank() over (order by (case when mycolumn like '%abc12345' then 1 
               when mycolumn like '%bc12345' then 2 
               when mycolumn like '%c12345' then 3 
               when mycolumn like '%12345' then 4 
               when mycolumn like '%2345' then 5 
               when mycolumn like '%345' then 6 
               when mycolumn like '%45' then 7 
               when mycolumn like '%5' then 8 
             end) 
          ) as seqnum 
     where mycolumn like '%5' -- ensure at least one match 
     from t 
    ) t 
where seqnum = 1; 

これは、このような何かインスピレーション:

select t.* 
from (select t.*, max(i) over() as maxi 
     from t join 
      (select str, generate_series(1, length(str)) as i 
      from (select 'abc12345' as str) s 
      ) s 
      on left(t.mycolumn, i) = left(str, i) 
    ) t 
where i = maxi; 
1

あなたがテーブルを再構築することができない場合、私はこの問題をこのようにアプローチします:

  • avgcostを検索、MySQLのソースにsql/udf_example.cの例を参照)Cに集約UDF LONGEST_SUFFIX_MATCH(col, str)を書く

  • SELECT @longest_match:=LONGEST_SUFFIX_MATCH(mycol, "abcd12345") FROM mytbl; SELECT * FROM mytbl WHERE mycol LIKE CONCAT('%', SUBSTR("abcd12345", [email protected]_match))

あなたがテーブルを再構築することができれば、私は、D o完全な解決策がまだありませんが、最初に、文字列を逆にして(REVERSE()関数を使用して)得られた特別な列mycol_revを追加し、そのキーを検索に使用します。私はすぐに解決策を投稿します。

更新:

あなたはそれにキーで逆に列を追加することができた場合:

  • は(CONCAT(SUBSTR(REVERSEをLIKE myrevcol mytbl FROM SELECT myrevcol `の形式でクエリを使用します'$ search_string')、$ n)、 '%')LIMIT 1は、1から$ search_stringまでの範囲にわたって$ nに関するバイナリ検索を実行して、クエリが返す$ nの最大値を見つけますCONCAT LIKE myrevcol(SUBSTR(REVERSE( 'の$ SEARCH_STRING')、$ found_n)、 '%')
  • 01 mytblから行
  • SELECT *

このソリューションでは、限り、あなたはあまりにも多くの行が戻って来ていないと非常に高速である必要があります。 O(log(L))個のクエリの合計があります。ここで、Lは検索文字列の長さで、それぞれがBツリー検索で、1行だけ読み込まれた後にインデックスが読み取られた別のBツリー検索必要な行のみを表示します。

1

興味深いパズル:)

をここでの一番の問題は、長さが何であるかを見つけることですサフィックスパターンに一致するターゲットサフィックスの

MySQLでは、おそらく系列やUDFを生成する必要があります。他はすでにこれを提案しました。 PostgreSQLと正規表現ベースの部分文字列を提供する他のシステムでは

、あなたは以下のトリックを使用することができます

select v, 
    reverse(
     substring(
     reverse(v) || '#' || reverse('abcdefg') 
     from '^(.*).*#\1.*' 
    )) res 
from table; 

を何それがないことである:あなたの文字列や接尾辞を組み合わせた単一の文字列を構築

    • 。注意してください。
    • #を重要な文字列の間に置きます。文字列に存在しない文字が必要です。
    • は、我々はそれが文字列の先頭に^
    • 試合(.*)
    • は、いくつかの残りの文字を持つことができ、任意の数の文字を開始し、このような
      • こと、substringを使用して、正規表現の一致を抽出.*
      • 今のところ#
      • と一致する同じ文字列を(.*)としたい#の直後に送信されます。だから我々は\1
      • を使用して、いくつかの尾の文字が.*
      • 我々はあなたが最大の長さを見つけ、最長のサフィックスを持っていたら、抽出された文字列

    を逆転し、その後持つすべての文字列を見つけることができその長さの接尾辞は簡単です。

    PostgreSQLを使用しているSQLFiddleです:

  • 関連する問題