Ini untuk bersenang-senang kan?
SQL adalah semua tentang pemrosesan kumpulan baris, jadi jika kita dapat mengubah 'kata' menjadi kumpulan karakter sebagai baris, maka kita dapat menggunakan fungsi 'grup' untuk melakukan hal-hal yang berguna.
Menggunakan 'mesin database relasional' untuk melakukan manipulasi karakter sederhana terasa salah. Namun, apakah mungkin menjawab pertanyaan Anda hanya dengan SQL? Ya itu...
Sekarang, saya selalu memiliki tabel yang memiliki satu kolom bilangan bulat yang memiliki sekitar 500 baris di dalamnya yang memiliki urutan menaik 1 .. 500. Ini disebut 'integerseries'. Ini adalah tabel yang sangat kecil yang banyak digunakan sehingga di-cache di memori. Ini dirancang untuk menggantikan from 'select 1 ... union ...
teks dalam kueri.
Ini berguna untuk menghasilkan baris berurutan (tabel) dari apa pun yang dapat Anda hitung yang didasarkan pada bilangan bulat dengan menggunakannya dalam cross join
(juga inner join
). Saya menggunakannya untuk menghasilkan hari selama setahun, menguraikan string yang dibatasi koma, dll.
Sekarang, sql mid
fungsi dapat digunakan untuk mengembalikan karakter pada posisi tertentu. Dengan menggunakan tabel 'integerseries' saya dapat 'dengan mudah' mengubah 'Word' menjadi tabel karakter dengan satu baris per karakter. Kemudian gunakan fungsi 'grup'...
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
Keluaran:
charAtIdx count(charAtIdx)
--------- ------------------
1
d 1
e 1
H 1
l 3
o 2
r 1
W 1
Catatan:Jumlah baris dalam output adalah jumlah karakter yang berbeda dalam string. Jadi, jika jumlah baris keluaran dihitung maka jumlah 'huruf yang berbeda' akan diketahui.
Pengamatan ini digunakan dalam kueri akhir.
Permintaan terakhir:
Hal yang menarik di sini adalah untuk memindahkan pembatasan 'cross join' 'integerseries' (1 .. length(word)) ke 'join' yang sebenarnya daripada melakukannya di where
ayat. Ini memberikan petunjuk kepada pengoptimal tentang cara membatasi data yang dihasilkan saat melakukan 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
Keluaran:
wordId word letterCount
------ -------------------- -------------
1 3333333333 1
2 1113333333 2
3 1112222444 3
4 Hello World 8
5 funny - not so much? 13
Tabel Kata dan Data:
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);
Tabel bilangan bulat:rentang 1 .. 30 untuk contoh ini.
CREATE TABLE `integerseries` (
`id` int(11) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=500 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci