问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

EXCEL筛选的重复数据时候明明不重复的数据为什么显示是重复的?

发布网友 发布时间:2022-04-28 12:39

我来回答

6个回答

懂视网 时间:2022-05-03 06:43

在很多异常情况下,比如高并发、网络糟糕的时候,数据库里偶尔会出现重复的记录。

假如现在有一张书籍表,结构类似这样

+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
+----+--------------+

在异常情况下,可能会出现下面这样的记录

+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
| 2 | 人类简史 |
| 3 | 人类简史 |
+----+--------------+

但是,想了想,自己在处理相关数据的时候也加了判重的相关逻辑,比如,新增时当图书 name 相同时,会提示图书重复而返回。

初次遇到这个情况的时候,感觉有点摸不着头脑,后面想了想,还是理清了,其实这和数据库的事务隔离级别有一定关系。

先简单说下数据库事务的 4 个隔离级别,然后重现下上述问题,最后说说解决办法。

1 数据库事务的 4 个隔离级别

1.1 未提交读

顾名思义,当事务隔离级别处于这个设置的时候,不同事务能读取其它事务中未提交的数据。

便于说明,我开了两个客户端(A 以及 B),并设置各自的隔离级别为未提交读。(并没有全局设置)

设置隔离级别命令

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

好了,开始。

Client A

mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@session.tx_isolation;
+------------------------+
| @@session.tx_isolation |
+------------------------+
| READ-UNCOMMITTED |
+------------------------+
1 row in set (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
+----+--------------+
1 row in set (0.00 sec)

mysql> insert into books(name) values('人类简史');
Query OK, 1 row affected (0.01 sec)

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
| 4 | 人类简史 |
+----+--------------+
2 rows in set (0.00 sec)

当 A 中的事务没有关闭的时候,我们去 B 中看下数据

Client B

mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@session.tx_isolation;
+------------------------+
| @@session.tx_isolation |
+------------------------+
| READ-UNCOMMITTED |
+------------------------+
1 row in set (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
| 4 | 人类简史 |
+----+--------------+
2 rows in set (0.00 sec)

B 中可以读取 A 未提交的数据,所谓未提交读就是这样。

最后,记得把各个事务提交。

Client A & Client B

mysql> commit;

1.2 提交读

不能事务可以读取其它事务中已经提交的数据。

篇幅问题,这里我就不贴出设置隔离级别的语句,测试某个隔离级别的时候,默认已经设置好该级别。

Client A

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
+----+--------------+
1 row in set (0.00 sec)

mysql> insert into books(name) values('人类简史');
Query OK, 1 row affected (0.00 sec)

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
| 5 | 人类简史 |
+----+--------------+
2 rows in set (0.00 sec)

A 没提交,在 B 里面去看下数据

Client B

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
+----+--------------+
1 row in set (0.00 sec)

和预期一样,A 中未提交的数据在 B 中看不到。

A 中提交事务

Client A

mysql> commit;

在 B 中看下

Client B

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
| 5 | 人类简史 |
+----+--------------+
2 rows in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

B 中能看到 A 中提交的数据。

1.3 可重复读

细心的朋友可能会发现一个问题,那就是在 B 中的同一个事务读同一个表,得到的结果却不一致,开始只有 1 条,后面有 2 条,而如果没有这个问题的话,也就是可重复读了。

我们来验证下

Client A

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
+----+--------------+
1 row in set (0.00 sec)

mysql> insert into books(name) values('人类简史');
Query OK, 1 row affected (0.01 sec)

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
| 6 | 人类简史 |
+----+--------------+
2 rows in set (0.00 sec)

Client B

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
+----+--------------+
1 row in set (0.00 sec)

Client A

mysql> commit
Query OK, 0 rows affected (0.00 sec)

Client B

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
+----+--------------+
1 row in set (0.00 sec)

和预期一致。B 中事务没有受到 A 中事务的提交影响,读取的数据和事务刚开始的时候一致,books 中都只有一条数据,这就是可重复读。

当然,B 在自己的事务中做修改,肯定是可见的。

Client B

mysql> insert into books(name) value ('时间简史');
Query OK, 1 row affected (0.00 sec)

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
| 8 | 时间简史 |
+----+--------------+
2 rows in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

1.4 串行化

这是隔离级别最严格的一级,在该级别中,不同事务中的读写会相互阻塞。

Client A

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
+----+--------------+
1 row in set (0.00 sec)

当 A 未提交的时候在 B 中对同一个表进行写

Client B

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from books;
+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
+----+--------------+
1 row in set (0.00 sec)

mysql> insert into books(name) value ('人类简史');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

由于不同事务中的读写相互阻塞,所以出现了上面超时的情况。

如果 A 中提交事务

Client A

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

那么在 B 中就能正常写了

Client B

mysql> insert into books(name) value ('人类简史');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

同理,在 A 中开启事务并向 books 中插入一条记录后不提交,B 中开启事务并对该表进行读操作,也会超时。当 A 中的事务提交后,B 中对 books 的读操作就没有问题了。

2 重现问题

由于 MySQL 的 Innodb 的默认事务隔离级别为可重复读,也就导致了判重逻辑可能会出现问题,我们来重现一下。

现在,数据库的数据是这样的

+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
+----+--------------+

后端逻辑类似这样的

try:
 book_name = '人类简史'
 book = get_by_name(book_name)
 if book:
 raise Exception(f'图书 {book_name} 已存在')

 # 新增操作
 # 其它操作

 db.session.commit()
 return {'success': True}
except Exception as e:
 db.session.rollback()
 return {'success': False, 'msg': f'新增图书失败 {e}'}

当两个用户输入书名「人类简史」并提交后,同时有两个线程执行这段逻辑,也就相当于上面两个客户端同时开启了事务,我们以这两个客户端来说明问题

Client A

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from books where name = '人类简史';
Empty set (0.00 sec)

mysql> insert into books(name) values('人类简史');
Query OK, 1 row affected (0.00 sec)

A 中检测图书不存在,然后插入,但是由于「其它操作」由于网络或者其它原因太费时间,导致事务提交延迟。

这时在 B 中执行类似操作

Client B

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from books where name = '人类简史';
Empty set (0.00 sec)

mysql> insert into books(name) values('人类简史');
Query OK, 1 row affected (0.00 sec)

由于事务隔离级别是可重复读的,B 中无法读取 A 中未提交的数据,所以判重逻辑顺利通过,也插入了同一本书。(也就是说隔离级别在提交读及以上都有可能出现这个问题)

最后 A 和 B 都提交后

Client A & Clinet B

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

就出现了重复记录了

+----+--------------+
| id | name  |
+----+--------------+
| 1 | 世界简史 |
| 12 | 人类简史 |
| 13 | 人类简史 |
+----+--------------+

3 怎么解决

3.1 数据库层面

从底层进行限制,对 name 添加唯一索引后,插入重复记录会报错,简单粗暴的解决了这个问题。

3.2 代码层面

加唯一索引能解决,但是总觉得代码不够完整,其实在代码层面也可以解决这个问题。

如果我们在接收请求的时候如果碰到关键参数相同的请求,我们可以直接拒绝,返回类似「操作进行中」的响应,这样也就从源头上解决了这个问题。

实现上面的思路也很简单,借助 redis 的 setnx 即可。

book_name = request.form.get('book_name', '')
if not book_name:
 reutrn json.dumps({'success': False, 'msg': '请填写书名'})

redis_key = f'add_book_{book_name}'
set_res = redis_client.setnx(redis_key, 1)
if not set_res:
 reutrn json.dumps({'success': False, 'msg': '操作进行中'})

add_res = add_book(book_name) # 添加操作

redis_client.delete(redis_key)
return json.dumps(add_res)

如果类似场景比较多,可以考虑把 redis 的操作封装成一个装饰器,让代码能复用起来,这里不再赘述。

4 小结

由于数据库隔离级别的原因,一些数据就算是逻辑上进行防重了,也有可能出现重复记录。解决这个问题,可以在数据库层面加唯一索引解决,也可以在代码层面进行解决。

原文链接:http://www.kevinbai.com/articles/8.html

关注「小小后端」公众号,更多干货等着你喔!

数据库存数据时,逻辑上防重了为啥还会出现重复记录?

标签:html   阻塞   情况下   事务隔离级别   网络   开始   add   code   tab   

热心网友 时间:2022-05-03 03:51

筛选的选项设置错了,正确的操作步骤为:

1、在基本表数据中,它是产品的月销售额,A是日期,B是产品名称,C是销售量。要提取产品类别,您需要使用数据选项卡中的过滤工具,然后单击Excel菜单栏。数据标签。

2、选择基础数据中的项目列(B列),单击“数据”选项栏中的“过滤器”选项,然后下拉按钮将显示在列B的顶部。单击按钮查看产品类别用于验证。随后的筛查结果是否正确。

3、单击“过滤器”选项右下角的“高级”选项,弹出“高级过滤器”对话框,在对话框中选择“选择非重复记录”,然后模式中有两个选项,在这里我们选择第一个A“在原始区域显示筛选结果”。

4、单击“确定”按钮,将在初始基本表的基础上完成过滤操作。该项目的类别将被过滤掉。从图中可以看出,第一次出现的不同产品类别将被过滤掉。复制已过滤的表单以获取产品类别。

5、如果在步骤3中,我们选择“方法”作为“将过滤结果复制到其他位置”,则需要单击弹出框的“复制到”空白列以激活该选项,然后选择新选项。用鼠标。放置过滤结果的位置。

6、单击“确定”按钮。此时,我们选择的产品类别将显示在我们的鼠标在步骤5中选择的新放置位置。此操作可以直接获取非重复产品类别,而无需单独复制。

热心网友 时间:2022-05-03 05:09

这个问题N年前就有结论了,countif 和 sumif 函数不能区分15位后面的数字
可以用sumproct函数:
=SUMPRODUCT(($C$2:$C$100=C2)*1)

热心网友 时间:2022-05-03 06:43

公式有误,应该是
=IF(COUNTIF(C:C,C2)>1,"重复","")

意思是如果条件项COUNTIF(C:C,C2)>1符合,则输出结果“重复”,否则输出为空值。
“重复”选项应该放在 if 的中间部位,表示条件项成立时的值。

EXCEL似乎只识别数字形式的东东前15位,对15位后的不感冒。。。
对此问题,如果前六位地区号为一致的话,不妨用mid(c2,7,12)截取后12位,然后进行比较。

热心网友 时间:2022-05-03 08:35

这个公式有错误。更正为:
=IF(COUNTIF(C:C,C2)>1,"重复","")

热心网友 时间:2022-05-03 10:43

格内可能有些是文本格式,在些是数字格式了。最好是在筛选前用顺序功能排好序,然后将相同的用其中一个复制再将相同的全部粘贴一次,这下就肯的格式一样了,再使用筛选功能应就得了。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
...乙肝表面抗体和乙肝核心抗体同显阳性,其余三项为阴性说明了什么... 确认劳动关系原告可以是多人吗 华为p7_l09的时间如何调整 什么地方卖毛线 如何订购毛线 顾景舟石瓢壶多少价 ...这个日期什么格式 Java 中怎么日期 转换成这样子呢如:2013-06-27... java中用正则表达式匹配并输出的时间怎样拿到别的方法里进行计算。例... Java程序 题目:星期计算器的实现。实现要点:输入一个2013-05-01后的日... 半夜敷面膜这些星座就是这样被吓死的 vivo手机浏览器的查找记录被清空了,又没有添加过书签,怎么找回啊,求解答。 vivo浏览器如何降级,它升级之后浏览记录只剩几个了? 在vivo浏览器上看视频时跳出来一个东西然后买了现在怎么找不到了呢怎么找,关键是现在好多天了,也没? vivo自带浏览器怎么看到以前浏览过的网页?(以前设置的是无痕模式) vivo手机只要恢复出厂设置了是浏览器搜过历史记录都没有了吗 vivo手机自带浏览器的历史记录只有今天和昨天的,以前的历史记录怎么才能知道? VIVOY66I手机浏览器浏览历史删除后怎么恢复 vivo手机浏览器历史记录被删除了如何复原视频记录也行? vivo浏览器自动恢复上次网页 Vivo手机无痕浏览能恢复聊天记录吗? vivo手机自带浏览器的历史记录删了以后怎么复原 网上下的模板好多都有grid.css这个css文件,这拿干啥用的 二手手机那个平台好? 电脑主板的序列号怎么才能看到是原装的? 在外地做亲子鉴定能不能在家里上户口? 昨晚梦见死猫。 亲子鉴定上户口需要什么手续 我梦见死猫意味着什么 上户口需要亲子鉴定吗 我女友昨晚梦见死猫 求解梦 excel查找重复内容,是不是有时候不准确呢? excel表格通过自动筛选,原数据与筛选后的数据为什么不一致的? 冬天汽车玻璃起雾怎么办 为什么excel在同一个数据表中,用相同的筛选条件,筛选两次出来的数据会不一样?遇到两三次,遇到鬼了? 请问:excel查找重复内容,是不是有时候不准确呢? 冬天来了,开车时挡风玻璃上起雾,有何好的解决办法? 为什么我的EXCEL筛选的数据不对,是什么问题呢?请教高手 Excel筛选出来的数据为什么不全 在冬季开车,为什么车窗上会形成一层薄雾呢? excel里筛选重复数据,点“条件格式—突出显示单元格规则—重复值”后,得到的数据为什么有部分并不重复? EXCEL用函数筛选出一列中不重复的数据,遇到错误了,求大神解答 冬天开车时挡风玻璃上总有雾,这时是不是应该打开空调? excel表,明明有重复的,为什么识别不出来啊? 冬天下雪汽车玻璃起雾怎么办 电脑计算器在哪儿调出来 将EXCEL表中的数据导入CAD 笔记本电脑如何清除风扇上的灰尘呢? 股权转让流程哪些?怎么办理? CSS,问题 grid可以不用在css里面设置display,而是像图里面直接用么?原理是啥 大家都说DNF出私服了,真的吗?