-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
1997 lines (1683 loc) · 118 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Mw's Hexo</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="静静的来,静静的去,静静的前行,静静的收获。">
<meta property="og:type" content="website">
<meta property="og:title" content="Mw's Hexo">
<meta property="og:url" content="http://example/index.html">
<meta property="og:site_name" content="Mw's Hexo">
<meta property="og:description" content="静静的来,静静的去,静静的前行,静静的收获。">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="mawan">
<meta name="twitter:card" content="summary">
<link rel="alternate" href="/atom.xml" title="Mw's Hexo" type="application/atom+xml">
<link rel="shortcut icon" href="/favicon.png">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/index.min.css">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/fancybox/jquery.fancybox.min.css">
<meta name="generator" content="Hexo 5.3.0"></head>
<body>
<div id="container">
<div id="wrap">
<header id="header">
<div id="banner"></div>
<div id="header-outer" class="outer">
<div id="header-title" class="inner">
<h1 id="logo-wrap">
<a href="/" id="logo">Mw's Hexo</a>
</h1>
</div>
<div id="header-inner" class="inner">
<nav id="main-nav">
<a id="main-nav-toggle" class="nav-icon"></a>
<a class="main-nav-link" href="/">Home</a>
<a class="main-nav-link" href="/archives">Archives</a>
</nav>
<nav id="sub-nav">
<a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
<a id="nav-search-btn" class="nav-icon" title="Search"></a>
</nav>
<div id="search-form-wrap">
<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit"></button><input type="hidden" name="sitesearch" value="http://example"></form>
</div>
</div>
</div>
</header>
<div class="outer">
<section id="main">
<article id="post-MyBatis从入门到精通第1章" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2023/02/06/MyBatis%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A%E7%AC%AC1%E7%AB%A0/" class="article-date">
<time class="dt-published" datetime="2023-02-05T16:00:00.000Z" itemprop="datePublished">2023-02-06</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2023/02/06/MyBatis%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A%E7%AC%AC1%E7%AB%A0/">第1章:MyBatis入门</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h1 id="第1章:MyBatis入门"><a href="#第1章:MyBatis入门" class="headerlink" title="第1章:MyBatis入门"></a>第1章:MyBatis入门</h1><h2 id="随记:"><a href="#随记:" class="headerlink" title="随记:"></a>随记:</h2><p>MyBatis的<br> 配置项的顺序不能颠倒。如果颠倒了它们的顺序,那么在MyBatis去启动阶段就会发生异常,导致程序无法正常运行。 </p>
<h2 id="MyBtis简介"><a href="#MyBtis简介" class="headerlink" title="MyBtis简介"></a>MyBtis简介</h2><p>  MyBatis是一款优秀的支持自定以SQL查询、存储过程和高级映射的持久层框架,消除了几乎所有的JDBC代码和参数的手动设置以及结果集的检索。 MyBatis可以使用XML或注解进行配置和映射,MyBatis通过将参数映射到配置的SQL形成最终执行的SQL语句,最后将执行SQL的结果映射成JAVA对象返回。<br>  与其他的ORM(对象关系映射)框架不同,MyBatis并没有将Java对象与数据库表关联起来,而是将Java方法与SQL语句关联。MyBatis允许用户充分利用数据库的各种功能,例如存储过程、视图、各种复杂的查询以及某数据库的专有特性。如果要对遗留数据库、不规范的数据库进行操作,或者要完全控制SQL的执行,MyBatis将会是一个不错的选择。<br>  与JDBC相比,MyBatis简化了相关代码,SQL语句在一行代码中就能执行。MyBatis提供了一个映射引擎,声明式地将SQL语句地执行结果与对象树映射起来。通过使用一种内嵌地XMl表达式语言,SQL语句可以被动态生成。<br>  MyBatis支持生命是数据缓存(declarative data caching).当一条SQL语句被标记为”可缓存”后,首次执行它时从数据库获取地所有数据会被存储在高速缓存中,后面在执行这条语句时会从高速缓存中读取结果,而不是再次命中数据库。MyBatis提供了默认情况下基于Java HashMap地缓存实现,以及用于OSCache、Encache、Hazelcast和Memcached连接地默认连接器,同时还提供了API供其他缓存实现使用。 </p>
<h2 id="创建项目后地相关依赖"><a href="#创建项目后地相关依赖" class="headerlink" title="创建项目后地相关依赖"></a>创建项目后地相关依赖</h2><pre><code class="java"><dependencies>
<!-- Junit依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- MyBatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!-- Log4j依赖-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies> </code></pre>
<h2 id="配置MyBtis"><a href="#配置MyBtis" class="headerlink" title="配置MyBtis"></a>配置MyBtis</h2><p>  配置MyBatis有多种方式,本节使用最基础最常用地XMl形式进行配置。 </p>
<ul>
<li>注意:除XML方式外,在后面介绍和Spring集成地时候还会使用SpringBean方式进行配置。另外还可以通过Java编码方式进行配置。但Java编码配置方式不常用。 </li>
</ul>
<p>  使用XML形式进行配置,首先在src/main/resources下面创建mybatis-config.xml配置文件,具体内容如下: </p>
<pre><code class="java"><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 指定使用LOG4J输出日志-->
<settings>
<setting name="logImpl" value="LOG4J"/>
<!-- 此配置属性为true可以自动将以下划线命名的数据库列映射到Java对象的驼峰式命名属性中。-->
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/>-->
</settings>
<!-- 配置一个包名,以免MyBatis频繁使用全限定名称-->
<typeAliases>
<package name="tk.mybatis.simple.model"></package>
</typeAliases>
<!-- 配置数据库连接-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="" value=""/>
</transactionManager>
<dataSource type="UNPOOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 配置一个包含完整类路径的CountryMapper.xml,这是一个MyBatis的SQL语句与映射配置文件-->
<mappers>
<!-- 这是单个配置-->
<!-- <mapper resource="tk/mybatis/simple/mapper/CountryMapper.xml"></mapper>-->
<!--直接使用整个包配置-->
<package name="tk.mybatis.simple.mapper"/>
</mappers>
</configuration></code></pre>
<p>  相关配置的含义: </p>
<ul>
<li><settings>中的logImpl属性指定使用LOG4J输出日志。 </li>
<li><typeAliases>元素下面配置了一个包的别名,通常确定一个类的时候需要使用类的全限定名称,例如:tk.mybatis.simple.model.Country。在MyBatis中需要频繁用到类的全限定名称,为了方便使用,我们配置了tk.mybatis.simple.model包,这样配置后,在使用类的时候不需要写包名的部分,只是用Country即可。 </li>
<li><enviroments>环境配置中主要配置了数据库连接,数据库的url为jdbc:mysql//localhost:3306/mybatis,使用的是本机MySQL中的mybatis数据库,后面的username和password分别是数据库的用户名和密码。 </li>
<li><mapper>中配置了一个包含完整类路的CountryMapper.xml,这是一个MyBatis的SQL语句和映射文件,这个XMl会在后面介绍。<br><font color="red">注意在原始代码中由于md语法需要,符号’<’要写成’<’</font> </li>
</ul>
<h2 id="创建实体类和Mapper-xml文件"><a href="#创建实体类和Mapper-xml文件" class="headerlink" title="创建实体类和Mapper.xml文件"></a>创建实体类和Mapper.xml文件</h2><p>  MyBatis是一个姐u哦映射框架,这里创建的实体类实际上是一个数据值对象(Data Value Object),在实际应用中,一个表一般会对应一个实体,用于INSERT、UPDATE、DELETE和简单的SELECT操作,所以姑且称这个简单的对象为实体类。 </p>
<ul>
<li>提示!关于Mapper的明明方式:在MyBatis中,根据MyBayis官方的习惯,一般用Mapper作为XML和接口类名的后缀,这里的Mapper和我们常用DAO后缀类似,只是一种习惯而已,本书中全部使用Mapper后缀。通常称XMl为Mapper.xml文件,称接口为Mapper接口,在实际应用中可以根据自己的需要来定义命名方式。 </li>
</ul>
<p>  下面我们先展示一下这个项目的目录结构:图片已上传到远端,在本地加载不出来?<br><img src="https://github.com/seasky-wjl/MyBatisIndoor/blob/main/note/Mybatis%E5%85%A5%E9%97%A8/imgs/projectStructure.PNG" alt="该项目的目录结构" title="该项目的目录结构"></p>
<p>  在src/main/java下创建一个基础的包tk.mybatis.simple,在这个包下面再创建model包。根据数据库表名country,再model包下创建实体类Country。属性与数据库中的一一对应。 </p>
<p>  在src/main/resoures下面创建tk/mybatus/simple/mapper目录,再在该目录下面创建CountryMapper.xml文件,内容如下: </p>
<pre><code class="java"> <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="tk.mybatis.simple.mapper.CountryMapper">
<select id="selectAll" resultType="Country">
select id,countryname,countrycode from country
</select>
</mapper> </code></pre>
<p>SQL定义在CounryMapper.xml文件中,里面的配置作用如下。 </p>
<ul>
<li><mapper>元素:XML的根元素,属性namespace定义了当前XMl的命名空间。 </li>
<li><select>元素:我们所定义的一个SELECT查询。 </li>
<li>id属性:定义了当前查询的返回值类型,此处就是指十日类COuntry,前面配置中提到的别名主要用于这里,如果没有设置别名,此处就需要写成resultType=”tk.mybatis.simple.model.Country”。</li>
<li>select id,…:查询SQL语句。 </li>
</ul>
<p>   创建好实体和Mapper.xml后,接下来要有针对性地配置Log4j,让MyBatis在执行数据库操作地时候可以将执行的SQL和其他信息输出到控制台。 </p>
<h2 id="配置Log4j"><a href="#配置Log4j" class="headerlink" title="配置Log4j"></a>配置Log4j</h2><p>  在src/main/resources中添加log4j.properties配置文件,输入如下内容。 </p>
<pre><code class="java"> # 全局配置
log4j.rootLogger=ERROR, stdout
# MyBatis日志配置
log4j.logger.tk.mybatis.simple.mapper=TRACE
# 控制台输出配置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n</code></pre>
<blockquote>
<p>日志注意事项!<br>  用过Log4j日志组件的人可能都会知道,配置中的log4j.logger.tk.mybatis.simple.mapper对应的是tk.mybatis.simple.mapper包,但是目前为止,该例子中Java目录下并没有这个报名,只有在资源目录下有mapper目录。<br>  在MyBatis的日志实现中,所谓包名实际上是XML配置中的namespace属性值的一部分。后面章节中介绍结合接口使用的相关内容时,由于namespace属性值必须和接口全限定类名相同,因此才会真正对应到Java中的包。当使用纯注解方式时,使用就是纯粹的包名。<br>  MyBatis日志的最低级别是TRACE,在这个日志级别下,M有B按提示、会输出执行SQL过程的详细信息,这个级别特别适合在开发时使用。</p>
</blockquote>
</div>
<footer class="article-footer">
<a data-url="http://example/2023/02/06/MyBatis%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A%E7%AC%AC1%E7%AB%A0/" data-id="clemvoh6u00007s7ef6v28r7v" data-title="第1章:MyBatis入门" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/MyBatis%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A/" rel="tag">MyBatis从入门到精通</a></li></ul>
</footer>
</div>
</article>
<article id="post-基于笔画识别的手写汉字美化方法研究华科2020" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2022/10/03/%E5%9F%BA%E4%BA%8E%E7%AC%94%E7%94%BB%E8%AF%86%E5%88%AB%E7%9A%84%E6%89%8B%E5%86%99%E6%B1%89%E5%AD%97%E7%BE%8E%E5%8C%96%E6%96%B9%E6%B3%95%E7%A0%94%E7%A9%B6%E5%8D%8E%E7%A7%912020/" class="article-date">
<time class="dt-published" datetime="2022-10-03T11:01:16.000Z" itemprop="datePublished">2022-10-03</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2022/10/03/%E5%9F%BA%E4%BA%8E%E7%AC%94%E7%94%BB%E8%AF%86%E5%88%AB%E7%9A%84%E6%89%8B%E5%86%99%E6%B1%89%E5%AD%97%E7%BE%8E%E5%8C%96%E6%96%B9%E6%B3%95%E7%A0%94%E7%A9%B6%E5%8D%8E%E7%A7%912020/">基于笔画识别的手写汉字美化方法研究华科2020</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h2 id="Article"><a href="#Article" class="headerlink" title="Article:"></a>Article:</h2><p>潘冬冬. 基于笔画识别的手写汉字美化方法研究[D].华中科技大学,2020.DOI:10.27157/d.cnki.ghzku.2020.002244.</p>
<hr>
<h2 id="Data"><a href="#Data" class="headerlink" title="Data:"></a>Data:</h2><p>题目:<br> 基于笔画识别的手写汉字美化方法研究 </p>
<p> 提出了一种基于笔画识别的手写汉字美化方法,它融合了笔画识别与拐点检测、笔画结构以及笔画轮廓美化等方法。虽然作者是采用联机的方式来进行这一研究。 </p>
<p>背景:<br> 美化汉字的主流研究方向有3种:</p>
<ol>
<li>以整字为基本单位,对用户手写汉字识别后将其替换为标准字体; </li>
<li>以笔画为基本单位,直接对笔画进行美化,对用户手写汉字的所有壁画进行美化即完成了汉字的美化; </li>
<li>首先对笔画进行笔画识别和笔画拐点检测,利用笔画拐点检测的结果将笔画分解为多个笔段,然后根据笔画识别的结果利用自己的美化算法针对性的对每个笔段进行美化,最后美化后的笔段拼接起来即完成了笔画的美化。 </li>
</ol>
<p>研究现状: </p>
<pre><code>汉字美化:</code></pre>
<p> Elena J. Jakubia提出一种 SSF(Stylized Stroke Fonts)的方法,该方法提出每一个字形由三部分构成:一条由线段和贝塞尔曲线构成的笔画路径、一系列描述笔画宽度的参数、以及一系列的端点。这和夏伟平提出的将每一个笔画分解为笔段和连接点,然后分别对笔段和连接点进 行建模,最后将笔段和连接点按照每个笔画的规则连接起来的思想非常相似。<br>刘丽娟在夏伟平的方法的基础上进行了进一步的丰富和完善,其对笔段和拐点的分类更加完善,对笔段和连接点的拼接规则考虑到汉字的整体结构,更加科学严谨。<br>本文的手写汉字美化算法将在刘丽娟提出的算法基础上对笔画识别和笔画拐点检测算法进行优化,并进行 笔画结构调整。 </p>
<pre><code>笔画识别:</code></pre>
<p> Xinyue Zhang提出使用卷积神经网络来进行笔画识别,其具体做法是将汉字笔画划分为20种,自建数据集,请20个志愿者为每一种笔画写200次,之后利用自建数据集和卷积神经网络训练出笔画识别的模型,并使用该模型进行笔画分类,对笔画分类为20类,而本文将笔画分类为32类。</p>
<pre><code>笔画拐点检测:</code></pre>
<p> 拐点检测是汉字美化的步骤之一,通过拐点检测之后将笔画分解为笔段和连接点,然后分别对笔段和连接点建模,最后将笔段和连接点连接起来,完成美化。<br>目前较为常见的进行拐点(数学上是二阶导数变号的点,或者是原图像凹凸变换的那个点)检测的算法为利用弯曲值检测拐点。<br>本文中采用卷积神经网络进行笔画拐点检测。</p>
<pre><code>笔画结构调整:</code></pre>
<p> 笔画结构调整是对用户输入的轨迹进行整体结构的调整和笔画层面的调整,以 使得其满足特定书法的特征。<br>但刘丽娟在其论文中对结构调整非常有限。</p>
<p>方法:<br> 本文首先使用卷积神经网络进行笔画识别和拐点检测等问题;在一般手写汉字美化方案的笔画步骤前增加笔画结构调整,使用户手写汉字笔画结构更接近标准书法笔画结构;最后以问卷调查 的形式将本文美化效果与前任美化效果进行对比。<br>使用 ResNet18 训练笔画识别模型,使用 CPM(卷积姿态机)完成了笔画拐点检测模型的训练。<br>从五个方面进行结构调整:整体结构变换、拟合贝塞尔曲线、角度调整、对钩的处理、替换 “横撇弯钩”。</p>
<hr>
<h2 id="Comments:"><a href="#Comments:" class="headerlink" title="Comments:"></a>Comments:</h2><p> 使用了目前比较热门的卷积神经网络来训练模型,让笔画识别和笔画拐点检测等问题的准确率都得到了一定提升。<br>我们的课题可以用到与作者类似的方法,笔画识别、拐点检测、再根据特定笔画结构的特点,对该笔画的书写进行评价并作修改意见。<br>因为本文的目的就是对用户在设备上手写的汉字进行美化,所以它没有对用户这个字写的好不好的量化标准,不管用户写的好不好,都会对其进行美化,但是可以从这个美化的标准中去寻找我们需要的量化标准,如果可以,可以直接将原来的字与美化后的字来进行一个对比,美化的地方即是用户可以提升的地方。</p>
<p>关于数据集:<br> 目前关于手写汉字笔画没有公开的数据集。手写汉字有几个比较知名的公开数据集,哈大深采集的 HIT-OR3C、华南理工大学采集的SCUT-COUCH009、中科院采集的 CASIA-OLHWDB1.0 和 1.1 数据集。由于这些数据集在用户的手写汉字轨迹,存在大量连笔,本文作者自建了手写汉字笔画的数据集。</p>
<hr>
<h2 id="Why"><a href="#Why" class="headerlink" title="Why:"></a>Why:</h2><p>了解汉字识别的课题背景,学习前人的实验方法。</p>
<hr>
<h2 id="Summary"><a href="#Summary" class="headerlink" title="Summary:"></a>Summary:</h2><p>对于用户在设备上手写的汉字,识别笔画、笔画拐点,将笔画分解为笔段和连接点,对其分别建模,再连接起来形成笔画。最后进行笔画的结构调整以达到整个汉字美化的目的。</p>
</div>
<footer class="article-footer">
<a data-url="http://example/2022/10/03/%E5%9F%BA%E4%BA%8E%E7%AC%94%E7%94%BB%E8%AF%86%E5%88%AB%E7%9A%84%E6%89%8B%E5%86%99%E6%B1%89%E5%AD%97%E7%BE%8E%E5%8C%96%E6%96%B9%E6%B3%95%E7%A0%94%E7%A9%B6%E5%8D%8E%E7%A7%912020/" data-id="clemvoh7j00097s7e6yf27gtk" data-title="基于笔画识别的手写汉字美化方法研究华科2020" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E7%9C%8B%E6%96%87%E7%8C%AE/" rel="tag">看文献</a></li></ul>
</footer>
</div>
</article>
<article id="post-基于-相似度-的手写汉字识别与美感评分北邮2019" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2022/09/29/%E5%9F%BA%E4%BA%8E-%E7%9B%B8%E4%BC%BC%E5%BA%A6-%E7%9A%84%E6%89%8B%E5%86%99%E6%B1%89%E5%AD%97%E8%AF%86%E5%88%AB%E4%B8%8E%E7%BE%8E%E6%84%9F%E8%AF%84%E5%88%86%E5%8C%97%E9%82%AE2019/" class="article-date">
<time class="dt-published" datetime="2022-09-29T12:54:17.000Z" itemprop="datePublished">2022-09-29</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2022/09/29/%E5%9F%BA%E4%BA%8E-%E7%9B%B8%E4%BC%BC%E5%BA%A6-%E7%9A%84%E6%89%8B%E5%86%99%E6%B1%89%E5%AD%97%E8%AF%86%E5%88%AB%E4%B8%8E%E7%BE%8E%E6%84%9F%E8%AF%84%E5%88%86%E5%8C%97%E9%82%AE2019/">基于_相似度_的手写汉字识别与美感评分北邮2019</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h1 id="基于-相似度-的手写汉字识别与美感评分北邮2019"><a href="#基于-相似度-的手写汉字识别与美感评分北邮2019" class="headerlink" title="基于_相似度_的手写汉字识别与美感评分北邮2019"></a><center>基于_相似度_的手写汉字识别与美感评分北邮2019</center></h1><h2 id="Article"><a href="#Article" class="headerlink" title="Article:"></a>Article:</h2><p>[1]庄子明. 基于深度学习的手写汉字识别与美感评分[D].北京邮电大学,2019.<br>==<em>基于相似度的手写汉字美感评分</em> </p>
<hr>
<h2 id="Data:"><a href="#Data:" class="headerlink" title="Data:"></a>Data:</h2><p>题目:<br>基于深度学习的手写汉字识别与美感评分</p>
<p>背景:<br>数据采集方式有两种:联机和脱机。前者可以记录笔者笔顺轨迹、笔画数量等信息、识别对象具有时间顺序的采样点信息,需要有特定输入设备,实际场景比较少。脱机的使用场景更多,但会缺少笔顺信息,有光照、分辨率、书写背景等不同条件的干扰。</p>
<p>汉字识别研究背景:<br>基于传统的“预处理+特征提取+分类器”的HCCR框架在识别性能上突破不够。随着研究者们将许多深度学习模型,如深度卷积神经网络(CNN)、深度置信网络(DBN)、深度递归神经网络(DRNN)应用到手写文字识别,取得了大量突破。</p>
<p>美感分析的现状:<br>传统的方法基本都专注于探索文字的特征构建和优化特征提取方法,如陈惠敏等人按照书写特征,将汉字的笔画简单地分为直线笔画和弧线笔画,分别给出了识别模型和评估算法,评价结果波动较大;李玉峰等人在工程制图字体场景下通过抓取手写字体的点阵特征根据汉字在结构方面特征相似度来评价书写质量,但这仅限于规定格式的标准书写字体;李艺等人提出了从笔画。部件、整字等三个层次建立汉字书写特征集,并以此为依据对书写者硬币汉字书写的工整性进行评价;王耀等人针对四线格英文字母书写练习场景,提出了规定格式书写质量评价方法,分别从比例、位置、大小、畸变四个方面分析参照字符与被分析字符的参数距离,给出书写的质量评价,这一方法直接应用于手写汉字效果并不很理想。</p>
<p>方法:<br>手写汉字没敢评价方法非常依赖对汉字的特征提取和分析。深度学习的一大优势是消除了复杂的特征工程的困难挑战,只需要将数据直接传递到网络,通过可以让计算机自动学习出模型特征,让特征学习融入到建立模型的过程中。</p>
<p>深度学习的根本原理是利用海量的数据在多隐层网络中训练模型,学习数据中有价值的信息——特征。深度学习的本质是特征学习。</p>
<p>对于手写汉字的识别和美感评分,最难也是最关键的核心就是特征提取。而无监督是深度学习学习最大的特点,在训练时无需人工进行特征提取,全过程自主取样自主学习。</p>
<p>模型分为三大部分:汉字检测、识别、美感评分。</p>
<p>作者使用自然场景下手写汉字检测模型–连接文本区域候选网络(CTPN)的相关原理和细节,将RNN的网络结构与Faster-RCNN网络相结合,既可以提取到深度特征,也能够进行序列的特征识别。<br>手写汉字识别模型——HCCR-GoogleLeNet网络,将手动提取的汉字特征作为先验知识嵌入到深度卷积神经网络中,有助于网络更好地学习到汉字辅助特征。</p>
<p>作者将传统的评价手写汉字美感的两类结构特征——重心特征和网格特征与CNN特征结合来优化手写汉字美感评分效果。</p>
<p> <font color="yellow">作者的相似度检索策略的思路为:将待测汉字与已含有美感类别标签的手写汉字数据库进行相似度检索,根据检索出来的手写美感类别标签确定待测的手写汉字的美感分数。手写汉字相似度检索分成两部分:手写汉字特征的提取与手写汉字特征的距离度量。</font></p>
<p>形近字难以区分,可以用什么方法来根据语境推测这到底是什么字。</p>
<hr>
<h2 id="Comments:"><a href="#Comments:" class="headerlink" title="Comments:"></a>Comments:</h2><p>先选一部分字让们打分,算出每个字的平均分,再让模型学习,学习完了之后,就可以直接用这个模型根据库中已有文字及其分数来对新的手写汉字进行打分,而且结果是写得越好的字,它的得分的准确率就会越高,因为好的标准已经确定,且笔画的结构相似度越高;而写得越不好的字,它的得分的准确率就会相对较低。</p>
<p>这篇文章就是老师说的情况,只是通过它的相似度去给出一个评价,而没有去给这个字怎样写得更好去提出建议和指导。</p>
<p>作者认识到,这个系统将检测、识别、美感评分散步分别构建了三个深度学习的网络模型,而且在实验过程中,基于相似度检索的手写汉字没敢评分CNN网络实际上具有一定成都的手写汉字识别功能,既可以通过待评分汉字与数据库中已有汉字的特征相似度的距离排序来确定汉字的识别结果,但目前准确度还不高。</p>
<hr>
<h2 id="Why:"><a href="#Why:" class="headerlink" title="Why:"></a>Why:</h2><p>了解汉字识别的课题背景,学习前人的实验方法。</p>
<hr>
<h2 id="Summary:"><a href="#Summary:" class="headerlink" title="Summary:"></a>Summary:</h2><p>基于相似度的手写汉字美感评分。</p>
</div>
<footer class="article-footer">
<a data-url="http://example/2022/09/29/%E5%9F%BA%E4%BA%8E-%E7%9B%B8%E4%BC%BC%E5%BA%A6-%E7%9A%84%E6%89%8B%E5%86%99%E6%B1%89%E5%AD%97%E8%AF%86%E5%88%AB%E4%B8%8E%E7%BE%8E%E6%84%9F%E8%AF%84%E5%88%86%E5%8C%97%E9%82%AE2019/" data-id="clemvoh7i00087s7e6p8571f3" data-title="基于_相似度_的手写汉字识别与美感评分北邮2019" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E7%9C%8B%E6%96%87%E7%8C%AE/" rel="tag">看文献</a></li></ul>
</footer>
</div>
</article>
<article id="post-看文献应该做什么" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2022/09/29/%E7%9C%8B%E6%96%87%E7%8C%AE%E5%BA%94%E8%AF%A5%E5%81%9A%E4%BB%80%E4%B9%88/" class="article-date">
<time class="dt-published" datetime="2022-09-29T12:49:33.000Z" itemprop="datePublished">2022-09-29</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2022/09/29/%E7%9C%8B%E6%96%87%E7%8C%AE%E5%BA%94%E8%AF%A5%E5%81%9A%E4%BB%80%E4%B9%88/">看文献应该做什么</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h1 id="看一篇文献后需要干什么"><a href="#看一篇文献后需要干什么" class="headerlink" title="看一篇文献后需要干什么"></a><center>看一篇文献后需要干什么</center></h1><p>看一篇文献需要做以下工作:<br>Article: 文献出处(方便再次搜索)<br>Data: 文献数据(总结归纳,方便理解)<br>Comments: 对文献的想法 (强迫自己思考,结合自己的学科)<br>Why: 为什么看这篇文献 (方便再次搜索)<br>Summary: 文献方向归纳 (方便分类管理) </p>
<ol>
<li><p>Article:记录文献出处,包括作者、文献题目、文献时间。</p>
</li>
<li><p>Data:文献数据,包括这篇文章的题目、背景介绍、方法、结果、结论。</p>
</li>
<li><p>Comments:自己的想法,记录自己看了文章之后有什么想法,创新点,不足之处,经验教训等等等。</p>
</li>
<li><p>Why:为什么?即为什么要精读这篇文献,为什么做文献笔记?原因可以是:了解课题背景,用于实验设计,用于写作仿真等。</p>
</li>
<li><p>Summary:文献总结。用尽量少的话来概括此文。可以是文献关键词的组合,也可以是自己的总结。目的是为了让你以后对相关文献笔记进行分类,搜索的时候也更容易。</p>
</li>
</ol>
</div>
<footer class="article-footer">
<a data-url="http://example/2022/09/29/%E7%9C%8B%E6%96%87%E7%8C%AE%E5%BA%94%E8%AF%A5%E5%81%9A%E4%BB%80%E4%B9%88/" data-id="clemvoh86001d7s7e7zgefpeo" data-title="看文献应该做什么" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E7%9C%8B%E6%96%87%E7%8C%AE/" rel="tag">看文献</a></li></ul>
</footer>
</div>
</article>
<article id="post-morris遍历" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2022/09/11/morris%E9%81%8D%E5%8E%86/" class="article-date">
<time class="dt-published" datetime="2022-09-11T14:24:15.000Z" itemprop="datePublished">2022-09-11</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2022/09/11/morris%E9%81%8D%E5%8E%86/">morris遍历</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h1 id="morris遍历"><a href="#morris遍历" class="headerlink" title="morris遍历"></a><center>morris遍历</center></h1><h2 id="前序遍历"><a href="#前序遍历" class="headerlink" title="前序遍历"></a>前序遍历</h2><p>核心思想是利用大量空闲指针,实现空间开销的极限缩减。其前序遍历规则总结如下:<br>1.新建临时节点,另该节点为root;<br>2.如果当前节点的左子节点为空,将当前节点加入答案,并遍历当前节点的右子节点。<br>3.如果当前节点的左子节点不为空,在当前节点的左子树中找到当前节点在中序遍历中的前驱节点:<br> 1).如果前驱节点的右子节点为空,将前驱节点设置为当前节点。然后将当前节点加入答案,并将前驱节点的右子节点更新为当前节点。当前节点更新为当前节点的左子节点。<br> 2).如果前驱节点的右子节点为当前节点,将他的右边子节点重新设为空。当前节点更新为当前节点的右子节点。<br>4.重复步骤2和3,直到遍历结束。<br>Java代码为:</p>
<pre><code>public List<Integer> preorderTraverse(TreeNode root){
List<Integer> res=new ArrayList<>();
TreeNode p1=root,p2=null;
while(p1!=null){
p2=p1.left;
if(p2!=null){
while(p2.right!=null && p2.right!=p1){
p2=p2.right; //去找p1的中序遍历前驱节点
}
if(p2.right==null){ //前驱找到且还没把p1链接到右孩子
res.add(p1.val);
p2.right=p1;
p1=p1.left; //p1向左子树走
continue;
}else{
p1=p2.right;
}
}else{
add(p1.val);
}
p1=p1.right;
}
return res;
}</code></pre>
<p>复杂度分析: </p>
<ul>
<li>时间:O(n),其中n是二叉树的节点数。没有左子树的节点制备访问一次,有左子树的节点被访问两次。 </li>
<li>空间:O(1),只需常数的额外空间。 </li>
</ul>
<h2 id="后序遍历"><a href="#后序遍历" class="headerlink" title="后序遍历"></a>后序遍历</h2><p>其后序遍历规则总结如下:<br>1.新建临时节点,令该节点为 root;<br>2.如果当前节点的左子节点为空,则遍历当前节点的右子节点;<br>3.如果当前节点的左子节点不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点;<br> 1).如果前驱节点的右子节点为空,将前驱节点的右子节点设置为当前节点,当前节点更新为当前节点的左子节点。<br> 2).如果前驱节点的右子节点为当前节点,将它的右子节点重新设为空。倒序输出从当前节点的左子节点到该前驱节点这条路径上的所有节点。当前节点更新为当前节点的右子节点。<br>4.重复步骤 2 和步骤 3,直到遍历结束。 </p>
<p>Java代码为:</p>
<pre><code>public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) {
return res;
}
TreeNode p1 = root, p2 = null;
while (p1 != null) {
p2 = p1.left;
if (p2 != null) {
while (p2.right != null && p2.right != p1) {
p2 = p2.right;
}
if (p2.right == null) {
p2.right = p1;
p1 = p1.left;
continue;
} else {
p2.right = null;
addPath(res, p1.left);
}
}
p1 = p1.right;
}
addPath(res, root);
return res;
}
public void addPath(List<Integer> res, TreeNode node) {
int count = 0;
while (node != null) {
++count;
res.add(node.val);
node = node.right;
}
int left = res.size() - count, right = res.size() - 1;
while (left < right) {
int temp = res.get(left);
res.set(left, res.get(right));
res.set(right, temp);
left++;
right--;
}
}</code></pre>
<p>复杂度分析: </p>
<ul>
<li>时间复杂度:O(n)O(n),其中 nn 是二叉树的节点数。没有左子树的节点只被访问一次,有左子树的节点被访*问两次。 </li>
<li>空间复杂度:O(1)O(1)。只操作已经存在的指针(树的空闲指针),因此只需要常数的额外空间。</li>
</ul>
</div>
<footer class="article-footer">
<a data-url="http://example/2022/09/11/morris%E9%81%8D%E5%8E%86/" data-id="clemvoh7w000s7s7ee5846kfj" data-title="morris遍历" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E7%AE%97%E6%B3%95/" rel="tag">算法</a></li></ul>
</footer>
</div>
</article>
<article id="post-第13章分组数据" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2022/07/18/%E7%AC%AC13%E7%AB%A0%E5%88%86%E7%BB%84%E6%95%B0%E6%8D%AE/" class="article-date">
<time class="dt-published" datetime="2022-07-18T10:56:21.000Z" itemprop="datePublished">2022-07-18</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2022/07/18/%E7%AC%AC13%E7%AB%A0%E5%88%86%E7%BB%84%E6%95%B0%E6%8D%AE/">第13章分组数据</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h1 id="第13章:分组数据"><a href="#第13章:分组数据" class="headerlink" title="第13章:分组数据"></a><center>第13章:分组数据</center></h1><h2 id="13-1-数据分组"><a href="#13-1-数据分组" class="headerlink" title="13.1 数据分组"></a>13.1 数据分组</h2><p> 从上一章知道,SQL聚集函数可用来汇总数据。这使我们能够对行进<br>行计数,计算和与平均数,获得最大和最小值而不用检索所有数据。<br> 目前为止的所有计算都是在表的所有数据或匹配特定的WHERE子句的<br>数据上进行的。提示一下,下面的例子返回供应商1003提供的产品数目:</p>
<blockquote>
<p>输入:SELECT COUNT(*) AS num_prods FROm products WHERE vend_id=1003; </p>
</blockquote>
<p>输出: </p>
<table>
<thead>
<tr>
<th align="center">num_prods</th>
</tr>
</thead>
<tbody><tr>
<td align="center">7</td>
</tr>
</tbody></table>
<p> 但如果要返回每个供应商提供的产品数目怎么办?或者返回只提供单项产品的供应商所提供的产品,或返回提供10个以上产品的供应商怎么办?这就是分组显身手的时候了。分组允许把数据分为多个逻辑组,以便能对每个组进行聚集计算。</p>
<h2 id="13-2-创建分组"><a href="#13-2-创建分组" class="headerlink" title="13.2 创建分组"></a>13.2 创建分组</h2><p> 分组是在SELECT语句的GROUP BY子句中建立的。理解分组的最好办法是看一个例子: </p>
<blockquote>
<p>输入:SELECT vend_id ,COUNT(*) AS num_prods FROm products GROUP BY vend_id; </p>
</blockquote>
<p>输出:</p>
<table>
<thead>
<tr>
<th align="left">vend_id</th>
<th align="left">num_prods</th>
</tr>
</thead>
<tbody><tr>
<td align="left">1001</td>
<td align="left">3</td>
</tr>
<tr>
<td align="left">1002</td>
<td align="left">2</td>
</tr>
<tr>
<td align="left">1003</td>
<td align="left">7</td>
</tr>
<tr>
<td align="left">1005</td>
<td align="left">2</td>
</tr>
</tbody></table>
<blockquote>
<p>分析:上面的SELECT语句指定了两个列,vend_id包含产品供应商的ID,num_prods为计算字段(用COUNT(*)函数建立)。GROUP BY子句指示MySQL按vend_id排序并分组数据。这导致对每个vend_id而不是整个表计算num_prods一次。从输出中可以看到,供应商1001有3个产品,供应商1002有2个产品,供应商1003有7个产品,而供应商1005有2个产品。</p>
</blockquote>
<p> 因为使用了GROUP BY,就不必指定要计算和估值的每个组了。系统会自动完成。GROUP BY子句指示MySQL分组数据,然后对每个组而不是整个结果集进行聚集。<br> 在具体使用GROUP BY子句前,需要知道一些重要的规定。</p>
<ol>
<li><p>GROUP BY子句可以包含任意数目的列。这使得能对分组进行嵌套,为数据分组提供更细致的控制。</p>
</li>
<li><p>如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算(所以不能从个别的列取回数据)。</p>
</li>
<li><p> GROUP BY子句中列出的每个列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式。不能使用别名。</p>
</li>
<li><p>除聚集计算语句外,SELECT语句中的每个列都必须在GROUP BY子句中给出。</p>
</li>
<li><p>如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列中有多行NULL值,它们将分为一组。</p>
</li>
<li><p>GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。</p>
<pre><code> 使用ROLLUP 使用WITH ROLLUP关键字,可以得到每个分组以及每个分组汇总级别(针对每个分组)的值,如下所示:</code></pre>
</li>
</ol>
<h2 id="13-3-过滤分组"><a href="#13-3-过滤分组" class="headerlink" title="13.3 过滤分组"></a>13.3 过滤分组</h2><p> 除了能用GROUP BY分组数据外,MySQL还允许过滤分组,规定包括哪些分组,排除哪些分组。例如,可能想要列出至少有两个订单的所有顾客。为得出这种数据,必须基于完整的分组而不是个别的行进行过滤。<br> 我们已经看到了WHERE子句的作用(第6章中引入)。但是,在这个例子中WHERE不能完成任务,因为WHERE过滤指定的是行而不是分组。事实上,WHERE没有分组的概念。<br> 那么,不使用WHERE使用什么呢?MySQL为此目的提供了另外的子句,那就是HAVING子句。HAVING非常类似于WHERE。事实上,目前为止所学过的所有类型的WHERE子句都可以用HAVING来替代。唯一的差别是WHERE过滤行,而HAVING过滤分组。</p>
<pre><code> HAVING支持所有WHERE操作符 在第6章和第7章中,我们学习了WHERE子句的条件(包括通配符条件和带多个操作符的子句)。所学过的有关WHERE的所有这些技术和选项都适用于HAVING。它们的句法是相同的,只是关键字有差别。</code></pre>
<blockquote>
<p>输入: SELECT cust_id,COUNT(<em>) AS orders FROM orders GROUP BY cust_id HAVING COUNT(</em>)>=2;</p>
</blockquote>
<p>输出:</p>
<table>
<thead>
<tr>
<th align="center">cust_id</th>
<th align="center">orders</th>
</tr>
</thead>
<tbody><tr>
<td align="center">10001</td>
<td align="center">2</td>
</tr>
</tbody></table>
<blockquote>
<p>分析:这条SELECT语句的前3行类似于上面的语句。最后一行增加了HAVING子句,它过滤COUNT(*) >=2(两个以上的订单)的那些分组。正如所见,这里WHERE子句不起作用,因为过滤是基于分组聚集值而<br>不是特定行值的。</p>
</blockquote>
<pre><code> HAVING和WHERE的差别 这里有另一种理解方法,WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。这是一个重要的区别,WHERE排除的行不包括在分组中。这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组。</code></pre>
<p> 那么,有没有在一条语句中同时使用WHERE和HAVING子句的需要呢?事实上,确实有。假如想进一步过滤上面的语句,使它返回过去12个月内具有两个以上订单的顾客。为达到这一点,可增加一条WHERE子句,过滤出过去12个月内下过的订单。然后再增加HAVING子句过滤出具有两个<br>以上订单的分组。<br> 为更好地理解,请看下面的例子,它列出具有2个(含)以上、价格<br>为10(含)以上的产品的供应商:</p>
<blockquote>
<p>输入:SELECT vend_id,COUNT(<em>) AS num_prods FROM products WHERE prod_price >= 10 GROUP BY vend_id HAVING COUNT(</em>)>=2;</p>
</blockquote>
<p>输出:</p>
<table>
<thead>
<tr>
<th align="center">vend_id</th>
<th align="center">num_prods</th>
</tr>
</thead>
<tbody><tr>
<td align="center">1003</td>
<td align="center">4</td>
</tr>
<tr>
<td align="center">1005</td>
<td align="center">2</td>
</tr>
</tbody></table>
<blockquote>
<p>分析:这条语句中,第一行是使用了聚集函数的基本SELECT,它与前面的例子很相像。WHERE子句过滤所有prod_price至少为10的行。然后按vend_id分组数据,HAVING子句过滤计数为2或2以上的分组。如果没有WHERE子句,将会多检索出两行(供应商1002,销售的所有产品价格都在10以下;供应商1001,销售3个产品,但只有一个产品的价格大于等于10):</p>
</blockquote>
<blockquote>
<p>输入:SELECT vend_id,COUNT(<em>) AS num_prods FROM products GROUP BY vend_id HAVING COUNT(</em>)>=2;</p>
</blockquote>
<p>输出:</p>
<table>
<thead>
<tr>
<th align="center">vend_id</th>
<th align="center">num_prods</th>
</tr>
</thead>
<tbody><tr>
<td align="center">1001</td>
<td align="center">3</td>
</tr>
<tr>
<td align="center">1002</td>
<td align="center">2</td>
</tr>
<tr>
<td align="center">1003</td>
<td align="center">7</td>
</tr>
<tr>
<td align="center">1005</td>
<td align="center">2</td>
</tr>
</tbody></table>
<h3 id="13-4-分组和排序"><a href="#13-4-分组和排序" class="headerlink" title="13.4 分组和排序"></a>13.4 分组和排序</h3><p> 虽然GROUP BY和ORDER BY经常完成相同的工作,但它们是非常不同<br>的。下表展示了它们之间的差别。</p>
<table>
<thead>
<tr>
<th align="center">ORDER BY</th>
<th align="center">GROUP BY</th>
</tr>
</thead>
<tbody><tr>
<td align="center">排序产生的输出</td>
<td align="center">分组行。但输出可能不是分组的顺序</td>
</tr>
<tr>
<td align="center">任意列都可以使用(甚至非选择的列也可以使用)</td>
<td align="center">只可能使用选择列或表达式列,而且必须使用每个选择列表达式</td>
</tr>
<tr>
<td align="center">不一定需要</td>
<td align="center">如果与聚集函数一起使用列(或表达式),则必须使用</td>
</tr>
</tbody></table>
<p> 表中列出的第一项差别极为重要。我们经常发现用GROUP BY分组的数据确实是以分组顺序输出的。但情况并不总是这样,它并不是SQL规范所要求的。此外,用户也可能会要求以不同于分组的顺序排序。仅因为你以某种方式分组数据(获得特定的分组聚集值),并不表示你需要以相同的方式排序输出。应该提供明确的ORDER BY子句,即使其效果等同于GROUP BY子句也是如此。</p>
<pre><code> 不要忘记ORDER BY 一般在使用GROUP BY子句时,应该也给出ORDER BY子句。这是保证数据正确排序的唯一方法。千万不要仅依赖GROUP BY排序数据。</code></pre>
<p> 为说明GROUP BY和ORDER BY的使用方法,请看一个例子。下面的SELECT语句类似于前面那些例子。它检索总计订单价格大于等于50的订单的订单号和总计订单价格:</p>
<blockquote>
<p>输入:SELECT order_num,SUM(quantity<em>item_price) AS ordertotal FROM orderitems GROUP BY order_num HAVING SUM(quantity</em>item_price) >=50;</p>
</blockquote>
<p>输出:</p>
<table>
<thead>
<tr>
<th align="center">order_num</th>
<th align="center">ordertotal</th>
</tr>
</thead>
<tbody><tr>
<td align="center">20005</td>
<td align="center">149.87</td>
</tr>
<tr>
<td align="center">20006</td>
<td align="center">55.00</td>
</tr>
<tr>
<td align="center">20007</td>
<td align="center">1000.00</td>
</tr>
<tr>
<td align="center">20008</td>
<td align="center">125.00</td>
</tr>
</tbody></table>
<p> 为按总计订单价格排序输出,需要添加ORDER BY子句,如下所示:</p>
<blockquote>
<p>输入:SELECT order_num,SUM(quantity<em>item_price) AS ordertotal FROM orderitems GROUP BY order_num HAVING SUM(quantity</em>item_price) >=50 ORDER BY ordertotal;</p>
</blockquote>
<p>输出:</p>
<table>
<thead>
<tr>
<th align="center">order_num</th>
<th align="center">ordertotal</th>
</tr>
</thead>
<tbody><tr>
<td align="center">20006</td>
<td align="center">55.00</td>
</tr>
<tr>
<td align="center">20008</td>
<td align="center">125.00</td>
</tr>
<tr>
<td align="center">20005</td>
<td align="center">149.87</td>
</tr>
<tr>
<td align="center">20007</td>
<td align="center">1000.00</td>
</tr>
</tbody></table>
<blockquote>
<p>分析:</p>
</blockquote>
<p>在这个例子中,GROUP BY 子句用来按订单号(order_num列)分组数据,以便SUM(*)函数能够返回总计订单价格。HAVING子句过滤数据,使得只返回总计订单价格大于等于50的订单。最后,用ORDER BY排序。</p>
<h2 id="13-5-SELECT子句顺序"><a href="#13-5-SELECT子句顺序" class="headerlink" title="13.5 SELECT子句顺序"></a>13.5 SELECT子句顺序</h2><p> 回顾一下SELECt语句中子句的顺序。<br>| 子句 | 说明 | 是否必须使用 |<br>| :—–: | :——-: | :——-: |<br>| SELECT | 要返回的列或表达式 | 是 |<br>| FROM | 从中检索数据的表 | 仅在从表选择数据时使用|<br>| WHERE | 行级过滤 | 否 |<br>| GROUP BY | 分组说明 | 仅在按组计算聚集时使用 |<br>| HAVING | 组级过滤 | 否 |<br>| ORDER BY | 输出排序顺序 | 否 |<br>| LIMIT | 要检索的行数 | 否 |</p>
<p>输出: </p>
<table>
<thead>
<tr>
<th align="left">avg_price</th>
</tr>
</thead>
<tbody><tr>
<td align="left">16.133571</td>
</tr>
</tbody></table>
<blockquote>
<p>分析:此SELECT语句返回值avg_Price,它包含products表中所有产品的平均价格。如第10章所述,avg_price是一个别名。</p>
</blockquote>
<pre><code> 只用于单个列 AVG()只能用来确定特定数值列的平均值,而且列名必须作为函数参数给出。为了获得多个列的平均值,必须使用多个AVG()函数。
NULL值 AVG()函数忽略列值为NULL的行。</code></pre>
<h3 id="12-1-2-COUNT-函数"><a href="#12-1-2-COUNT-函数" class="headerlink" title="12.1.2 COUNT()函数"></a>12.1.2 COUNT()函数</h3><p> COUNT()函数进行计数。可利用COUNT()确定表中行的数目或符合特定条件的行的数目。<br> COUNT()函数有两种使用方式。 </p>
<ol>
<li>使用COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值。</li>
<li>使用COUNT(column)对特定列中具有值的行进行计数,忽略NULL值。</li>
</ol>
<blockquote>
<p>输入:SELECT COUNT(*) AS num_cust FROm customers;</p>
</blockquote>
<p>输出:</p>
<table>
<thead>
<tr>
<th align="left">num_cust</th>
</tr>
</thead>
<tbody><tr>
<td align="left">5</td>
</tr>
</tbody></table>
<blockquote>
<p>分析: 在此例子中,利用COUNT(*)对所有行计数,不管行中各列有什么值。计数值在num_cust中返回。 </p>
</blockquote>
<p> 下面的例子只对具有电子邮件地址的客户计数: </p>
<blockquote>
<p>SELECT COUNT(cust_email) AS num_cust FROm customers;</p>
</blockquote>
<p>输出:</p>
<table>
<thead>
<tr>
<th align="left">num_cust</th>
</tr>
</thead>
<tbody><tr>
<td align="left">3</td>
</tr>
</tbody></table>
<blockquote>
<p>分析:这条SELECT语句使用COUNT(cust_email)对cust_email列中有值的行进行计数。在此例子中,cust_email的计数为3(表示5个客户中只有3个客户有电子邮件地址)。</p>
</blockquote>
<pre><code> NULL值 如果指定列名,则指定列的值为空的行被COUNT()函数忽略,但如果COUNT()函数中用的是星号(*),则不忽略。</code></pre>
<h3 id="12-1-3-MAX-函数"><a href="#12-1-3-MAX-函数" class="headerlink" title="12.1.3 MAX()函数"></a>12.1.3 MAX()函数</h3><p> MAX()返回指定列中的最大值。MAX()要求指定列名,如下所示: </p>
<blockquote>
<p>输入:SELECT MAX(prod_price) AS max_price FROM products; </p>
</blockquote>
<p>输出: </p>
<table>
<thead>
<tr>
<th align="left">min_price</th>
</tr>
</thead>
<tbody><tr>
<td align="left">55.00</td>
</tr>
</tbody></table>
<blockquote>
<p>分析:这里,MAX()返回products表中最贵的物品的价格。 </p>
</blockquote>
<pre><code> 对非数值数据使用MAX() 虽然MAX()一般用来找出最大的数值或日期值,但MySQL允许将它用来返回任意列中的最大值,包括返回文本列中的最大值。在用于文本数据时,如果数据按相应的列排序,则MAX()返回最后一行。
NULL值 MAX()函数忽略列值为NULL的行。</code></pre>
<h3 id="12-1-4-MIN-函数"><a href="#12-1-4-MIN-函数" class="headerlink" title="12.1.4 MIN()函数"></a>12.1.4 MIN()函数</h3><p> MIN()的功能正好与MAX()功能相反,它返回指定列的最小值。</p>
<h3 id="12-1-5-SUM-函数"><a href="#12-1-5-SUM-函数" class="headerlink" title="12.1.5 SUM()函数"></a>12.1.5 SUM()函数</h3><p> SUM()用来返回指定列值得和(总计)。<br> 下面举一个例子,orderitems表包含订单中实际的物品,每个物品有相应的数量(quantity)。可如下检索所订购物品的总数(所有quantity值之和):</p>
<blockquote>
<p>输入:SELECT SUM(quantity) AS items_ordered FROM orderitems WHERE order_num =20005;</p>
</blockquote>
<p>输出:</p>
<table>
<thead>
<tr>
<th align="left">items_ordered</th>
</tr>
</thead>
<tbody><tr>
<td align="left">19</td>
</tr>
</tbody></table>
<blockquote>
<p>分析:函数SUM(quantity)返回订单中所有物品数量之和,WHERE子句保证只统计某个物品订单中的物品。</p>
</blockquote>
<p> SUM()也可以用来合计计算值。在下面的例子中,合计每项物品的<br>item_price*quantity,得出总的订单金额:</p>
<blockquote>
<p>输入:SELECT SUM(item_price*quantity) AS total_price FROM orderitems WHERE order_num =20005; </p>
</blockquote>
<p>输出:</p>
<table>
<thead>
<tr>
<th align="left">total_price</th>
</tr>
</thead>
<tbody><tr>
<td align="left">149.87</td>
</tr>
</tbody></table>
<blockquote>
<p>分析:函数SUM(item_price*quantity)返回订单中所有物品价钱之和,WHERE子句同样保证只统计某个物品订单中的物品。</p>
</blockquote>
<pre><code> 在多个列上进行计算 如本例所示,利用标准的算术操作符,所有聚集函数都可用来执行多个列上的计算。
NULL值 SUM()函数忽略列值为NULL的行。</code></pre>
<h2 id="12-2-聚集不同值"><a href="#12-2-聚集不同值" class="headerlink" title="12.2 聚集不同值"></a>12.2 聚集不同值</h2><pre><code> MySQL 5 及后期版本 下面将要介绍的聚集函数的DISTINCT的使用,已经被添加到MySQL 5.0.3中。下面所述内容在MySQL 4.x中不能正常运行。</code></pre>
<p> 以上5个聚集函数都可以如下使用:</p>
<ol>
<li><p>对所有的行执行计算,指定ALL参数或不给参数(因为ALL是默认<br>行为); </p>
</li>
<li><p>只包含不同的值,指定DISTINCT参数。</p>
<pre><code> ALL为默认 ALL参数不需要指定,因为它是默认行为。如果不指定DISTINCT,则假定为ALL。</code></pre>
</li>
</ol>
<p> 下面的例子使用AVG()函数返回特定供应商提供的产品的平均价格。它与上面的SELECT语句相同,但使用了DISTINCT参数,因此平均值只考虑各个不同的价格:</p>
<blockquote>
<p>输入:SELECT AVG(DISTINCT prod_price) AS avg_price FROM products WHERE end_id=1003;</p>
</blockquote>
<p>输出: </p>
<table>
<thead>
<tr>
<th align="left">avg_price</th>
</tr>
</thead>
<tbody><tr>
<td align="left">15.998000</td>
</tr>
</tbody></table>
<blockquote>
<p>分析:可以看到,在使用了DISTINCT后,此例子中的avg_price比较高,因为有多个物品具有相同的较低价格。排除它们提升了平均价格。</p>
</blockquote>
<pre><code> 注意 如果指定列名,则DISTINCT只能用于COUNT()。DISTINCT不能用于COUNT(*),因此不允许使用COUNT(DISTINCT),否则会产生错误。类似地,DISTINCT必须使用列名,不能用于计算或表达式。</code></pre>
<h2 id="12-3-组合聚集函数"><a href="#12-3-组合聚集函数" class="headerlink" title="12.3 组合聚集函数"></a>12.3 组合聚集函数</h2><p> SELECT语句可根据需要包含多个聚集函数。请看下面的例子: </p>
<blockquote>
<p>输入:SELECT COUNT(*) AS num_items,Min(prod_price) AS price_min,MAX(prod_price) AS price_max, AVG(prod_price) AS price_avg FROM products;</p>
</blockquote>
<p>输出:</p>
<table>
<thead>
<tr>
<th align="left">num_items</th>
<th align="left">price_min</th>
<th align="left">price_max</th>
<th align="left">price_avg</th>
</tr>
</thead>
<tbody><tr>
<td align="left">14</td>
<td align="left">2.5</td>
<td align="left">55</td>
<td align="left">16.133571</td>
</tr>
</tbody></table>
<blockquote>
<p>分析:这里用单条SELECT语句执行了4个聚集计算,返回4个值(products表中物品的数目,产品价格的最高、最低以及平均值)。</p>
</blockquote>
<pre><code> 取别名 在指定别名以包含某个聚集函数的结果时,不应该使用表中实际的列名。虽然这样做并非不合法,但使用唯一的名字会使你的SQL更易于理解和使用(以及将来容易排除故障)。</code></pre>
</div>
<footer class="article-footer">
<a data-url="http://example/2022/07/18/%E7%AC%AC13%E7%AB%A0%E5%88%86%E7%BB%84%E6%95%B0%E6%8D%AE/" data-id="clemvoh7s000h7s7eba7rev7p" data-title="第13章分组数据" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/MySQL%E5%BF%85%E7%9F%A5%E5%BF%85%E4%BC%9A/" rel="tag">MySQL必知必会</a></li></ul>
</footer>
</div>
</article>
<article id="post-第12章汇总数据" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2022/07/17/%E7%AC%AC12%E7%AB%A0%E6%B1%87%E6%80%BB%E6%95%B0%E6%8D%AE/" class="article-date">
<time class="dt-published" datetime="2022-07-17T13:29:00.000Z" itemprop="datePublished">2022-07-17</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">