Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Zählen Sie die Anzahl der eindeutigen Zeichen in einer Zeichenfolge

Das ist zum Spaß, richtig?

Bei SQL dreht sich alles um die Verarbeitung von Sätzen von Zeilen. Wenn wir also ein 'Wort' in einen Satz von Zeichen als Zeilen umwandeln können, können wir die 'Gruppen'-Funktionen verwenden, um nützliche Dinge zu tun.

Die Verwendung einer „relationalen Datenbank-Engine“ zur einfachen Zeichenmanipulation fühlt sich falsch an. Ist es dennoch möglich, Ihre Frage nur mit SQL zu beantworten? Ja, das ist es...

Jetzt habe ich immer eine Tabelle, die eine ganzzahlige Spalte mit etwa 500 Zeilen enthält, die die aufsteigende Folge 1 .. 500 hat. Sie wird "Integerseries" genannt. Es ist eine wirklich kleine Tabelle, die viel verbraucht hat, sodass sie im Speicher zwischengespeichert wird. Es soll den from 'select 1 ... union ... ersetzen Text in Abfragen.

Es ist nützlich, um aufeinanderfolgende Zeilen (eine Tabelle) von allem zu generieren, was Sie berechnen können, das auf einer Ganzzahl basiert, indem Sie es in einem cross join verwenden (auch jeder inner join ). Ich verwende es zum Generieren von Tagen für ein Jahr, zum Analysieren von durch Kommas getrennten Zeichenfolgen usw.

Nun, die sql mid Funktion kann verwendet werden, um das Zeichen an einer bestimmten Position zurückzugeben. Durch die Verwendung der 'Integerseries'-Tabelle kann ich ein 'Wort' 'einfach' in eine Zeichentabelle mit einer Zeile pro Zeichen umwandeln. Dann nutzen Sie die 'Gruppen'-Funktionen...

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  

Ausgabe:

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

Hinweis:Die Anzahl der Zeilen in der Ausgabe ist die Anzahl der verschiedenen Zeichen in der Zeichenfolge. Wenn also die Anzahl der ausgegebenen Zeilen gezählt wird, ist die Anzahl der 'verschiedenen Buchstaben' bekannt.

Diese Beobachtung wird in der letzten Abfrage verwendet.

Die letzte Abfrage:

Der interessante Punkt hier ist, die 'Integerseries'-'Cross Join'-Beschränkungen (1 .. Länge(Wort)) in den eigentlichen 'Join' zu verschieben, anstatt es im where zu tun Klausel. Dies liefert dem Optimierer Hinweise, wie er die beim join erzeugten Daten einschränken kann .

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  

Ausgabe:

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

Worttabelle und Daten:

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-Tabelle:Bereich 1 .. 30 für dieses Beispiel.

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