计算字符串中唯一字符的数量

Dyn*_*ado 8 mysql sql database

我正在寻找一个sql语句来计算字符串中唯一字符的数量.

例如

3333333333 -> returns 1
1113333333 -> returns 2
1112222444 -> returns 3
Run Code Online (Sandbox Code Playgroud)

我用REGEX和mysql-string-functions做了一些测试,但是我找不到解决方案.

Rya*_*ent 7

这是为了好玩吗?

SQL就是处理行集,所以如果我们可以将'word'转换为一组字符作为行,那么我们可以使用'group'函数来做有用的东西.

使用"关系数据库引擎"进行简单的字符操作感觉不对.仍然,是否可以用SQL回答你的问题?是的...

现在,我总是有一个表有一个整数列,其中有大约500行,其中升序列为1 .. 500.它被称为'integerseries'.它是一个非常小的表,它使用了很多,因此它被缓存在内存中.它旨在替换from 'select 1 ... union ...查询中的文本.

通过在cross join(也是任意inner join)中使用它来生成基于整数可以计算的任何事物的顺序行(表)非常有用.我用它来生成一年的日子,解析逗号分隔的字符串等.

现在,sql mid函数可用于返回给定位置的字符.通过使用'integerseries'表,我可以'轻松'将'word'转换为每个字符一行的字符表.然后使用'组'功能......

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  
Run Code Online (Sandbox Code Playgroud)

输出:

charAtIdx  count(charAtIdx)  
---------  ------------------
                            1
d                           1
e                           1
H                           1
l                           3
o                           2
r                           1
W                           1
Run Code Online (Sandbox Code Playgroud)

注意:输出中的行数是字符串中不同字符的数量.因此,如果计算输出行的数量,则将知道"不同字母"的数量.

此观察结果用于最终查询.

最后的查询:

这里有趣的一点是将'integerseries''交叉连接'限制(1 .. length(word))移动到实际的'join'中,而不是在where子句中执行.这为优化器提供了关于如何限制执行时生成的数据的线索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  
Run Code Online (Sandbox Code Playgroud)

输出:

wordId  word                  letterCount  
------  --------------------  -------------
     1  3333333333                        1
     2  1113333333                        2
     3  1112222444                        3
     4  Hello World                       8
     5  funny - not so much?             13
Run Code Online (Sandbox Code Playgroud)

单词表和数据:

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);
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)


Abh*_*rty 4

没有直接或简单的方法可以做到这一点。您可能需要编写一个存储函数来完成这项工作,并查看数据中您可能期望的所有字符。这是一个仅针对数字的示例,它可以扩展到存储函数中的所有字符

mysql> select * from test ;
+------------+
| val        |
+------------+
| 11111111   |
| 111222222  |
| 1113333222 |
+------------+


select 
val, 
sum(case when locate('1',val) > 0 then 1 else 0 end ) 
+ sum( case when locate('2',val) > 0 then 1 else 0 end)
+ sum(case when locate('3',val) > 0 then 1 else 0 end)
+sum(case when locate('4',val) > 0 then 1 else 0 end ) as occurence
from test group by val


+------------+-----------+
| val        | occurence |
+------------+-----------+
| 11111111   |         1 |
| 111222222  |         2 |
| 1113333222 |         3 |
+------------+-----------+
Run Code Online (Sandbox Code Playgroud)

或者,如果您有足够的时间,请创建一个包含您能想到的所有字符的查找表。并用 2 行进行查询

mysql> select * from test ;
+------------+
| val        |
+------------+
| 11111111   |
| 111222222  |
| 1113333222 |
+------------+
3 rows in set (0.00 sec)

mysql> select * from look_up ;
+------+------+
| id   | val  |
+------+------+
|    1 | 1    |
|    2 | 2    |
|    3 | 3    |
|    4 | 4    |
+------+------+
4 rows in set (0.00 sec)

select 
t1.val, 
sum(case when locate(t2.val,t1.val) > 0 then 1 else 0 end ) as occ 
from test t1,(select * from look_up)t2 
group by t1.val ;

+------------+------+
| val        | occ  |
+------------+------+
| 11111111   |    1 |
| 111222222  |    2 |
| 1113333222 |    3 |
+------------+------+
Run Code Online (Sandbox Code Playgroud)

  • @Vikrant那么你认为在mysql中完成工作的最简单方法是什么,发布为答案。 (4认同)
  • 整个前提是愚蠢的。我什至不知道为什么你们在这里批评 Abhik 为 OP 给出的精确输入参数提供了解决方案。MySQL 不是完成这项工作的工具,甚至没有对此进行讨论。 (3认同)