To je pro zábavu, že?
SQL je o zpracování sad řádků, takže pokud dokážeme převést „slovo“ na sadu znaků jako řádky, můžeme použít funkce „skupiny“ k užitečným věcem.
Používání „relačního databázového stroje“ k jednoduché manipulaci se znaky je špatné. Je přesto možné na vaši otázku odpovědět pouze pomocí SQL? Ano je...
Nyní mám vždy tabulku, která má jeden celočíselný sloupec, který má asi 500 řádků, které mají vzestupnou posloupnost 1...500. Říká se tomu 'integerseries'. Je to opravdu malá tabulka, která hodně používala, takže se ukládá do mezipaměti. Je navržen tak, aby nahradil from 'select 1 ... union ...
text v dotazech.
Je to užitečné pro generování sekvenčních řádků (tabulek) čehokoli, co můžete vypočítat a které je založeno na celém čísle pomocí cross join
(také jakékoli inner join
). Používám ho pro generování dnů za rok, analýzu řetězců oddělených čárkou atd.
Nyní sql mid
funkci lze použít k vrácení znaku na danou pozici. Pomocí tabulky 'integerseries' mohu 'snadno' převést 'slovo' na tabulku znaků s jedním řádkem na znak. Poté použijte funkce 'skupiny'...
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
Výstup:
charAtIdx count(charAtIdx)
--------- ------------------
1
d 1
e 1
H 1
l 3
o 2
r 1
W 1
Poznámka:Počet řádků ve výstupu je počet různých znaků v řetězci. Pokud se tedy spočítá počet výstupních řádků, bude znám počet „různých písmen“.
Toto pozorování je použito v závěrečném dotazu.
Poslední dotaz:
Zajímavým bodem je přesunout omezení 'integerseries' 'cross join' (1 .. length(word)) do skutečného 'join' spíše než to udělat v where
doložka. To poskytuje optimalizátoru vodítko, jak omezit data vytvářená při 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
Výstup:
wordId word letterCount
------ -------------------- -------------
1 3333333333 1
2 1113333333 2
3 1112222444 3
4 Hello World 8
5 funny - not so much? 13
Tabulka slov a 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);
Tabulka celých čísel:rozsah 1 .. 30 pro tento příklad.
CREATE TABLE `integerseries` (
`id` int(11) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=500 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci