Mysql
 sql >> Database >  >> RDS >> Mysql

Conta il numero di caratteri univoci in una stringa

Questo è per divertimento, vero?

SQL riguarda l'elaborazione di insiemi di righe, quindi se possiamo convertire una "parola" in un insieme di caratteri come righe, possiamo utilizzare le funzioni "gruppo" per fare cose utili.

L'uso di un "motore di database relazionale" per eseguire semplici manipolazioni dei personaggi sembra sbagliato. Tuttavia, è possibile rispondere alla tua domanda solo con SQL? Sì, lo è...

Ora, ho sempre una tabella che ha una colonna intera che contiene circa 500 righe che ha la sequenza crescente 1 .. 500. Si chiama "serie intera". È un tavolo davvero piccolo che ha usato molto, quindi viene memorizzato nella cache. È progettato per sostituire il from 'select 1 ... union ... testo nelle query.

È utile per generare righe sequenziali (una tabella) di qualsiasi cosa che puoi calcolare basata su un numero intero usandolo in un cross join (anche qualsiasi inner join ). Lo uso per generare giorni per un anno, analizzare stringhe delimitate da virgole ecc.

Ora, sql mid la funzione può essere utilizzata per restituire il carattere in una determinata posizione. Usando la tabella "integerseries" posso convertire "facilmente" una "parola" in una tabella di caratteri con una riga per carattere. Quindi usa le funzioni 'gruppo'...

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  

Uscita:

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

Nota:il numero di righe nell'output è il numero di caratteri diversi nella stringa. Quindi, se viene contato il numero di righe di output, sarà noto il numero di "lettere diverse".

Questa osservazione viene utilizzata nella query finale.

La query finale:

Il punto interessante qui è spostare le restrizioni 'integerseries' 'cross join' (1 .. length(word)) nell'effettivo 'join' piuttosto che farlo nel where clausola. Ciò fornisce all'ottimizzatore indizi su come limitare i dati prodotti durante l'esecuzione del 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  

Uscita:

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

Tabella di parole e dati:

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);

Tabella delle serie intere:intervallo 1 .. 30 per questo esempio.

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