简介银联官方2020年4月25日发布的银行卡BIN数据以Excel和MySQL两种格式打包共包含9868条卡片记录覆盖卡BIN、BIN长度、发卡行、银行卡名称、卡类型、卡号长度等核心字段适合支付接口开发、交易反欺诈、金融数据分析等场景也便于需要批量获取合规卡BIN信息的开发者直接读取。资源包共7个文件压缩后仅1.12MB内含5个按场景分类的Excel表格含非标卡、农民工卡、跨行转账卡、单位结算卡及常规卡等和一份整理好的SQL脚本可一键导入MySQL数据库省去数据清洗与格式转换时间。数据源自银联官方2020年4月最新发布权威性高、信息完整SQL语句经过整理表结构清晰查询方便尤其适合银行联调、商户进件核验、风控策略验证等需要快速比对卡BIN的真实场景。目前已有3483人浏览学习对支付、金融、电商领域的技术人员来说是一份省时省力的实用数据资产。 做支付系统对接那几年办公室里最常被问到的一句话就是这卡是哪个行的照卡号前几位去网页上现查慢不说还经常遇到查不到的小银行。后来我把银行卡BIN数据整理了一份放本地配合Excel做清洗、MySQL做存储查询同类问题从几分钟缩短到了秒回排查支付异常时也不用再依赖外部接口。这篇文章就是我整理这套数据全过程的记录重点围绕三个关键词展开银行卡BIN、Excel、MySQL。适合做支付开发、风控策略、数据运营的朋友参考也适合刚接触卡BIN概念、想自己建一套本地查询库的同学照着操作。1. 银行卡BIN是什么为什么支付和风控绕不开这张表1.1 从卡号前6位到8位IINBIN到底标识了什么BIN是Bank Identification Number的缩写也就是银行卡号最前面的一段数字。过去统一是6位现在卡组织逐步向8位扩展术语上叫IINIssuer Identification Number但业内在日常沟通里还是习惯叫BIN。它的核心作用就是三件事标识这张卡是哪家银行发的、属于哪个卡组织银联、Visa、Mastercard、美国运通等、是借记卡还是贷记卡。听起来简单实际业务里离不开它。支付网关要根据发卡行选择清算通道不同通道对卡种和卡组织支持不一样选错了交易就失败风控规则引擎要根据卡的类型判断风险等级某些BIN段只允许小额交易某些卡组织在做活动时需要单独识别客服排查用户投诉时也要第一时间判断卡是哪个行的、是不是预付费卡。没有一套本地BIN库这些场景全都要实时调远程接口不仅慢还有配额限制高峰期根本扛不住。1.2 覆盖范围、字段完整度、匹配策略决定这套数据好不好用拿到一份BIN数据后我不是马上导入MySQL而是先想清楚三个问题。因为这三个问题直接决定了这套数据将来能不能用、怎么用。第一个是覆盖范围。所谓最全到底全到什么程度我见过不少网上流传的版本国有大行和头部股份行都能覆盖但城商行、农商行、外资行和互联网银行经常缺。这份2020年的整理版本覆盖量在当时算是相当能打的不过横向对比渠道数据源之后依然发现有个别新成立银行的BIN没收录。所以你不能因为文件名写着最全就完全信任还得自己去补。第二个是字段完整度。BIN数据不只是卡号前缀银行名两列真正好用的表至少要包含卡组织、卡类型借记/贷记/准贷记/预付费、发卡地区、卡品牌甚至行别代码。有些数据源只给了银行名和卡类型风控场景里根本不够用。如果你想做联名卡识别就还需要额外的品牌字段。第三个是匹配策略。见过不少业务同学直接拿卡号前6位去匹配一张6位BIN表这在8位IIN普及之后会出问题。同一张卡既可以用前8位匹配到更精确的卡产品信息也能用前6位匹配到大类。所以后面查询时一定要先尝试长BIN匹配不到再退化到短BIN这个优先级逻辑我在MySQL的SQL语句里会专门演示。2. 拿到银联官方发布的BIN数据先别急着入库2.1 关于官方发布的两种理解网上流传的银行卡BIN数据很多都标注银联官方发布。这里得先把话说清楚。银联作为卡组织和转接清算机构确实维护着完整的BIN库官方也提供了开放查询接口给商户和机构按卡号查BIN但直接把完整数据表以Excel形式向社会公众发放的情况极少。市面上流传的所谓官方版本多数是某段时间有人通过官方在线查询工具逐卡查询后汇总整理的也可能是机构内部数据流出后转了几手的版本。所以我对官方发布这四个字的理解是数据内容来源于官方渠道而不是银联官方真的发过这张Excel表。这并不影响它的使用价值但会影响你对数据质量的心理预期。来源决定可信度既然是二手整理验货这一步就不能省。2.2 抽验、Luhn校验、内部一致性三步完成数据验货拿到表之后我一般做三步检查全部通过才会进入Excel清洗环节。第一步是抽样验证。随机抽20到30个BIN用银联开放平台的卡BIN查询接口或者支付宝、微信支付里自带的银行卡校验能力去核对。如果抽查样本的发卡行和原表标注的一致说明这个数据源大概率是走的官方查询通道可信度较高。第二步是做Luhn算法校验。卡号不是随便生成的完整卡号最后一位是根据Luhn算法计算出来的校验位。算法逻辑是从右往左奇数位数字直接相加偶数位数字先乘以2乘积大于9就减9再把所有结果求和和能被10整除就说明这个卡号结构上合法。用Excel写一个校验列能快速筛掉一批瞎编的测试数据。这个检验不针对BIN本身但对确认数据源质量很有用——如果一个数据源里的卡号样本大量过不了Luhn那它八成是手工编的。第三步是看内部一致性。同一个BIN在表里出现两次银行名却不一样或者表里的银行卡类型和卡品牌之间有明显矛盾比如某张卡标注银联借记卡但卡品牌字段却写了Visa。出现这种情况就说明这张表可能有拼接痕迹用的时候要格外小心该补的字段得自己补。3. Excel清洗BIN数据的五个关键动作3.1 字段类型是第一道坎BIN是编号不是数值拿到原始数据后第一个动作不是删数据而是先把字段类型理清楚。BIN虽然是纯数字但它的含义是编号不是数值不能参与加减乘除。我在Excel里见过最经典的坑有人双击单元格之后BIN列前面有0的几位直接被吞了6位变成5位后面在MySQL做匹配时怎么都对不上。正确的做法有两种。一种是选中BIN列后点数据-分列在第三步把列数据格式选为文本另一种是在Excel导入CSV时直接指定该列为文本。如果你已经在单元格里存成了数字可以用TEXT(A2,0)把数值重新转成文本再粘贴为值覆盖原列。注意转完之后要重新检查一遍看有没有因为科学计数法导致的精度丢失。3.2 去重、标准化银行名、批量补全与体检清洗阶段我按下面这五个动作走每个动作都很机械但顺序不能乱。第一步是去重。理论上BIN不会重复但拼接的数据源里同一段BIN出现在多行的情况很常见。我会先用条件格式高亮重复值扫一遍再用删除重复值功能按BIN加银行名两个字段组合去重。这里有个前提先做银行名标准化再做去重否则同一个银行因为写法不同会被当成两条数据留下来。第二步是银行名称标准化。表里经常同时出现中国工商银行、工商银行、工行三种写法。我自己的做法是维护一张银行标准名称对照表用VLOOKUP(B2,银行对照表!A:B,2,FALSE)匹配出标准名再覆盖原列。如果你手头没有行别代码表至少要把常见简称和别名全部映射到标准名称这步偷懒的话后面统计银行维度会一塌糊涂。第三步是补全卡类型和卡组织。有些BIN行只有银行名卡类型和卡组织是空的。可以通过已知卡BIN段范围内其他行的规律做批量推测比如同一段BIN的前面几行都是贷记卡那缺失行大概率也是贷记卡也可以用其他数据源交叉补全。实在补不上的标记为未知不要硬猜硬猜的数据比空缺更危险。第四步是字段格式整理。银行名称统一去掉首尾空格卡类型和卡组织统一大小写省得之后导入MySQL后出现同类数据写法和内容不一致的情况。这里我一般会用TRIM函数先处理一遍再粘贴为值。第五步是体检。用数据透视表按银行统计BIN数量按卡组织统计条数粗看分布是否合理。举个例子如果某家地方性小银行的BIN数量占到了全国一半明显是源数据有问题。这一步不需要精确是用来发现重大异常的。3.3 几万行级别的Excel操作体验优化处理BIN数据通常就是几万行到十几万行Excel完全扛得住。但操作时会卡主要是公式太多导致的重算开销。这里有三个我自己用下来很有效的习惯。第一开始清洗前先关闭自动计算改为手动。路径在公式-计算选项-手动等所有清洗步骤做完了再统一按F9重算避免每拉一个单元格就全表重算。第二公式生成的新列确认无误后立刻复制-选择性粘贴-粘贴为值把公式消化掉让工作簿保持体积小、打开快。第三尽量少用整列引用比如VLOOKUP里写A:B看起来方便但Excel会把整列都纳入计算范围数据量大了明显变慢改成具体范围A1:B10000会好很多。提示清洗完的Excel表另存一份CSV时建议用UTF-8编码。Windows下直接另存为CSV默认是ANSI编码后面导入MySQL时用utf8mb4字符集会乱码这个坑我踩过一次印象很深。4. MySQL建表与导入从CSV到可查询库的一次性实操4.1 表结构设计的几个取舍清洗后得到一份干净的Excel表下一步就是入库。先给出我实际用的建表语句CREATE TABLE bank_bin ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, bin_no VARCHAR(11) NOT NULL COMMENT 银行卡BIN/IIN编号, bank_code VARCHAR(16) DEFAULT NULL COMMENT 银行行别代码, bank_name VARCHAR(64) NOT NULL COMMENT 发卡行标准名称, card_type VARCHAR(16) DEFAULT NULL COMMENT 卡类型借记卡/贷记卡/准贷记卡/预付费卡, card_brand VARCHAR(16) DEFAULT NULL COMMENT 卡组织银联/Visa/Mastercard/美国运通, area VARCHAR(32) DEFAULT NULL COMMENT 发卡地区, source_version VARCHAR(32) DEFAULT NULL COMMENT 数据版本号, update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 记录更新时间, PRIMARY KEY (id), UNIQUE KEY uk_bin (bin_no), KEY idx_bank_name (bank_name), KEY idx_card_type (card_type) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT银行卡BIN基础数据表;表结构里有几个细节值得说一下。bin_no我用VARCHAR(11)没用INT。原因很简单BIN是编号不是数值以后如果扩展到更长的IIN或者出现前导0的情况用整数类型会出大问题。VARCHAR(11)在MySQL里存索引也够用查询性能上和数据量相比根本不需要担心。uk_bin唯一索引是必须的。它既保证了数据不会重复导入也为后面按BIN精确查找提供索引支撑。idx_bank_name和idx_card_type是给统计类的分组查询用的BIN表本身数据量不大有这两条辅助索引已经足够。字符集直接选utf8mb4。MySQL 8里默认就是这个兼容中文和生僻字符比如有些银行名称里的特殊汉字用utf8mb3可能存不进。4.2 LOAD DATA INFILE导入及secure_file_priv的坑数据量不大时其实用Navicat或DataGrip的可视化导入最省事。选中表右键导入向导选CSV文件字段映射看清楚跑一次就结束了。但命令行方式也得会因为它是自动化脚本的基础以后做增量更新时离不开。LOAD DATA INFILE /var/lib/mysql-files/bank_bin.csv INTO TABLE bank_bin CHARACTER SET utf8mb4 FIELDS TERMINATED BY , OPTIONALLY ENCLOSED BY LINES TERMINATED BY \n IGNORE 1 LINES (bin_no, bank_code, bank_name, card_type, card_brand, area);这条语句有两个高频坑。第一个是secure_file_priv。MySQL 8默认限制LOAD DATA只能读指定目录下的文件你随便放一个路径大概率会报ERROR 1290。最简单的处理就是把CSV文件丢进/var/lib/mysql-files/目录或者用SHOW VARIABLES LIKE secure_file_priv;看看当前限定的目录是哪个再放进去。第二个是编码。前面说过Windows下Excel另存的CSV经常是ANSI编码直接用utf8mb4导入会乱码解决办法是先转成UTF-8编码再导入或者在导入前用iconv命令做一次转码。4.3 从Excel到MySQL的字段映射检查不管是可视化导入还是LOAD DATA导入完成后一定要做一次数据量核对。我通常用三条SQL快速检查SELECT COUNT(*) FROM bank_bin;看总行数和Excel里去重后的行数是否一致SELECT COUNT(DISTINCT bin_no) FROM bank_bin;和总数对比确保没有重复SELECT * FROM bank_bin LIMIT 20;抽查几条确认银行名没有乱码卡类型字段没有变成空串。这三条走完数据才算真正落地。5. 实际查询的SQL套路单卡匹配与统计分析5.1 完整卡号反查BIN时先长后短的排序技巧数据入库后最常用的一个场景就是给我一个完整卡号找出对应的BIN信息。这看着简单实际执行时有个容易忽略的细节——匹配优先级。SELECT bin_no, bank_name, card_type, card_brand FROM bank_bin WHERE 6222021234567890 LIKE CONCAT(bin_no, %) ORDER BY CHAR_LENGTH(bin_no) DESC LIMIT 1;这条SQL的逻辑就是上面说过的先长后短。如果既有6位BIN段又有8位IIN段用ORDER BY CHAR_LENGTH(bin_no) DESC让数据库优先匹配更精确的8位段匹配不到时自动退化到6位段。LIKE CONCAT(bin_no, %)走的是索引的最左前缀BIN表数据量在百万级别以内性能完全没问题。如果你不想在SQL里做LIKE匹配也可以在应用层先截取卡号前8位去查查不到再用前6位查一次。两种方式效果一样前者省代码后者逻辑更直观看团队习惯。我自己更倾向于第一条SQL因为它把匹配细节收敛在数据库里应用层代码不需要感知BIN位数变化。5.2 银行维度、卡类型维度统计与Excel回填除了单卡查询日常用得多的还有统计类SQL。比如按银行维度看借贷记分布SELECT bank_name, card_type, COUNT(*) AS cnt FROM bank_bin GROUP BY bank_name, card_type ORDER BY cnt DESC;再比如看卡组织占比SELECT card_brand, COUNT(*) AS cnt, ROUND(COUNT(*)/SUM(COUNT(*)) OVER(), 4) AS ratio FROM bank_bin GROUP BY card_brand ORDER BY cnt DESC;这些统计结果可以直接从MySQL导出再回到Excel做图表。BIN数据本身不大做报表分析Excel的透视表和图表还是比直接写SQL查询结果要直观得多。我的习惯是MySQL负责存和取Excel负责看和呈现各干各擅长的事。6. 时效性是BIN库的隐形杀手我踩过的更新坑6.1 2020版本放到今天有哪些典型失真最后必须说一个最坑的地方就是BIN数据的时效性。我手里这份2020版本放到现在用已经出现不少失效的BIN段。具体表现有三类银行合并导致发卡行变更比如原来的城商行被股份行合并卡BIN对应的银行名已经变了银行停发旧卡产品老BIN段不再新增卡号但旧卡还能用卡组织新发BIN段比如2020年之后新成立的互联网银行在表里完全没有收录。这意味着如果你拿2020年的表直接上生产环境新用户的卡大概率识别不出银行老用户的卡也可能被识别成已经合并前的旧银行名。这不是数据质量差而是金融数据的天然属性——它有生命周期。BIN数据不用天天更新但绝对不能几年不更新。6.2 增量更新、事件提醒与Redis缓存方案我的建议是除非你只是拿它做产品Demo或联调测试否则生产环境必须建立更新机制。具体做法分三步。第一步是定期增量更新。可以按季度从银联开放平台或者银行官网查询新发BIN更新时在source_version字段里写入版本号比如2020_original、2024Q1_supplement方便追溯。增量数据先导入临时表再用LEFT JOIN找出新增和变更的BIN最后合并到主表。第二步是利用MySQL事件调度器做提醒。BIN表是低频变化数据不需要实时监控但需要定期人工过一遍。可以设一个每月任务把最近90天没有变化的BIN记录导出或者反过来检查update_time超过一年没有更新的记录数生成一张清单供人工核对。第三步是应用层加缓存TTL。BIN数据非常适合做Redis缓存key用BIN段value存银行和卡类型信息TTL设置24到48小时。这样线上请求先走缓存缓存淘汰后回源MySQL不会给数据库造成压力。更新BIN表时统一在同步脚本里删掉相关缓存保证数据一致。提示增量更新的脚本里一定要保留update_time字段的自动更新机制。我见过有人批量UPDATE时把update_time覆盖成了固定值结果后面排查数据变更时间全都失真了。这个字段值的是时间不是摆设。我实际维护这套BIN库大概一年半最大的体会是数据本身不值钱值钱的是围绕数据建立的更新流程和异常核对机制。如果只是拿一份Excel导入MySQL就完事那三个月后它会变成一份坑人的过期数据。用Excel做初次清洗的优势是所见即所得几万行数据完全够用等后续增量频率高了再把清洗逻辑逐步搬进脚本。整个过程不需要什么高深技术耐心和细心占大头。如果你也正准备搭一套本地BIN查询库希望这篇记录能帮你少走几步弯路。本文还有配套的精品资源点击获取