
1. 为什么 pymssql 连 SQL Server 总在第一步卡住Python 连 SQL Server 的库有好几个pymssql 算是比较轻的一个它不走 ODBC 驱动管理器那一层直接通过 FreeTDS 协议跟 SQL Server 通信装完就能用不需要额外配 DSN。适合谁适合本地开发、内网小工具、数据同步脚本这类场景——你只想快速把一张表读出来不想折腾系统级驱动。但它的坑也很集中装包时编译失败、连接时报 20009、中文取出来是乱码、pymssql.connect()参数顺序写错。这些问题我在不同机器上基本都踩过一遍。这篇就按“装依赖 → 配连接 → 跑验证 → 排错”的顺序走一遍最后给一份可以直接复制的连接骨架和验证脚本。另外提一句调试数据库脚本时经常要顺手问 AI 一些 SQL 或报错含义如果多个工具各配一套 Key 会很乱。我习惯用 TaoToken 把模型通道统一管起来后面第 2 节会说怎么接不影响数据库本身的连接逻辑。2. 环境依赖安装与 TaoToken 前置准备2.1 安装 pymssql先确认 Python 版本pymssql 对 3.8 以上支持比较好python --version pip install pymssql如果你在 Windows 上直接pip install pymssql就成功了那说明有预编译 wheel省事。Linux 上如果报编译错误通常是缺 FreeTDS 开发头文件# Debian/Ubuntu sudo apt-get install freetds-dev # CentOS/RHEL sudo yum install freetds-devel装完再pip install pymssql。验证是否装好import pymssql print(pymssql.__version__)能打印版本号就说明库本身没问题接下来才是连接的事。2.2 用 TaoToken 统一管理调试期的 AI 工具 Key调试阶段我经常要问 AI“pymssql 报 20009 是什么原因”“这段 SQL 在 SQL Server 里语法对不对”。如果每个编辑器插件、每个 CLI 工具都单独填一次 Key换机器就得重配。TaoToken 的做法是给你一个统一的 API 通道工具侧只认一个 Key 和一个 base_url。先到控制台建 Keyhttps://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite建完在 API Keys 页面能看到以sk-开头的密钥https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite接入时把 base_url 指向https://taotoken.net/api注意这个地址不加 UTM 参数Key 填刚建的那个。这样你在不同工具里问数据库报错走的是同一条通道额度也统一看。注意TaoToken 管的是 AI 模型的调用通道不是数据库连接通道。SQL Server 的连接还是 pymssql 直连两者别混。如果你要长期跑编码类任务比如让 AI 帮你批量生成 SQL 脚本可以看下 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite3. 可复制的 pymssql 连接配置骨架3.1 连接参数怎么写pymssql.connect()支持位置参数也支持关键字参数。位置参数的顺序是host, user, password, database但我不建议用位置参数——一旦记错顺序报错信息很难指向真正原因。用关键字参数最稳import pymssql conn pymssql.connect( server127.0.0.1, port1433, usersa, passwordYourStrongPassword, databaseWMS, charsetutf8, login_timeout10, timeout30, as_dictFalse )几个参数说明一下。server和host在 pymssql 里是等价的写哪个都行。port默认 1433如果 SQL Server 配了动态端口就得显式指定。charset建议写utf8不写的话中文可能出问题。login_timeout是登录超时秒数默认值偏大调试时设小一点能更快暴露网络问题。as_dictTrue时查询结果返回字典而不是元组按列名取值更方便。3.2 封装成可复用的连接函数每次都写一遍 connect 太啰嗦封装一下import pymssql from contextlib import contextmanager DB_CONFIG { server: 127.0.0.1, port: 1433, user: sa, password: YourStrongPassword, database: WMS, charset: utf8, login_timeout: 10, } contextmanager def get_conn(): conn None try: conn pymssql.connect(**DB_CONFIG) yield conn finally: if conn: conn.close()用contextmanager的好处是连接一定会关不会因为异常漏掉close()。调用时with get_conn() as conn: cursor conn.cursor() cursor.execute(select version) print(cursor.fetchone()[0])3.3 建表、插入、更新、删除的写法建表时用try/except/finally包住出错回滚def create_table(): with get_conn() as conn: cursor conn.cursor() cursor.execute(drop table if exists teacher) sql create table teacher( id int primary key, name varchar(20) not null, sex varchar(2) not null, age int not null ) try: cursor.execute(sql) conn.commit() print(CREATE TABLE SUCCESS.) except pymssql.Error as err: print(fCREATE TABLE FAILED, CASE:{err}) conn.rollback()插入和更新同理关键是commit()和rollback()要配对。pymssql 默认不是自动提交忘了 commit 数据不会落库这个坑很常见。def insert_record(): with get_conn() as conn: cursor conn.cursor() sql insert into teacher values(1001, 小明, 男, 18) try: cursor.execute(sql) conn.commit() print(INSERT SUCCESS.) except pymssql.Error as err: print(fINSERT FAILED, CASE:{err}) conn.rollback()3.4 查询与中文乱码处理查询用fetchall()拿全部fetchone()拿一条rowcount看影响行数。中文乱码是老问题如果charsetutf8还乱可以试着手动转def query_record(): with get_conn() as conn: cursor conn.cursor() cursor.execute(select * from teacher) results cursor.fetchall() for row in results: num row[0] name row[1].encode(latin-1).decode(gbk) sex row[2].encode(latin-1).decode(gbk) age row[3] print(fid:{num}, name:{name}, sex:{sex}, age:{age})不过更推荐的做法是建库建表时就用nvarchar而不是varchar从源头避免编码问题。varchar存中文在排序规则不匹配时就会出乱码nvarchar是 Unicode 存储省心很多。4. 验证请求与成功结果4.1 最小验证脚本把下面这段存成test_conn.py直接跑import pymssql def main(): try: conn pymssql.connect( server127.0.0.1, port1433, usersa, passwordYourStrongPassword, databaseWMS, charsetutf8, login_timeout10 ) cursor conn.cursor() cursor.execute(select version) data cursor.fetchone() print(fDatabase version: {data[0]}) conn.close() except pymssql.Error as err: print(fCONNECT FAILED: {err}) if __name__ __main__: main()成功的话会打印类似Microsoft SQL Server 2019 (RTM) - 15.0.2000.5的版本信息。这一步通了说明网络、账号、库名、驱动都没问题后面建表插数据就是顺水推舟。4.2 用 AI 辅助看报错如果验证脚本报错把完整错误信息贴给模型问一下比自己翻文档快。用 TaoToken 的模型对话入口https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite比如报20009: Unable to connect: Adaptive Server is unavailable模型会告诉你大概率是端口没通或 SQL Server 没开 TCP/IP 协议。这种定位比盲猜高效。5. 本篇常见报错排查5.1 报错 20009连不上服务器这是最高频的。按顺序查SQL Server 服务是否启动TCP/IP 协议是否启用在 SQL Server 配置管理器里端口 1433 是否监听netstat -an | findstr 1433防火墙是否放行。如果 SQL Server 用的是命名实例端口可能是动态的需要在配置管理器里固定成 1433。5.2 报错 18456登录失败账号密码不对或者该账号没开 SQL Server 身份验证。默认安装可能只开了 Windows 身份验证需要在服务器属性里改成“SQL Server 和 Windows 身份验证模式”然后重启服务。sa账号如果被禁用也要启用。5.3 中文乱码前面说过优先用nvarchar。如果表结构改不了就在连接时加charsetutf8查询时再手动encode(latin-1).decode(gbk)。注意这个转换只对varchar存的中文有效nvarchar不需要。5.4 安装 pymssql 编译失败Linux 上缺freetds-devWindows 上如果 Python 版本太新可能没有对应 wheel。解决办法Linux 装开发包Windows 换 Python 3.8–3.11 之间的版本或者用 conda 装conda install -c conda-forge pymssql。5.5 忘记 commit 导致数据没落库pymssql 默认手动提交execute之后不commit关连接时改动就丢了。养成习惯写操作后立刻conn.commit()异常时conn.rollback()。6. 把连接骨架用起来到这里你手上应该有一份能跑的连接配置和验证脚本了。我的建议是先把test_conn.py跑通确认版本号能打印出来再去动建表和增删改查。顺序反了的话一旦报错你分不清是连接问题还是 SQL 问题。调试过程中如果遇到不认识的报错码用 TaoToken 的模型对话问一下比搜索引擎快https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite需要统一管理多个 AI 工具 Key 的话控制台在这里https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite最后一个小技巧把DB_CONFIG里的密码换成从环境变量读别硬编码在脚本里。os.environ.get(DB_PASSWORD)一行的事能省掉以后改密码时满仓库找的麻烦。