☰
双色球历史数据集:Excel与MySQL双格式整理及SQL统计实战
2026/11/4 4:53:01 网站建设 项目流程

双色球从2003年开售到现在,二十多年攒下来的开奖记录已经是一个相当可观的数据体量了。我手头这份覆盖2003到2025年、合计3287期的历史数据集,最初只是为了自己写个小工具做号码频次统计,后来折腾着折腾着,就顺手整理成了Excel和MySQL两套格式。这份数据能干什么?说白了,它适合做数据清洗练习、SQL查询练手、统计分析入门、可视化项目素材,也适合那些想研究随机序列分布特征的朋友拿来当样本。不管你是刚学数据库的学生,还是想找个真实数据集练手的数据爱好者,这套东西都能直接上手用。下面我就把这套数据集的整理思路、字段设计、导入流程和踩过的坑,原原本本讲一遍。

1. 数据集整体设计与字段拆解

1.1 为什么选Excel加MySQL双格式

一开始我只存了Excel,毕竟打开就能看,筛选排序都方便。但数据量涨到三千多行之后,问题就来了:想做个跨年份的号码频次统计,Excel的公式越写越长,透视表刷新也慢,而且每次改统计口径都得重新拖字段。后来我把数据导进MySQL,一条GROUP BY就能出结果,效率完全不是一个量级。

所以这套数据集最终做成双格式,各有各的定位。Excel版本面向的是快速查看、手工筛选、做简单图表;MySQL版本面向的是批量统计、复杂查询、程序调用。两者字段结构完全一致,方便你在两个环境之间来回倒腾。

这里有个设计上的取舍值得说一下:我没有把红球和蓝球拆成两张表。按数据库范式来说,拆表似乎更"规范",但实际用起来,每次查询都要JOIN,写起来啰嗦,而且双色球本身就是一期一组号码,天然适合放在一行里。所以我采用了宽表设计,六个红球字段加一个蓝球字段,查询时直接SELECT就行,代价是字段稍微多一点,但换来的是操作上的直观。

1.2 字段定义与类型选择

整套数据的字段设计如下表所示,这是Excel和MySQL共用的结构:

字段名含义Excel类型MySQL类型说明
issue期号文本VARCHAR(10)如2025001,保留前导零
open_date开奖日期日期DATE格式YYYY-MM-DD
red1红球1数值TINYINT升序排列后的第一个
red2红球2数值TINYINT升序排列后的第二个
red3红球3数值TINYINT升序排列后的第三个
red4红球4数值TINYINT升序排列后的第四个
red5红球5数值TINYINT升序排列后的第五个
red6红球6数值TINYINT升序排列后的第六个
blue蓝球数值TINYINT取值范围1-16
sales销售额数值DECIMAL(14,2)单位元,部分早期期次缺失
pool奖池金额数值DECIMAL(14,2)单位元,部分早期期次缺失

期号用VARCHAR而不是INT,这一点很多人会忽略。期号形如2025001,如果存成整数,前导零虽然不影响数值,但显示时会变成2025001没问题,可一旦遇到某些需要按字符串排序或拼接的场景,整数类型反而添乱。更重要的是,期号本质上是标识符而不是可运算的数值,用字符串类型在语义上更准确。

红球字段用TINYINT,取值范围1到33,一个字节足够,没必要用INT浪费空间。蓝球1到16同理。销售额和奖池用DECIMAL而不是FLOAT,是因为金额涉及精确比较和求和,浮点数会有精度误差,DECIMAL(14,2)表示总共14位、小数2位,最大能存到万亿级别,对这份数据绰绰有余。

注意:早期部分期次的销售额和奖池字段存在缺失,导入时如果设了NOT NULL会直接报错。我的处理是把这两列设为允许NULL,缺失值统一留空,统计时用WHERE sales IS NOT NULL过滤掉即可。

1.3 数据完整性校验思路

三千多期数据,手工核对不现实,必须靠规则校验。我在整理时定了三条硬性校验规则,每次导入新数据都跑一遍:

第一条,红球必须严格升序。双色球开奖号码公布时通常就是升序,但不同来源的数据格式不统一,有的按开出顺序记录,导入前必须统一排序。校验方法很简单,逐行检查red1 < red2 < red3 < red4 < red5 < red6,任何一行不满足就说明数据有问题。

第二条,红球范围1到33且不重复,蓝球范围1到16。这条用SQL一条语句就能查出来:

SELECT issue FROM lottery_data WHERE red1 < 1 OR red6 > 33 OR blue < 1 OR blue > 16 OR red1 = red2 OR red2 = red3 OR red3 = red4 OR red4 = red5 OR red5 = red6;

第三条,期号唯一且日期递增。期号重复说明有重复导入,日期不递增说明排序或数据源有问题。这两条用COUNT和窗口函数都能快速验证。

2. Excel版本的整理与使用要点

2.1 表格结构设计与格式规范

Excel版本我做了两张工作表。第一张叫"开奖数据",就是上面那张宽表,一行一期,从2003001期一直排到2025年的最新期次。第二张叫"字段说明",写清楚每个字段的含义、类型和取值范围,方便别人拿到文件后不用问就能看懂。

格式上我做了几个处理。期号列设为文本格式,避免Excel自动把2025001识别成数字后丢掉前导零——这个问题在实际操作中非常常见,很多人导完数据发现期号变成了2025001看着没问题,但一旦有期号是类似001结尾的短号就会出乱子。日期列统一设为YYYY-MM-DD格式,区域设置不同可能导致显示差异,但底层存储的是日期序列值,不影响计算。

红球和蓝球列加了数据验证,限制输入范围分别是1-33和1-16,这样手工补录数据时能挡住明显的录入错误。表头做了冻结窗格,三千多行往下翻的时候表头始终可见。另外我给整张表加了自动筛选,想按年份看就筛期号前缀,想按蓝球看就筛蓝球列,日常查看足够用了。

2.2 常用统计公式与透视表配置

Excel版本最大的价值在于快速出一些直观的统计。我预置了几个常用公式,你拿到就能改。

统计某个红球出现的总次数,用COUNTIF跨六列统计:

=COUNTIF(B2:G3288, 5)

这里假设红球在B到G列,5是你要统计的号码。但要注意,COUNTIF对多列区域是逐列统计再汇总,写一个公式覆盖六列区域就行,不用写六个再相加。

统计蓝球频次更简单,蓝球单独一列,直接对整列做COUNTIF。我一般会配一个1到16的辅助列,每个号码旁边放一个COUNTIF公式,下拉就出全部频次,再插入一个柱状图,分布一目了然。

透视表的配置有个小技巧。想做"按年份统计各红球出现次数",直接把期号列拖到行区域后,Excel会按期号分组,但期号是文本,分组效果不理想。更好的做法是加一个辅助列提取年份,公式用LEFT(期号,4),然后按这个年份列做透视。这个辅助列在MySQL版本里对应的是直接用LEFT(issue,4)查询,两边思路一致。

2.3 大数据量下的性能优化

三千多行对Excel来说不算大,但如果你的公式写得重,比如整列引用加数组公式,刷新起来还是会卡。我的经验是三条:

第一,避免整列引用。写COUNTIF(A:A, ...)这种整列引用,Excel会计算上百万个单元格,哪怕实际只有三千行有数据。改成COUNTIF(A2:A3288, ...)精确引用,速度快一个数量级。

第二,透视表数据源用表格对象而不是普通区域。选中数据区域后按Ctrl+T转成表格,透视表引用这个表格名,后续追加数据时透视表刷新会自动包含新行,不用每次手动改范围。

第三,复杂统计尽量放到MySQL里做,Excel只负责展示结果。我现在的习惯是,凡是涉及多条件组合统计的,先在数据库里跑出结果,再复制到Excel做图,两边各干各擅长的事。

3. MySQL版本的建库导入全流程

3.1 建表语句与索引设计

MySQL版本的建表语句我反复调整过几版,最终定稿如下:

CREATE TABLE lottery_data ( id INT AUTO_INCREMENT PRIMARY KEY, issue VARCHAR(10) NOT NULL UNIQUE, open_date DATE NOT NULL, red1 TINYINT NOT NULL, red2 TINYINT NOT NULL, red3 TINYINT NOT NULL, red4 TINYINT NOT NULL, red5 TINYINT NOT NULL, red6 TINYINT NOT NULL, blue TINYINT NOT NULL, sales DECIMAL(14,2) DEFAULT NULL, pool DECIMAL(14,2) DEFAULT NULL, INDEX idx_open_date (open_date), INDEX idx_blue (blue) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

几个设计点解释一下。自增主键id是习惯做法,虽然issue本身唯一可以作为主键,但用自增整数做主键在InnoDB下插入性能更好,issue上加UNIQUE约束保证唯一性即可。open_date加了索引,因为按时间范围查询是最常见的操作之一。blue加了索引,因为蓝球频次统计是高频查询。

红球字段没有单独加索引,原因是红球查询通常是组合条件,单列索引帮助有限,而且数据量只有三千多行,全表扫描的开销完全可以接受。给六个红球列都加索引反而增加写入负担和存储开销,得不偿失。这个取舍在小数据量场景下很典型:索引不是越多越好,要看实际查询模式。

字符集用utf8mb4,虽然这份数据全是数字和日期,用不上多字节字符,但统一用utf8mb4能避免以后混入其他文本字段时的编码问题,属于一劳永逸的做法。

3.2 从Excel到MySQL的数据导入

导入方式我试过三种,最后推荐两种。

第一种是MySQL Workbench的导入向导。打开Workbench,右键表选Table Data Import Wizard,选Excel文件,映射字段,一路下一步就行。优点是图形化、不用写代码,缺点是Excel里的日期格式如果和MySQL期望的不一致,容易导成0000-00-00。解决办法是在导入前把Excel日期列统一转成文本格式的YYYY-MM-DD,导入后再用STR_TO_DATE转换,或者干脆在Excel里就存成标准日期文本。

第二种是LOAD DATA LOCAL INFILE,适合数据量大或者需要反复导入的场景。先把Excel另存为CSV,注意保存时选UTF-8编码,然后执行:

LOAD DATA LOCAL INFILE '/path/lottery_data.csv' INTO TABLE lottery_data FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 ROWS (issue, open_date, red1, red2, red3, red4, red5, red6, blue, sales, pool);

这里有个坑要提醒:CSV里如果销售额字段是空的,LOAD DATA默认会把它当成空字符串,导入DECIMAL列时可能报错或变成0。我的处理是在Excel里把空值统一填成\N,LOAD DATA遇到\N会识别为NULL。这个细节不注意的话,导入后你会发现缺失的销售额全变成了0,统计时就会把0当成真实值算进去,结果全错。

提示:导入完成后务必跑一遍第1.3节的校验SQL,确认红球升序、范围合法、期号唯一三条规则全部通过,再开始做统计。数据没校验就分析,等于在沙子上盖楼。

3.3 高频统计查询语句模板

数据导进去之后,最常跑的查询我整理成了模板,改改参数就能用。

统计单个红球在全部期次中出现的次数,因为红球分散在六列,需要把六列合并后再统计:

SELECT COUNT(*) AS appear_count FROM ( SELECT red1 AS num FROM lottery_data UNION ALL SELECT red2 FROM lottery_data UNION ALL SELECT red3 FROM lottery_data UNION ALL SELECT red4 FROM lottery_data UNION ALL SELECT red5 FROM lottery_data UNION ALL SELECT red6 FROM lottery_data ) t WHERE num = 5;

这个UNION ALL的写法是把宽表转成长表的经典手法,六列纵向堆叠后统一过滤。三千多期乘以六,中间结果不到两万行,性能完全没问题。

统计全部红球的频次分布,把WHERE条件去掉,外面套一层GROUP BY:

SELECT num, COUNT(*) AS cnt FROM ( SELECT red1 AS num FROM lottery_data UNION ALL SELECT red2 FROM lottery_data UNION ALL SELECT red3 FROM lottery_data UNION ALL SELECT red4 FROM lottery_data UNION ALL SELECT red5 FROM lottery_data UNION ALL SELECT red6 FROM lottery_data ) t GROUP BY num ORDER BY cnt DESC;

蓝球频次统计就简单多了,单列直接GROUP BY:

SELECT blue, COUNT(*) AS cnt FROM lottery_data GROUP BY blue ORDER BY cnt DESC;

按年份统计开奖期数,用LEFT提取期号前四位:

SELECT LEFT(issue, 4) AS year, COUNT(*) AS issue_count FROM lottery_data GROUP BY year ORDER BY year;

这几个模板覆盖了大部分入门统计需求,想加条件就在WHERE里加,想按时间段筛就用open_date BETWEEN。

4. 实操中踩过的坑与排查实录

4.1 数据源格式不统一引发的连锁问题

这份数据最早是从多个渠道拼凑的,不同来源的格式差异让我吃了不少苦头。最典型的是日期格式,有的源是2025-01-02,有的是2025/1/2,还有的是20250102这种紧凑格式。直接合并后,Excel里日期列一半是日期值一半是文本,排序全乱。

我的解决办法是统一走一道转换:先把所有日期转成YYYY-MM-DD的文本,再用DATEVALUE转成真正的日期值。MySQL这边则是在导入前用Python脚本预处理,把所有日期字符串统一成标准格式再写CSV。这一步看着繁琐,但不做的话后面所有按时间排序、按年份统计的操作都会出问题。

另一个坑是期号的前导零。有些数据源把2025001存成了2025001没问题,但把类似2003001这种早期期号存成整数后,某些工具导出时会变成2003001看着也对,可一旦遇到期号位数不一致的情况就露馅了。统一用文本类型存储是唯一稳妥的做法。

4.2 导入报错的典型场景与解决

导入过程中最常见的报错有三类,我整理成了速查表:

报错信息原因解决方法
Incorrect date value日期格式与MySQL期望不符预处理成YYYY-MM-DD文本,或用STR_TO_DATE转换
Data too long for column字段长度不够,常见于期号或金额检查VARCHAR长度和DECIMAL精度
Duplicate entry for key 'issue'期号重复,重复导入或数据源有重复行导入前用Excel去重,或加IGNORE关键字跳过
Out of range value红球或蓝球超出TINYINT范围校验数据,确认没有录入错误
Cannot be null缺失值导入到NOT NULL列缺失字段设为允许NULL,或填充默认值

其中Duplicate entry这个报错最容易被忽视。有时候数据源本身就有重复期号,比如同一期被不同渠道各记录了一次,导入时撞上UNIQUE约束直接中断。我的做法是导入前先在Excel里用"删除重复项"功能按期号去重,或者在LOAD DATA语句里加IGNORE,让重复行被跳过而不是报错。但IGNORE是静默跳过,你得自己确认跳过的确实是重复行而不是别的错误,所以导入后还是要跑一遍期号唯一性校验。

4.3 统计结果对不上的排查思路

有次我统计红球5的出现次数,Excel算出来和MySQL算出来差了十几次,排查了半天才发现是Excel那边COUNTIF的区域少选了几行。这种"结果对不上"的问题,排查顺序我总结成三步:

第一步,先确认两边数据行数一致。Excel用COUNTA数期号列,MySQL用SELECT COUNT(*),数字对不上说明数据本身就不一致,先解决数据同步问题。

第二步,确认统计口径一致。比如统计红球5,Excel的COUNTIF区域是否覆盖了全部六列,MySQL的UNION ALL是否包含了全部六列,任何一边漏一列结果就会偏。

第三步,抽样核对。随机挑几期,手工数一下目标号码是否出现,和两边的统计结果对照。抽样能快速定位是系统性偏差还是个别数据错误。

这套排查思路不只适用于这份数据,任何跨工具的数据核对都能套用。核心就是先对齐数据范围,再对齐计算逻辑,最后抽样验证。

5. 基于这份数据集的进阶玩法

5.1 号码分布可视化

数据整理好之后,最有意思的就是做可视化。我用Python的matplotlib做过一版红球频次分布图,思路很简单:从MySQL读出频次统计结果,画成柱状图,横轴1到33,纵轴出现次数。跑出来的图能直观看到哪些号码出现得多、哪些少,虽然这不能说明任何预测意义,但作为数据可视化的练习素材非常合适。

如果想做得更细,可以按年份分段画,看看不同年份的分布有没有变化。我的经验是,三千多期的样本量下,各号码频次大致在一个区间内波动,没有哪个号码显著偏离,这本身就是一个很好的随机性直观演示。做这类可视化时,建议把图表标题和坐标轴标签写清楚,注明数据范围和统计口径,避免看图的人产生误解。

5.2 用SQL做区间与组合分析

除了单号码频次,还可以做一些组合维度的分析。比如统计每期红球的和值分布:

SELECT issue, (red1+red2+red3+red4+red5+red6) AS sum_red FROM lottery_data ORDER BY sum_red;

再比如统计红球中奇数和偶数的个数比例,这个用CASE WHEN配合取模运算就能做。这类分析的价值不在于得出什么结论,而在于练习SQL的条件判断和聚合能力。我建议刚开始接触SQL的朋友,就拿这份数据练手,从简单的SELECT到GROUP BY再到子查询,一步步加难度,比看教程有效得多。

5.3 数据集的扩展与维护

这份数据集目前覆盖到2025年,后续新期次的开奖记录需要持续追加。我的维护流程是:每期开奖后,把新数据按统一格式追加到Excel表格末尾,然后重新导出CSV,用LOAD DATA导入MySQL。为了避免重复导入,导入前先查一下MySQL里已有的最大期号,只导入比它新的期次。

追加数据时最容易出的错是格式不一致,比如新数据日期用了不同分隔符,或者期号位数不对。我的习惯是维护一个录入模板,新数据先填进模板,模板里带数据验证和格式约束,填完再合并到主表,这样能从源头挡住大部分格式问题。

另外建议定期做一次全量备份。Excel版本直接另存一份带日期的副本,MySQL版本用mysqldump导出:

mysqldump -u root -p lottery_db lottery_data > backup_20250101.sql

备份文件按日期命名,出问题时能快速回滚到某个时间点的状态。这个习惯在数据量越来越大之后会显得越来越重要,我吃过没备份的亏,一次误操作把整列数据覆盖了,只能从头重新整理,那滋味不好受。

我个人在实际操作中的体会是,这份数据集最大的价值不在于数据本身,而在于整理它的过程逼着我把数据清洗、格式统一、导入校验、统计查询这一整套流程走了一遍。每踩一个坑,对数据处理的理解就深一层。如果你也想拿它练手,建议别急着做分析,先把导入和校验流程跑通,把数据质量这道关把住,后面的统计和可视化才有意义。最后再分享一个小技巧:做任何统计之前,先跑一遍SELECT COUNT(*)确认行数,再跑一遍范围校验SQL确认数据合法,这两步花不了一分钟,却能省掉后面大量的返工。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询