sql >> データベース >  >> RDS >> Mysql

文字列内の一意の文字の数を数える

    これは楽しみのためですよね?

    SQLはすべて行のセットを処理することを目的としているため、「単語」を行としての文字のセットに変換できれば、「グループ」関数を使用して便利な処理を実行できます。

    「リレーショナルデータベースエンジン」を使用して単純な文字操作を行うのは間違っていると感じます。それでも、SQLだけであなたの質問に答えることは可能ですか?はい、そうです...

    今、私は常に、昇順1..500を持つ約500行の整数列が1つあるテーブルを持っています。これは「integerseries」と呼ばれます。これは非常に小さなテーブルであり、多くを使用したため、メモリにキャッシュされます。 from 'select 1 ... union ...を置き換えるように設計されています クエリ内のテキスト。

    cross joinで使用することにより、整数に基づいて計算できるすべての連続行(テーブル)を生成するのに役立ちます。 (inner joinも )。 1年間の日数の生成、カンマ区切り文字列の解析などに使用します。

    さて、SQL mid 関数を使用して、指定された位置にある文字を返すことができます。 'integerseries'テーブルを使用することにより、'単語'を文字ごとに1行の文字テーブルに'簡単に'変換できます。次に、「グループ」関数を使用します...

    SET @word='Hello World';
    
    SELECT charAtIdx, COUNT(charAtIdx)
    FROM (SELECT charIdx.id,
        MID(@word, charIdx.id, 1) AS charAtIdx 
        FROM integerseries AS charIdx
        WHERE charIdx.id <= LENGTH(@word)
        ORDER BY charIdx.id ASC
        ) wordLetters
    GROUP BY
       wordLetters.charAtIdx
    ORDER BY charAtIdx ASC  
    

    出力:

    charAtIdx  count(charAtIdx)  
    ---------  ------------------
                                1
    d                           1
    e                           1
    H                           1
    l                           3
    o                           2
    r                           1
    W                           1
    

    注:出力の行数は、文字列内のさまざまな文字の数です。したがって、出力行の数を数えると、「異なる文字」の数がわかります。

    この観察結果は、最終的なクエリで使用されます。

    最後のクエリ:

    ここで興味深い点は、whereではなく、'integerseries''cross join'制限(1 .. length(word))を実際の'join'に移動することです。 句。これにより、オプティマイザーは、joinを実行するときに生成されるデータを制限する方法に関する手がかりを得ることができます。 。

    SELECT 
       wordLetterCounts.wordId,
       wordLetterCounts.word,   
       COUNT(wordLetterCounts.wordId) AS letterCount
    FROM 
         (SELECT words.id AS wordId,
                 words.word AS word,
                 iseq.id AS charPos,
                 MID(words.word, iseq.id, 1) AS charAtPos,
                 COUNT(MID(words.word, iseq.id, 1)) AS charAtPosCount
         FROM
              words
              JOIN integerseries AS iseq
                   ON iseq.id BETWEEN 1 AND words.wordlen 
          GROUP BY
                words.id,
                MID(words.word, iseq.id, 1)
          ) AS wordLetterCounts
    GROUP BY
       wordLetterCounts.wordId  
    

    出力:

    wordId  word                  letterCount  
    ------  --------------------  -------------
         1  3333333333                        1
         2  1113333333                        2
         3  1112222444                        3
         4  Hello World                       8
         5  funny - not so much?             13
    

    単語テーブルとデータ:

    CREATE TABLE `words` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `word` varchar(128) COLLATE utf8mb4_unicode_ci NOT NULL,
      `wordlen` int(11) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    
    /*Data for the table `words` */
    
    insert  into `words`(`id`,`word`,`wordlen`) values (1,'3333333333',10);
    insert  into `words`(`id`,`word`,`wordlen`) values (2,'1113333333',10);
    insert  into `words`(`id`,`word`,`wordlen`) values (3,'1112222444',10);
    insert  into `words`(`id`,`word`,`wordlen`) values (4,'Hello World',11);
    insert  into `words`(`id`,`word`,`wordlen`) values (5,'funny - not so much?',20);
    

    Integerseriesテーブル:この例では範囲1..30です。

    CREATE TABLE `integerseries` (
      `id` int(11) unsigned NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=500 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
    


    1. CSVファイルデータをPostgreSQLテーブルにインポートする方法は?

    2. MYSQLでのバルク挿入

    3. RDBMSとNoSQL

    4. SQLiteでのDate()関数のしくみ