简介双色球自2003年2月23日首期开售至2025年4月15日全部3287期开奖记录已按时间顺序完整整理为一份轻量数据包面向需要批量获取历史号码的趋势分析、频次统计或预测建模用户能有效省去手工收集与清洗校验的繁琐环节。压缩包共5个文件核心为一个Excel工作簿和一个可直接导入MySQL的SQL脚本前者便于筛选排序、数据透视与图表制作后者适合执行复杂查询和深度统计另附一个Python辅助脚本及工程配置文件为二次开发与自动化处理提供便利。每期均包含期号、开奖日期、6个红球1-33与1个蓝球1-16数据无缺失、无重复可直接用于冷热号追踪、连号/区间分布、号码频次分析等场景也可作为自建预测模型的基础训练集。整个压缩包仅约213KB轻巧便携目前已有1602人学习下载适合Excel、MySQL及Python用户快速开展历史开奖数据的整理、挖掘与验证。1. 为什么盯上这份2003-2025双色球开奖记录一个能练手又能做分析的数据包做数据分析或数据库练习的人最缺的往往不是教程而是一份真实、干净、量级刚好合适的数据。这份 2003-2025 双色球全部开奖记录共 3287 期同时打包了 Excel 和 MySQL 数据文件恰好把缺口补上了。下载后你既能丢进 MySQL 练查询、写存储过程、做联表统计也能用 Excel 练筛选、透视表和函数公式如果你正在学 JavaWeb 项目开发它还能直接当种子数据喂给 SpringBoot4 Mybatis 的查询接口。这篇笔记会从表结构设计、导入验证、Excel 清洗讲到容易翻车的几个坑最后送你一个我常用的两套文件一致性校验方法。2. 拆解开奖记录数据包字段含义与 MySQL 表结构设计2.1 双色球开奖记录的基本字段不只是六个红球和一个蓝球双色球一注由 6 个红球和 1 个蓝球组成红球范围是 1 到 33蓝球范围是 1 到 16。所以一份完整的开奖记录里至少会有期号、开奖日期、红球 1 到红球 6、蓝球这几个字段。附带字段通常还包括本期销售额、奖池金额、一等奖注数、单注奖金等这些信息对研究彩票数据非常有用比如奖池变化能反映加奖周期销售额可以看出市场热度。但做表结构时不要把所有这些字段都堆进一张表尤其不要给销售额、奖池这类数值型字段用错类型否则后面做聚合统计时容易算出莫名其妙的结果。打开数据包后先别急着导入先看字段名。很多整理者把列名写成red_1、red1、红球一这种混乱命名我的习惯是先把列名规范成一套英文小写加下划线的形式。如果字段只有期号、日期和开奖号码最好自己补上sale_amount和pool_amount这两个冗余列的位置方便以后做奖池分析。不要担心数据包里没有这些字段结构设计本来就是拿到数据后根据分析目标来定的。字段类型的选择也有讲究。红球和蓝球本质上是小范围内的整数用TINYINT UNSIGNED就足够没必要用INT后者每行多占 3 个字节在 3287 行时无感但你如果把它当成千万级业务的模板就会暴露出问题。开奖日期用DATE类型别用字符串否则按年份过滤、按月份分组都会吃力。期号建议用INT UNSIGNED但要注意有些数据文件的期号带前导零比如2025001这种存成数字会丢失前导零需要先确认源数据格式再决定用INT还是VARCHAR。2.2 表结构设计TINYINT、DATE 和 UNIQUE KEY 怎么选我一般会新建一个独立库来承载这份数据而不是把它塞进已有的业务库。建表语句如下你可以直接在 MySQL 客户端执行CREATE DATABASE IF NOT EXISTS lottery DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE lottery; CREATE TABLE ssq_record ( project_no INT UNSIGNED NOT NULL COMMENT 期号, open_date DATE NOT NULL COMMENT 开奖日期, red1 TINYINT UNSIGNED NOT NULL COMMENT 红球1, red2 TINYINT UNSIGNED NOT NULL, red3 TINYINT UNSIGNED NOT NULL, red4 TINYINT UNSIGNED NOT NULL, red5 TINYINT UNSIGNED NOT NULL, red6 TINYINT UNSIGNED NOT NULL, blue TINYINT UNSIGNED NOT NULL COMMENT 蓝球, sale_amount DECIMAL(16,2) DEFAULT NULL COMMENT 本期销售额(元), pool_amount DECIMAL(16,2) DEFAULT NULL COMMENT 奖池金额(元), PRIMARY KEY (project_no), UNIQUE KEY uk_open_date (open_date), KEY idx_blue (blue) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这段建表逻辑的关键点有几个。TINYINT UNSIGNED用来存红蓝球是因为范围 0 到 255 完全覆盖 1 到 33 和 1 到 16比INT省空间且逻辑更严谨。DATE类型保证日期能做区间比较例如WHERE open_date BETWEEN 2020-01-01 AND 2020-12-31会走索引。PRIMARY KEY (project_no)直接按期号做主键因为每一期是唯一的业务标识UNIQUE KEY uk_open_date是第二道保险防止同一开奖日期重复导入。最后的KEY idx_blue则是为蓝球聚合查询准备的索引后面统计蓝球分布时会快很多。如果你拿到的数据文件里没有销售额和奖池那把这两列去掉即可不要把DECIMAL列强行留空。注意DECIMAL(16,2)的 16 表示总位数2 表示小数位最大可存 99999999999999.99单位是元双色球奖池金额在这个数量级内足够。字符集统一用utf8mb4虽然开奖记录本身没有中文但你后期可能会把导入说明写进表注释或者关联地区表免得出现乱码。2.3 一份数据两种玩法Excel 做探索MySQL 做精确查询数据包里同时给 Excel 和 MySQL 文件是有道理的。Excel 适合小规模手工看数透视表拖几下就能看到蓝球分布、冷热号排序MySQL 适合跑全量统计比如计算某个红球连续未出现多少期、两个红球组合历史上共现多少次这类问题用 Excel 公式硬算也能算但绝没有 SQL 干净。很多情况下我会先用 Excel 做数据探查确认字段含义和大致范围再决定 SQL 怎么写这个链路效率很高。另一个常见用途是把它喂给业务系统做测试。如果你正在学 SpringBoot4 和 Mybatis或者写的是一个 JavaWeb 项目往库里插入 3287 行真实分布的数据比手动造一千条假数据更能体现分页、排序、条件查询的效果。比如接口GET /lottery?date2024-01-01返回某期详情或者做一个“统计每个蓝球出现次数”的图表接口数据量大但又不至于大到跑不动正好用来验证索引和缓存策略。3. 导入 MySQL 数据文件从建库、导数据到验证一条龙3.1 准备工作确认 MySQL 版本、字符集和建库脚本先确保本机已经装好 MySQL。如果你刚照着 mysql 安装教程装完 MySQL 8.x默认字符集就是 utf8mb4省心很多如果你还在用 5.7建议在创建库时显式指定字符集否则导入文件里出现中文字段注释或附加描述时很容易变成乱码。装好之后用命令行客户端进入 MySQL先执行SELECT VERSION();看版本再执行下面的建库语句。mysql -u root -pCREATE DATABASE IF NOT EXISTS lottery DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE lottery; SOURCE /path/to/ssq_record.sql;SOURCE命令是 mysql 命令行客户端的内置命令不是 SQL所以不能在 Navicat 的查询窗口里执行。如果你习惯用命令行也可以直接用mysql -u root -p lottery ssq_record.sql效果一样。注意 Windows 下SOURCE的路径分隔符要用正斜杠例如SOURCE E:/data/ssq_record.sql用反斜杠会解析错误。字符集设置里选utf8mb4_general_ci就够了没必要为一份彩票数据去追求utf8mb4_unicode_ci的排序规则两者的性能差异在三千行上感知不到。如果你没有现成的.sql文件数据包给的是 CSV 或 Excel 导出的表格那就先跳过SOURCE参考下一小节的LOAD DATA INFILE。我建议导数据前先用SHOW VARIABLES LIKE secure_file_priv;看一下 MySQL 允许读取外部文件的目录这一步能省去后面很多路径报错。另外导入前确认账号权限练习时用 root 没问题但如果是在公司或模拟项目里应创建独立账号并只授予SELECT权限避免误删数据。3.2 导入数据前先做这一步核对 Excel 和 MySQL 文件的期数是否一致拿到数据包后不要急着导入。先分别打开 Excel 文件和 MySQL 数据文件确认期数一致。这里说的“期数”不是只看最后一个期号而是看完整记录数。Excel 文件里可以用COUNTA函数统计期号列的非空单元格数量MySQL 数据文件如果是.sql用文本编辑器搜索 INSERT 语句数量很麻烦我一般直接看导入后的COUNT(*)。之所以先做这一步是因为很多整理者会先更新 Excel后更新 MySQL 文件两边的数据差了最近几期后面做对比分析会对不上。具体做法Excel 里选中期号列状态栏会显示“计数”记下这个数MySQL 文件先不管等导入后再查COUNT(*)。如果两边不一致优先以 MySQL 文件为准因为数据库文件解析时不会受 Excel 自动格式化影响更可靠。如果差了很多说明这个数据包版本不完整别急着删先看看是否有单独的补丁文件。3.3 source、LOAD DATA INFILE 和 GUI 工具三种导入方式怎么选如果你的 MySQL 数据文件是.sql格式最简单的是SOURCE或命令行重定向前面已经给过命令。如果数据包给的是 CSV 格式那就用LOAD DATA INFILE。下面是一个完整例子LOAD DATA INFILE /var/lib/mysql-files/ssq_record.csv INTO TABLE lottery.ssq_record FIELDS TERMINATED BY , ENCLOSED BY LINES TERMINATED BY \n IGNORE 1 ROWS (project_no, open_date, red1, red2, red3, red4, red5, red6, blue, sale_amount, pool_amount) SET project_no project_no, open_date STR_TO_DATE(open_date, %Y-%m-%d), sale_amount NULLIF(sale_amount, ), pool_amount NULLIF(pool_amount, );这段逻辑的重点在SET部分。CSV 里的日期是字符串直接导入DATE列会报错或存成0000-00-00所以用STR_TO_DATE显式转换。NULLIF(sale_amount, )的作用是把空字符串转成NULL避免空字符串被当成 0否则统计平均值时会拉低结果。IGNORE 1 ROWS通常是跳过表头如果数据文件没有表头就不要加这一行。LOAD DATA INFILE最容易栽在路径上。MySQL 8.0 默认开启secure-file-priv只允许从指定目录读取文件你要先执行SHOW VARIABLES LIKE secure_file_priv;查看那个目录在哪然后把 CSV 放到该目录下。如果你用的是 Docker 安装 MySQL那文件还需要先通过docker cp复制进容器再指向容器内的路径。不想走这些流程的话可以退回到SOURCE或直接用 Navicat/DBeaver 的导入向导效果一样但能手动选择分隔符和文件编码适合 Windows 上操作。3.4 数据导入前必须格式化把红球、蓝球转为标准格式再入库很多从网页复制的开奖记录红球可能长这样1, 12, 21, 22, 30, 33中间带逗号空格蓝球可能是05或5混着。这类数据直接进 MySQL 会破坏表结构。如果 CSV 里每个球占一列问题不大但如果数据包里给的是“红球”一列你就得先拆分再导入。最稳的办法是在 Excel 里先用“分列”功能按逗号或空格拆成 6 列再把每一列设置成“文本”格式最后另存为 CSV。拆分时会遇到1, 12, 21这种前导空格Excel 会自动去首尾空格但01和1会混在一起所以导入前最好先把所有红球列统一格式用公式TEXT(A1,00)把个位数补成两位。我自己遇到过数据包里红球是1蓝球是01导入 MySQL 后蓝球范围检查通过但红球打印出来全是单个数字看似没毛病实际上和官方开奖号码的文本格式对不上后续做字符匹配时才发现。3.5 验证导入结果记录数、期号连续性和红球范围检查导入完成后不要直接开始写分析 SQL先跑一组验证查询确认数据没被导坏。这组查询我每次都会执行-- 1. 基础行数检查 SELECT COUNT(*) AS total_rows, MIN(project_no) AS min_no, MAX(project_no) AS max_no FROM ssq_record; -- 2. 期号重复检查 SELECT project_no, COUNT(*) FROM ssq_record GROUP BY project_no HAVING COUNT(*) 1; -- 3. 红蓝球范围检查 SELECT project_no FROM ssq_record WHERE red1 NOT BETWEEN 1 AND 33 OR red2 NOT BETWEEN 1 AND 33 OR red3 NOT BETWEEN 1 AND 33 OR red4 NOT BETWEEN 1 AND 33 OR red5 NOT BETWEEN 1 AND 33 OR red6 NOT BETWEEN 1 AND 33 OR blue NOT BETWEEN 1 AND 16;第一段查询看总记录数是否等于 3287最小期号和最大期号是否符合时间顺序。第二段查重理论上期号是唯一键但如果源数据文件本身有重复建表时的PRIMARY KEY会让导入报错验证查询可以发现已经导入的数据里有没有重复。第三段的红球范围检查很关键因为有些手抄数据会把30写成3或把16写成6这种错误在你用 Excel 看时不易察觉但会直接影响后续统计准确性。验证通过后我习惯再跑一条SELECT open_date, project_no FROM ssq_record ORDER BY open_date LIMIT 5;看看日期和期号是否一一对应。如果 2003 年第一期的期号不是2003001就要回头检查是不是数据包里的期号定义不同比如有的用1而不是2003001。这一步不做后面做按年统计时会把 2003 年混进其他区间。4. 用 Excel 处理开奖记录从原始记录到可统计的报表4.1 先给 Excel 数据“体检”日期、红球、蓝色球的三类坑Excel 打开数据文件后第一件事不是做图而是先检查日期列和号码列的格式。选中开奖日期列看单元格是不是真正的日期类型如果是数值或文本后面所有按周、按月汇总都会失效。日期在 Excel 里如果显示成2025/5/23右键设置单元格格式能看到“日期”分类那没问题如果显示成5/23且左侧对齐那八成是文本先用“分列”功能把它转成真日期。分列时选中日期列点“数据-分列”第三步选择“日期 YMD”完成后再设置单元格格式为yyyy-mm-dd。红球和蓝球列要小心 Excel 的自动转换。比如开奖号码里的1和12被当成数字倒是没问题但文本型的01会被自动去掉前导零变成1这就导致红球 1 和蓝球 1 在文件里看起来没问题实际上已经丢失了原始格式。除了格式还要检查有没有合并单元格。很多整理好的 Excel 文件会把同一月的第一行合并导致后面的行空着如果直接拿去做函数统计会漏数据。看到合并单元格先取消合并并填充同样的值。第四类坑是空行和空值。双色球早期部分记录可能缺少销售额或奖池字段Excel 里的空单元格在后续SUMIFS和透视表统计中不会报错但在COUNTIF里就会被漏计。我的做法是先用筛选把所有列拉到底看有没有全空的行如果有没有删除或标记。你下载的这批 3287 期数据包如果整理规范这类问题不多但“不多”不等于没有体检一次花五分钟后面省两小时。4.2 用 SUMIFS 和 SUMPRODUCT 统计“周二蓝球出现次数”这类问题Excel 里最常用的条件统计函数是SUMIFS和COUNTIFS但它们不支持把“某列的数组运算结果”作为条件。比如你想统计“开奖日期是周二且蓝球等于 05”的期数用COUNTIFS没法直接判断星期几这时候用SUMPRODUCT最稳。假设开奖日期在 B2:B3288蓝球在 I2:I3288公式如下SUMPRODUCT((WEEKDAY(B2:B3288,2)2)*(I2:I32885))这个公式的原理是WEEKDAY返回每个日期对应的星期数字参数2让星期一等于 1星期二等于 2依此类推(WEEKDAY(...)2)会得到一个由TRUE/FALSE组成的数组乘号另一边是(蓝球5)两者相乘时TRUE转成 1FALSE转成 0最后SUMPRODUCT对乘积求和结果就是满足两个条件的总行数。用这个公式前提是 B 列是真日期I 列没有文本否则会出现#VALUE!。如果要统计更复杂的多条件COUNTIFS也有用武之地。比如统计某一年的蓝球 5 出现次数可以写成COUNTIFS($A$2:$A$3288,2024*,$I$2:$I$3288,5)这里要求期号列 A 列必须是文本格式才能用通配符2024*。如果期号是数字就改成SUMPRODUCT((YEAR(B2:B3288)2024)*(I2:I32885))。我一般优先用SUMPRODUCT因为它的数组逻辑更统一不需要记通配符规则。Excel 文件里直接敲数组公式容易卡但 3287 行对 Excel 来说是小数据量实时计算没压力。4.3 从 MySQL 查询结果生成 Excel用 Python 写入自定义报表当你已经习惯了 Excel 做展示同时又想用 MySQL 跑复杂统计最顺手的办法是让 Python 在中间当桥梁。先通过 SQL 查出结果再写入 Excel。下面的例子用sqlalchemy和pandas这两个库几乎是数据分析标配import pandas as pd from sqlalchemy import create_engine engine create_engine( mysqlpymysql://user:passwordlocalhost:3306/lottery?charsetutf8mb4 ) sql SELECT YEAR(open_date) AS year, blue, COUNT(*) AS cnt FROM ssq_record GROUP BY YEAR(open_date), blue ORDER BY year, blue; df pd.read_sql(sql, engine) df.to_excel(blue_by_year.xlsx, indexFalse, sheet_name按年蓝球分布)上面代码的要点有三处。第一处是连接串里的charsetutf8mb4如果不加读出来的一年里包含中文列名时可能乱码第二处是pd.read_sql它会把 SQL 查询结果直接变成 DataFrame后续在 Python 里做透视、筛选都很方便第三处是df.to_excel指定sheet_name可以自定义工作表名indexFalse避免把 DataFrame 的无意义索引写进 Excel。如果要把多个统计结果写进同一个 Excel 文件可以用pd.ExcelWriterwith pd.ExcelWriter(ssq_report.xlsx, engineopenpyxl) as writer: df_year.to_excel(writer, sheet_name按年统计, indexFalse) df_blue.to_excel(writer, sheet_name蓝球分布, indexFalse)这样生成的文件可以直接用 Excel 打开且比手动复制粘贴整齐得多。我经常把 MySQL 里跑好的冷热号统计输出成 Excel然后丢给同事继续做图表大家都不用在 SQL 和 Excel 之间来回切换。需要留意的是pymysql在连接 MySQL 8.0 时可能因为认证插件问题报错如果连不上先试ALTER USER userlocalhost IDENTIFIED WITH mysql_native_password BY password;或者换高版本pymysql。5. 避坑指南双色球数据导入和统计最常见的 5 个坑5.1 现象Excel 打开 CSV 文件全是乱码很多人从 MySQL 导出 CSV 后直接双击用 Excel 打开结果中文全部变成乱码。原因是 MySQL 默认导出的 UTF-8 文件没有 BOMExcel 在 Windows 上默认按 ANSI 编码解析中文就全散了。这个坑在双色球数据包里也常见因为整理者通常会把期号、日期、奖池说明写在一起。解决方法是在 Excel 里用“数据-从文本/CSV 导入”并手动选择编码 UTF-8不要在 Excel 里直接双击打开如果已经在文件里了把内容全选复制到记事本另存为带 BOM 的 UTF-8 文件再重新打开。我每次从 MySQL 导出 CSV 都会加一句--default-character-setutf8mb4再确保输出文件开头带 BOMWindows 下基本能一次通过。5.2 现象导入 MySQL 时提示 Duplicate entry导入.sql或 CSV 时如果表里已经有过部分数据MySQL 会报Duplicate entry 2003001 for key PRIMARY。原因很直接期号重复了。可能是之前导入过但没清理也可能是数据包本身在整理时复制了两行。解决办法是导入前先执行TRUNCATE TABLE ssq_record;把旧数据清空再导。如果源文件本身有重复用GROUP BY检查后去重再导。注意不要用REPLACE INTO来绕过报错它会先删后插晚导入的数据会默默覆盖早导入的数据你完全不知道哪一期被换了。5.3 现象导入后红球范围检查失败执行验证 SQL 时查出red1 NOT BETWEEN 1 AND 33之类的记录说明源数据本身有错。常见的错法是“红球 36”这种超出范围更隐蔽的是“01”被 Excel 变成“1”后和红球 1 混淆但范围检查不会报错。如果范围检查失败先回到原始 Excel 文件用筛选功能找出异常记录再和官方开奖信息核对。别指望数据库帮你纠错它只会忠实地存进去。所以导入前的体检很重要特别是号码列用文本格式从 CSV 导入才能保留01和1的差别。5.4 现象LOAD DATA INFILE 一直报路径错误在 MySQL 8.0 里执行LOAD DATA INFILE时报错信息往往是一大串路径权限问题。原因基本只有一个secure-file-priv限制了读取目录。你可以执行SHOW VARIABLES LIKE secure_file_priv;查看允许的目录把 CSV 放进那个目录或者直接把LOAD DATA改成SOURCE命令导入.sql文件。如果你用 Docker 安装 MySQL还要先docker cp把文件复制到容器里再指向容器内部路径。我建议新手直接用 Navicat 的导入向导它能处理分隔符、编码和封号避免踩这一地的雷。5.5 现象查询很慢明明只有三千多行只有三千多行的表怎么查都不该慢但如果你在上面跑了复杂的GROUP BY加多个OR条件又没建索引仍有可能出现几十毫秒的延迟。更常见的是你连到了别人的远程 MySQL网络延迟占主要因素。解决办法是给常用的查询条件建复合索引比如经常按蓝球统计就建KEY idx_blue_red (blue, red1)然后EXPLAIN SELECT ...查看是否走了索引。如果确认本地查询也慢检查是不是没有用WHERE条件直接全表排序ORDER BY也会触发文件排序。开奖记录表不大慢多半是语句写法问题。6. 进阶用一条 SQL 快速验证 Excel 和 MySQL 两套文件是否一致拿到这份双色球数据包后我最担心的不是某个字段出错而是 Excel 文件更新到了 3287 期MySQL 文件却停在 3275 期。两套文件只有周期一致后面的分析才可信。验证方法很简单在 Excel 里用数据透视表统计每个蓝球出现的次数导出后记为excel_blue_cnt在 MySQL 里跑同样的统计SELECT blue, COUNT(*) AS cnt FROM ssq_record GROUP BY blue ORDER BY blue;把两个结果放在同一张 Excel 表里对比任何不一致都能直接暴露。蓝球只有 1 到 16 共 16 个数字比较起来非常快。如果两边的蓝球分布完全一致基本说明两套文件是同一版本如果差异很大先查总数再看具体到哪几个蓝球对不上。一次我在模拟项目里就是这么发现 Excel 文件少了最近 4 期当时整个人都懵了还以为 SQL 写错后来一查是数据包发布者忘了同步数据库文件。从那以后我的习惯是先做一致性校验再开始任何分析。除了蓝球还可以用同样的思路验证红球频次用UNION ALL把六列红球压平SELECT n, COUNT(*) AS cnt FROM ( SELECT red1 AS n FROM ssq_record UNION ALL SELECT red2 FROM ssq_record UNION ALL SELECT red3 FROM ssq_record UNION ALL SELECT red4 FROM ssq_record UNION ALL SELECT red5 FROM ssq_record UNION ALL SELECT red6 FROM ssq_record ) t GROUP BY n ORDER BY n;这段 SQL 的精髓是UNION ALL它不会去重所以最终记录数是 3287 乘 6每个红球位置都被统计一次。Excel 那边用COUNTIF对 1 到 33 每个数字统计相同频次两边一对就知道有没有缺失或重复。这个方法我几乎每次拿到双格式数据都会做成本不到一分钟却能让后续的走势分析和频次统计建立在可信的数据上。希望帮到你。本文还有配套的精品资源点击获取