これは楽しみのためですよね?
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