【Python Document】pymssql 官方文档翻译

2023-12-29 00:40

本文主要是介绍【Python Document】pymssql 官方文档翻译,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

英文原文档地址: http://www.pymssql.org/index.html
翻译结束于: 2020.7.24
全文严格按照原文档翻译(大概), 纯属翻译着玩, 措辞不一定严谨.
禁止商业使用

文章目录

  • pymssql 介绍
      • 资源
      • 特性
      • Works
      • License
      • Survey
      • Recent Changes
  • 介绍
      • 结构
      • 项目社区
      • 项目状态
      • 发展动态
  • pymssql 示例
      • 基础功能(严格的 DB-API 规范)
      • 迭代结果
      • 行字典
      • 使用 `with` 语句 (上下文管理器)
      • 调用存储过程
  • _mssql 示例
      • 快速开始使用各种方法
      • 一个捕获异常的示例
  • 发布记录
      • pymssql 2.0.0
      • pymssql module
      • Connection 类
      • Cursor 类
      • _mssql 模块
      • MSSQLConnection 类
  • FreeTDS 配置
      • 测试连接
  • pymssql 模块参考
  • _mssql 模块参考
  • 从1.x 迁移至 2.x
      • str vs. unicode
      • 处理 uniqueidentifier 列
      • pymssql.connect 的参数
      • 参数替换
  • 常见问题
      • 不能连接到 SQL Server
      • 返回日期错误
      • 查询没有返回记录
      • 结果丢失字段
      • pymssql 不会将 DATE 和 TIME 列反序列化为 datetime.date 和 datetime.time 实例
      • 共享对象 “libsybdb.so.3” 没找到
      • DB-Lib error message 20004, severity 9: Read from SQL server failed

pymssql 介绍

是一种 Microsoft SQL Server 的简化数据库接口, 基于 FreeTDS 构建的, 用于为 Python 提供与 SQL Server 连接的 DB-API (PEP-249) 接口.
pymssql 的 2.x 版本分支基于 FreeTDS 最新版本构建, 解决了旧的 FreeTDS 版本和 1.x 版本分支的诸多问题.

资源

  • Docs & Project Home
    • Quick Start: coming soon 😃
    • FAQ & Troubleshooting
  • PYPI Project
  • GitHub
  • Discussion
  • FreeTDS User Guide

特性

  • 适配 Unicode 编码
  • 适配 Python 3
  • 适用于主流操作系统
  • 基于 Cython 编写以提高性能
  • 包含一个低级模块 (_mssql), 简化严格的 DB-API
  • 支持具有返回值和参数的存储过程
  • 具有综合性的测试套件

Works

License

Survey

Recent Changes

(以上皆是废话, 均不详表)


介绍

结构

pymssql 包由以下两个模块组成:

  • pymssql – 若您在意 DB-API 的标准性或习惯了 DB-API 的语法, 您可使用它
  • _mssql – 若您在意程序的性能, 且想简化代码, 您可使用它 (该模块比前者更简单)

项目社区

http://groups.google.com/group/pymssql

项目状态

当前发布: 2.x 是当前开发的版本分支. 它使用 Cython 和最新版本的 FreeTDS 库全面重写(消除了旧版本 FreeTDS 的一些限制)
旧版本: 1.0.3是旧版本, 且不再开发更新

注意:
本文档适用于 pymssql 2.x .
此文档假设您只使用基于 pymssql 2.x 或更新版本编写的代码. 所有基于旧版本的描述均被移除.
如果您需要 1.x 版本的帮助, 请移步Google Code documentation Wiki

发展动态

(废话不表)


pymssql 示例

使用 pymssql 模块的示例脚本

基础功能(严格的 DB-API 规范)

from os import getenv
import pymssqlserver = getenv("PYMSSQL_TEST_SERVER")
user = getenv("PYMSSQL_TEST_USERNAME")
password = getenv("PYMSSQL_TEST_PASSWORD")conn = pymssql.connect(server, user, password, "tempdb")
cursor = conn.cursor()
cursor.execute("""
IF OBJECT_ID('persons', 'U') IS NOT NULLDROP TABLE persons
CREATE TABLE persons (id INT NOT NULL,name VARCHAR(100),salesrep VARCHAR(100),PRIMARY KEY(id)
)
""")
cursor.executemany("INSERT INTO persons VALUES (%d, %s, %s)",[(1, 'John Smith', 'John Doe'),(2, 'Jane Doe', 'Joe Dog'),(3, 'Mike T.', 'Sarah H.')])
# you must call commit() to persist your data if you don't set autocommit to True
# 如果你没有将参数autocommit设为true, 那么你必须调用commit()函数来提交数据
conn.commit()cursor.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')
row = cursor.fetchone()
while row:print("ID=%d, Name=%s" % (row[0], row[1]))row = cursor.fetchone()conn.close()

迭代结果

你可以使用迭代器来代替使用 while 循环. 迭代器是 pymssql 对 DB-API 的扩展.

conn = pymssql.connect(server, user, password, "tempdb")
cursor = conn.cursor()
cursor.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')for row in cursor:print('row = %r' % (row,))conn.close()

行字典

在获取行 (译注:应该指的是记录) 的时候, 可以指定用字典的样式而不是元组返回. 这样就允许使用列 (译注:应该指的是字段) 的名字访问而不是通过数字索引. 注意 as_dict 参数

conn = pymssql.connect(server, user, password, "tempdb")
cursor = conn.cursor(as_dict=True)cursor.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')
for row in cursor:print("ID=%d, Name=%s" % (row['id'], row['name']))conn.close()

使用 with 语句 (上下文管理器)

您可以使用 Python 的 with 语句实现连接和游标. 这样您就不必每次都去手动关闭它们了.

with pymssql.connect(server, user, password, "tempdb") as conn:with conn.cursor(as_dict=True) as cursor:cursor.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')for row in cursor:print("ID=%d, Name=%s" % (row['id'], row['name']))

调用存储过程

自 pymssql2.0.0 起, 使用 db-lib 的 rpc 接口可以实现调用存储过程

with pymssql.connect(server, user, password, "tempdb") as conn:with conn.cursor(as_dict=True) as cursor:cursor.execute("""CREATE PROCEDURE FindPerson@name VARCHAR(100)AS BEGINSELECT * FROM persons WHERE name = @nameEND""")cursor.callproc('FindPerson', ('Jane Doe',))for row in cursor:print("ID=%d, Name=%s" % (row['id'], row['name']))

译注: 上面第 10 行中的 cursor.callproc() 方法在 API 文档中未提及, 它是用来调用指定的存储过程的方法. 因为上面第 3 行的 execute() 方法只会在数据库中建立这个存储过程, 但不会立即执行它, 必须使用 callproc() 才能运行. 该方法的第一个参数是存储过程的名字, 第二个参数是一个元组, 里面装着提供给存储过程的参数.


_mssql 示例

快速开始使用各种方法

import _mssql
conn = _mssql.connect(server='SQL01', user='user', password='password', \database='mydatabase')
conn.execute_non_query('CREATE TABLE persons(id INT, name VARCHAR(100))')
conn.execute_non_query("INSERT INTO persons VALUES(1, 'John Doe')")
conn.execute_non_query("INSERT INTO persons VALUES(2, 'Jane Doe')")
# how to fetch rows from a table 如何从表中获取行
conn.execute_query('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')
for row in conn:print "ID=%d, Name=%s" % (row['id'], row['name'])
# examples of other query functions 其他查询方法的例子
numemployees = conn.execute_scalar("SELECT COUNT(*) FROM employees")
numemployees = conn.execute_scalar("SELECT COUNT(*) FROM employees WHERE name LIKE 'J%'")    # note that '%' is not a special character here
employeedata = conn.execute_row("SELECT * FROM employees WHERE id=%d", 13)
# how to fetch rows from a stored procedure 如何从存储过程中获取行
conn.execute_query('sp_spaceused')   # sp_spaceused without arguments returns 2 result sets
res1 = [ row for row in conn ]       # 1st result
res2 = [ row for row in conn ]       # 2nd result
# how to get an output parameter from a stored procedure 如何从存储过程获取输出参数
sqlcmd = """
DECLARE @res INT
EXEC usp_mystoredproc @res OUT
SELECT @res
"""
res = conn.execute_scalar(sqlcmd)
# how to get more output parameters from a stored procedure 如何从存储过程中获取更多输出参数
sqlcmd = """
DECLARE @res1 INT, @res2 TEXT, @res3 DATETIME
EXEC usp_getEmpData %d, %s, @res1 OUT, @res2 OUT, @res3 OUT
SELECT @res1, @res2, @res3
"""
res = conn.execute_row(sqlcmd, (13, 'John Doe'))
# examples of queries with parameters 带参数的查询示例
conn.execute_query('SELECT * FROM empl WHERE id=%d', 13)
conn.execute_query('SELECT * FROM empl WHERE name=%s', 'John Doe')
conn.execute_query('SELECT * FROM empl WHERE id IN (%s)', ((5, 6),))
conn.execute_query('SELECT * FROM empl WHERE name LIKE %s', 'J%')
conn.execute_query('SELECT * FROM empl WHERE name=%(name)s AND city=%(city)s', \{ 'name': 'John Doe', 'city': 'Nowhere' } )
conn.execute_query('SELECT * FROM cust WHERE salesrep=%s AND id IN (%s)', \('John Doe', (1, 2, 3)))
conn.execute_query('SELECT * FROM empl WHERE id IN (%s)', (tuple(xrange(4)),))
conn.execute_query('SELECT * FROM empl WHERE id IN (%s)', \(tuple([3, 5, 7, 11]),))
conn.close()

请注意迭代器的用法以及按列名访问结果的功能. 另外请注意连接方法的参数名称与 pymssql 模块中的名称不同

一个捕获异常的示例

import _mssqltry:conn = _mssql.connect(server='SQL01', user='user', password='password',database='mydatabase')conn.execute_non_query('CREATE TABLE t1(id INT, name VARCHAR(50))')
except _mssql.MssqlDatabaseException as e:if e.number == 2714 and e.severity == 16:# table already existed, so quieten the errorelse:raise # re-raise real error
finally:conn.close()

文档未完成:
添加使用 _mssql 模块的一个调用存储过程的例子
译注: 是官方没写完, 不是我没翻译完


发布记录

发布记录 - 所有爆款变化和其他值得注意的事情

pymssql 2.0.0

这是 pymssql 的全新主要版本. 它使用 Cython 完全从头开始重写. 我们对此版本的目标是:

  • 提供对 Python 3 的支持
  • 实现对存储过程的支持
  • 为了提升性能, 使用 C 语言 (实际上是 Cython) 为 pymssql 重写 DB-API 编译器
  • 整顿清理了模块的 API 和一些代码

这就是我们决定增加本版号的原因. 不幸的是, 新版本的 API 中存在不兼容旧版本的变化. 有的脚本可能无法正常工作, 因此您必须审核您的代码. 如果您在意兼容性, 就暂时继续使用 pymssql 1.0.x , 然后慢慢地迁移到 2.0.

我们改变了项目托管方式, 现在 pymssql 托关于 GitHub:http://github.com/pymssql/pymssql

版本发行者信息:

  • Marc Abramowitz <msabramo_at_gmail_com> who joined the project in Jan 2013 and is responsible for the actual release of the 2.0 version by fixing many old tickets, coding the port to Python 3 and driving the migration to Git and GitHub.
  • Damien Churchill <damoxc_at_gmail_com> who set the foundations of the new Cython-based code base, release engineering, new site features like Sphinx, SimpleJSON and others,
  • Andrzej Kukuła <akukula_at_gmail_com> who did all the docs, site migration, and other boring but necessary stuff.
  • Jooncheol Park <jooncheol_at_gmail_com> who did develop the initial version of pymssql (until 0.5.2). Now just doing boring translation docs for Korean.
    (致敬大佬们, 但是不译)

pymssql module

  • 使用C重写, 你应该能观察到相较于之前, 这次的性能有所提升
  • pymssql.connect()dsn 参数已移除
  • pymssql.connect()host 参数被改名为 server , 以与 _mssql 模块保持一致
  • pymssql.connect()max_conn 参数已移除

Connection 类

  • autocommit() 方法被改成 pymssql.Connection.autocommit 属性, 你可以通过它修改或获取该值

Cursor 类

  • fetchone_asdict() 方法被移除. 与参数 as_dict=True 一起使用 pymssql.connect(), 然后使用常规的 fetchone()
  • fetchmany_asdict() 方法被移除. 与参数 as_dict=True 一起使用 pymssql.connect() , 然后使用常规的 fetchmany()
  • fetchall_asdict() 方法被移除. 与参数 as_dict=True 一起使用 pymssql.connect(), 然后使用常规的 fetchall()

_mssql 模块

  • 添加对存储过程 (MSSQLStoredProcedure class) 的本地支持
  • _mssql.connect() 方法的 maxconn 参数已移除
  • _mssql.connect() 方法的 timeoutlogin_timeout 参数已添加
  • 模块添加新方法 get_max_connections()set_max_connections()
  • 类名发生变换的新旧对比表如下
旧类名新类名
MssqlExceptionMSSQLException
MssqlDriverExceptionMSSQLDriverException
MssqlDatabaseExceptionMSSQLDatabaseException
MssqlRowIteratorMSSQLRowIterator
MssqlConnectionMSSQLConnection

MSSQLConnection 类

  • 添加 tds_version 属性

FreeTDS 配置

这一节是与 FreeTDS 建立连接的基本信息.
pymssql 使用 FreeTDS 包与 SQL Server 实例相连接. 您必须告诉它如何找到您的数据库服务器. 最基本的信息包括主机名, 端口号以及应该使用的协议版本.
操作系统级的 FreeTDS 配置文件是/etc/freetds.conf 或者 C:\freetds.conf, 由您自己使用的操作系统决定. 也可能使用用户自定义的配置文件, 在 Linux 系统中应该是 $HOME/.freetds.conf, 而在 Windows 系统中应该是 %APPDATA%\.freetds.conf
建议的起始内容至少为:

[global]port = 1433tds version = 7.0

使用这种配置, 您就只需要给 pymssql.connect()_mssql.connect() 方法提供主机名即可

import pymssql
connection = pymssql.connect(server='mydbserver', ...)

否则您必须提供端口

connection = pymssql.connect(server='mydbserver:1433', ...)

想要连接到默认实例之外的实例, 你需要提供该实例正在监听的端口或他的实例名称

connection = pymssql.connect(server='mydbserver\\myinstancename', ...)
# or by port number (suppose you confirmed that this instance is on port 1237)
# 或通过端口号(假设您设置它监听了端口1237)
connection = pymssql.connect(server='mydbserver:1237', ...)

请参照 pymssql module reference, _mssql module reference, 以及 FAQ 的页面.
更多有关 FreeTDS 的信息请参照:http://www.freetds.org/userguide/freetdsconf.htm

测试连接

如果您确定您的数据库服务器是连通的, 但 pymssql 因为某些原因让你不能连接, 你可以使用 FreeTDS 包自带 tsql 功能检查连接

$ tsql
Usage:  tsql [-S <server> | -H <hostname> -p <port>] -U <username> [-P <password>] [-I <config file>] [-o <options>] [-t delim] [-r delim] [-D database]
(...)
$ tsql -S mydbserver -U user

注意:
以上方法适用于当且仅当您确定您的数据库连接名在 freetds.conf 里时. 否则使用 主机名/端口 格式:
$ tsql -H mydbserver -p 1433 -U user

您需要提交密码, 如果连接成功了, 您会看到 SQL 提示:

1>

接下来您就可以执行查询语句, 或者使用 exit 指令终止会话.
如果连接失败, 那么 tsql 功能会显示错误信息.


pymssql 模块参考

_mssql 模块参考

以上两节不译, 这两节全部是 API 的参考. 这一部分不知道为什么在官方文档网站上访问是 404. 想看英文原版的, 推荐直接阅读在 GitHub 上的官方文档.

  • GitHub: pymssql文档

  • Github: _mssql文档
    至于为什么不译, 因为已经有大佬在CSDN上发布了翻译, 所以不再重复发明轮子.

  • pymssql模块官方文档的翻译

  • _mssql模块官方文档的翻译
    (侵立删)


从1.x 迁移至 2.x

因为严格的 DB-API 标准, 又因为我们在保持 2.x 版本同 1.x 版本的 pymssql 接口的一致性方面付出了努力. 因此两者差距不大, 升级起来是比较容易的.
尽管还是有所不同…

str vs. unicode

注意, 现在讨论的是 Python 2, 因为 pymssql 1.x 在 Python 3 环境下不能工作.
pymssql 1.x 会返回 str 对象

>>> pymssql.__version__
'1.0.3'
>>> conn.as_dict = True
>>> cursor = conn.cursor()
>>> cursor.execute("SELECT 'hello' AS str FROM foo")
>>> cursor.fetchall()
[{0: 'hello', 'str': 'hello'}]

而 pymssql 2.x 会返回 Unicode 对象

>>> pymssql.__version__
u'2.0.1.2'
>>> conn.as_dict = True
>>> cursor = conn.cursor()
>>> cursor.execute("SELECT 'hello' AS str FROM foo")
>>> cursor.fetchall()
[{u'str': u'hello'}]

如果您的程序用不同的代码来处理 str 对象和 unicode 对象, 那么您可能会出现问题.
您可以通过 encoding 将 unicode 转换成 str

>>> cursor.execute("SELECT 'hello' AS str FROM foo")
>>> s = cursor.fetchone()['str']
>>> s
u'hello'
>>> s.encode('utf-8')
'hello'

处理 uniqueidentifier 列

SQL server 有一种数据类型叫 uniqueidentifier .
在 pymssql 1.x 中, uniqueidentifier 列返回时的结果是 16 位的字节串. 如果您希望得到一个 uuid.UUID 对象, 您需要使用字节串自己构建.

>>> cursor.execute("SELECT * FROM foo")
>>> id_value = cursor.fetchone()['uniqueidentifier']
>>> id_value
'j!\xcf\x14D\xce\xe6B\xab\xe0\xd9\xbey\x0cMK'
>>> type(id_value)
<type 'str'>
>>> len(id_value)
16
>>> import uuid
>>> id_uuid = uuid.UUID(bytes_le=id_value)
>>> id_uuid
UUID('14cf216a-ce44-42e6-abe0-d9be790c4d4b')

在 pymssql 2.x 中, uniqueidentifier 列直接返回 uuid.UUID 对象. 如果您希望像 pymssql 1.x 那样使用字节串, 可以使用 uuid.UUID.bytes_le 来获取

>>> cursor.execute("SELECT * FROM foo")
>>> id_value = cursor.fetchone()['uniqueidentifier']
>>> id_value
UUID('14cf216a-ce44-42e6-abe0-d9be790c4d4b')
>>> type(id_value)
#<class 'uuid.UUID'>
>>> id_value.bytes_le
'j!\xcf\x14D\xce\xe6B\xab\xe0\xd9\xbey\x0cMK'

译注: 真是弱智啊, 为什么写个<class 'uuid.UUID'>就没高亮了啊. 没法子, 只好注释掉了.

pymssql.connect 的参数

参数有一点小变化, 下面是一些重要的变化.

在 pymssql 1.x 中, 提供主机信息的参数叫 host, 并且它包含了主机和端口号.
例如

conn = pymssql.connect(host='SQLHOST:1433')  # specified TCP port at a host

对于这个参数而言, 还可以使用其他语法, 用逗号代替冒号来划分主机和端口号, 指定 Windows 主机, 指定 SQL Server 实例等等.

conn = pymssql.connect(host=r'SQLHOST,5000')  # specified TCP port at a host
conn = pymssql.connect(host=r'(local)\SQLEXPRESS')  # named instance on local machine [Win]

在 pymssql 2.x 中, host 参数依旧受支持 (但我不确定它是否和 pymssql 1.x 中的拥有完全一样的功能 (译注: 这是文档作者自己说的) ). 同时还有一个叫 server 的参数用于指定主机, 与之相分离的还有一个参数叫 port.

conn = pymssql.connect(server='SQLHOST', port=1500)

参数替换

对于参数替换, pymssql 2.x 支持使用 formatpyforma.( PEP 249 paramstyles)
注意 pyformat, PEP 249 只展示了一个字符串替换的例子, 比如

%(name)s

并不能从 PEP 249 中得知其他类型的替换是不是也支持, 比如

%(name)d
%(name)f

然而在 mailing list thread ( 译注: 俺也不知道这是啥 ) 中, 一般的共识是只有字符串可行.
请注意, pymssql 2.x 不支持 %(name)d, 而 pymssql 1.x 支持. 因此,您可能必须更改使用该格式的代码, 如下

>>> pymssql.__version__
u'2.0.1.2'
>>> pymssql.paramstyle
'pyformat'>>> cursor.execute("select 'hello' where 1 = %(name)d", dict(name=1))
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "pymssql.pyx", line 430, in pymssql.Cursor.execute (pymssql.c:5900)if not self._source._conn.nextresult():
pymssql.ProgrammingError: (102, "Incorrect syntax near '('.
DB-Lib error message 20018, severity 15:\n
General SQL Server error: Check messages from the SQL Server\n")

改成

>>> cursor.execute("select 'hello' where '1' = %(name)s", dict(name='1'))
>>> cursor.fetchall()
[(u'hello',)]

或者

>>> cursor.execute("select 'hello' where 1 = %d", 1)
>>> cursor.fetchall()
[(u'hello',)]

这个问题的例子:

  • Google Group post: paramstyle changed?
  • GitHub issue #155: pymssql 2.x does not support “%(foo)d” parameter substitution style; pymssql 1.x did

常见问题

不能连接到 SQL Server

如果你的脚本不能连接到数据库, 请尝试以下步骤:

  • 检查您是否可以连接的其他工具
    如果您使用 FreeTDS , 您可以使用 tsql 指令尝试连接, 就像这样
$ tsql -H sqlserverhost -p 1433 -U user -P password -D tempdb
locale is "en_US.UTF-8"
locale charset is "UTF-8"
using default charset "UTF-8"
Setting tempdb as default database in login packet
1> SELECT @@VERSION
2> GOMicrosoft SQL Server 2012 - 11.0.2100.60 (X64)Feb 10 2012 19:39:15Copyright (c) Microsoft CorporationDeveloper Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)(1 row affected)

注意:
注意, 我使用了 tsql-H 参数而非 -S 参数. 因为使用前者就可以绕过读取存储着 freetds.conf 文件中关于 porttds version 的设置. 这也更像 pymssql 模块所做的事情.

如果您用 tsql 或其他工具都不能连接, 那么问题可能不是出在 pymssql 模块的身上. 您的服务器配置 (参考下文), FreeTDS 配置 或者网络等等可能出了问题.

如果您能使用 tsql 连接成功, 那您接下来可以使用 pymssql 连接数据库, 就像这样

>>> import pymssql
>>> conn = pymssql.connect(
...     server="sqlserverhost",
...     port=1433,
...     user="user",
...     password="password",
...     database="tempdb")
>>> conn
<pymssql.Connection object at 0x10107a3f8>
>>> cursor = conn.cursor()
>>> cursor.execute("SELECT @@VERSION")
>>> print(cursor.fetchone()[0])
Microsoft SQL Server 2012 - 11.0.2100.60 (X64)Feb 10 2012 19:39:15Copyright (c) Microsoft CorporationDeveloper Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)

如果上述方法不起作用, 那么您可以尝试设置以下一两种控制日志记录的 FreeTDS 环境变量来进行诊断

  • TDSDUMP
  • TDSDUMPCONFIG
    这两者可以都安装, 也可以择其一. 他们可以被命名, 或改为 stdout / stderr.
    这会让 FreeTDS 输出一大堆反映它正在干啥的信息, 然后您就能通过这些信息发现它正在使用与您预期相悖的端口, 或其他类似的错误. 例如
>>> import os
>>> os.environ['TDSDUMP'] = 'stdout'
>>>
>>> import pymssql
>>> conn = pymssql.connect(server="sqlserverhost")
log.c:194:Starting log file for FreeTDS 0.92.dev.20140102on 2014-01-09 14:05:32 with debug flags 0x4fff.
config.c:731:Setting 'dump_file' to 'stdout' from $TDSDUMP.
...
dblib.c:7934:20013: "Unknown host machine name"
dblib.c:7955:"Unknown host machine name", client returns 2 (INT_CANCEL)
util.c:347:tdserror: client library returned TDS_INT_CANCEL(2)
util.c:370:tdserror: returning TDS_INT_CANCEL(2)
login.c:418:IP address pointer is empty
login.c:420:Server sqlserverhost:1433 not found!
...

注意:
尽管您可能已经在 freetds.conf 文件中指定了端口, 但 pymssql 还是会默认使用端口 1433. 因此如果 SQL Server 没有运行在 1433 端口上, 您需要在调用 pymssql.connect 方法时特别指定参数 port. 不要指望 freetds.conf 文件, 尽管 tsql -S 指令会这样做. 这也是为什么我会使用 tsql -H 指令来替代, 就是为了绕开这些连接问题.

tsql -C 指令也会让 FreeTDS 输出一大堆信息, 对于排查错误很有帮助

$ tsql -C
Compile-time settings (established with the "configure" script)Version: freetds v0.92.dev.20140102freetds.conf directory: /usr/local/etcMS db-lib source compatibility: noSybase binary compatibility: noThread safety: yesiconv library: yesTDS version: 5.0iODBC: yesunixodbc: noSSPI "trusted" logins: noKerberos: noOpenSSL: noGnuTLS: no
  • SQL Server 2005 以及更高级的版本默认不支持远程连接, 您必须使用 SQL Server Surface Area Configuration 或者 SQL Server Configuration Manager 来实现特定协议和网络配置. 更改设置后, 请重启 SQL Server.
  • 如果数据库在一台远程设备上, 那就检查连接是不是被防火墙, 杀毒软件或其他安全设备阻断.
  • 如果在 Linux/Unix 上使用 pymssql 模块, 检查 FreeTDS 的配置是否正确, 并确保 pymssql 能发现它. 最简单的办法就是使用 tsql 功能. 查看 FreeTDS Configuration 以获取更多信息.
  • 如果在 Windows 系统上使用并且数据库服务器就在本地, 您可以尝试在命令提示符中运行下面代码
REG ADD HKLM\Software\Microsoft\MSSQLServer\Client /v SharedMemoryOn /t REG_DWORD /d 1 /f

返回日期错误

如果您在 Linux/*nix 上使用 pymssql, 并且怀疑返回的日期不正确, 请阅读 FreeTDS和日期页面

查询没有返回记录

这是一个比较普便的问题, 一些 pymssql 1.x (pymssql 1.0.2 是我发现问题的地方) 在 FreeTDS 0.82 环境下工作正常, 但更高版本的就不能正常返回记录了, 比如FreeTDS 0.91 . 在 SurveyMonkey 上, 我们在使用 pymssql 1.0.2 并同时将 Ubuntu 10 (包含 FreeTDS 0.82)升级到 Ubuntu 12 (包含 FreeTDS 0.91)时遇到这个问题, 例如

>>> import pymssql
>>> pymssql.__version__
'1.0.2'
>>> conn = pymssql.connect(host='127.0.0.1:1433', user=user,
...                        password=password, database='tempdb')
>>> cursor = conn.cursor()
>>> cursor.execute('SELECT 1')
>>> cursor.fetchall()
[]

详情请看 GitHub issue 137: pymssql 1.0.2: No result rows are returned from queries with newer versions of FreeTDS.

这里有两种方法修复这个问题

  1. (推荐) 升级到 pymssql 2.x .
>>> import pymssql
>>> pymssql.__version__
u'2.0.1.2'
>>> conn = pymssql.connect(host='127.0.0.1:1433', user=user,
...                        password=password, database='tempdb')
>>> cursor = conn.cursor()
>>> cursor.execute('SELECT 1')
>>> cursor.fetchall()
[(1,)]
  1. 升级到 pymssql 1.0.3 .
>>> import pymssql
>>> pymssql.__version__
'1.0.3'
>>> conn = pymssql.connect(host='127.0.0.1:1433', user=user,
...                        password=password, database='tempdb')
>>> cursor = conn.cursor()
>>> cursor.execute('SELECT 1')
>>> cursor.fetchall()
[(1,)]

结果丢失字段

造成您的结果记录丢失字段的可能情况是您是否有配合参数 as_dict=True 来使用连接或游标, 并且您的查询中包含一个没有名称的字段
例如:

>>> cursor = conn.cursor(as_dict=True)
>>> cursor.execute("SELECT MAX(x) FROM (VALUES (1), (2), (3)) AS foo(x)")
>>> cursor.fetchall()
[{}]

哇偶, MAX(x) 函数发生了什么?!?!
译注: 此处没有给输出表格的列指定字段名
在这种情况下, pymssql 不知道该给字典的 key 使用什么值, 所以它直接忽略了字段.
解决办法就是给字段加上名字

>>> cursor.execute("SELECT MAX(x) AS [MAX(x)] FROM (VALUES (1), (2), (3)) AS foo(x)")
>>> cursor.fetchall()
[{u'MAX(x)': 3}]

这个问题现在已经解决了, 在 https://github.com/pymssql/pymssql/pull/160 中有所体现. 如果你现在还像上面那样做, 就会抛出一个异常

>>> cursor.execute("SELECT MAX(x) FROM (VALUES (1), (2), (3)) AS foo(x)")
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "pymssql.pyx", line 426, in pymssql.Cursor.execute (pymssql.c:5828)raise ColumnsWithoutNamesError(columns_without_names)
pymssql.ColumnsWithoutNamesError: Specified as_dict=True and there are columns with no names: [0]

关于这个问题的例子:

  • Google Group post: pymssql with MAX(values) function does not appear to work

pymssql 不会将 DATE 和 TIME 列反序列化为 datetime.date 和 datetime.time 实例

你或许注意到, pymssql 会将 DATETIME 对象反序列化为 datetime.datetime 对象, 但同时只会把 DATETIME 反序列化简单的字符串, 例如

>>> cursor.execute("""
... CREATE TABLE dates_and_times (
...     datetime DATETIME,
...     date DATE,
...     time TIME,
... )
... """)
>>> cursor.execute("INSERT INTO dates_and_times VALUES (GETDATE(), '20140109', '6:17')")
>>> cursor.execute("SELECT * FROM dates_and_times")
>>> cursor.fetchall()
[{u'date': u'2014-01-09', u'time': u'06:17:00.0000000',u'datetime': datetime.datetime(2014, 1, 9, 12, 41, 59, 403000)}]
>>> cursor.execute("DROP TABLE dates_and_times")

这个问题在于, DATETIME 已经被 FreeTDS 支持很长时间了, 但 DATE and TIME 是 SQL Server 中提供的新数据类型, 并且微软没有将对其的支持添加到 db-lib 之中, FreeTDS 也没有添加支持.
有一些关于将他们的支持添加到 FreeTDS 中的讨论, 但实际行动太磨蹭了: http://lists.ibiblio.org/pipermail/freetds/2013q2/thread.html#28348
因此我们必须等 FreeTDS 支持它, 并且大多数用户都能确保使用非常新的版本的 FreeTDS (除非在上述版本的 freetd 中有 pymssql 链接).

链接:

  • https://github.com/pymssql/pymssql/issues/156
  • Discussion of adding support for DATE and TIME to FreeTDS

共享对象 “libsybdb.so.3” 没找到

在 Linux/*nix 系统中您会遇到一下这种现象

>>> import _mssql
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ImportError: Shared object "libsybdb.so.3" not found

这也许意味着 FreeTDS 不可用了, 或者它的动态链接不能找到它了. 检查它确实已经安装了, 并且保证到文件 libsybdb.so 的路径在 /etc/ld.so.conf 文件中存在. 然后使用管理员权限刷新链接数据库. 在 Solaris 系统上, 我只是在开始使用 Python 之前, 把环境变量 LD_LIBRARY_PATH 设置为该库的路径.

pymssql 2.x 已经给受支持的平台捆绑了 FreeTDS 的 sybdb 库. 这种错误只会在您使用 pymssql 2.x , 同时尝试使用自己的 FreeTDS 进行构建时出现.

DB-Lib error message 20004, severity 9: Read from SQL server failed

在 Linux/*nix 系统中可能会出现下面问题

>>> import _mssql
>>> c=_mssql.connect('hostname:portnumber','user','pass')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
_mssql.DatabaseException: DB-Lib error message 20004, severity 9:
Read from SQL server failed.
DB-Lib error message 20014, severity 9:
Login incorrect.

当下面任何一个行为出现时, 都会发生这种错误

  • freetds.conf 文件找不到
  • freetds.conf 文件中的 tds version 不是 7.0 或 4.2
  • freetds.conf 文件中指定任意字符集
  • 任何不被认可的字符集被传递给了 _mssql.connect()pymssql.connect() 方法

这并不是 "Login incorrect" 这种错误, 真正的 "Login incorrect" 错误代码是 messages has code=18456 and severity=14

这篇关于【Python Document】pymssql 官方文档翻译的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/547829

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

nudepy,一个有趣的 Python 库!

更多资料获取 📚 个人网站:ipengtao.com 大家好,今天为大家分享一个有趣的 Python 库 - nudepy。 Github地址:https://github.com/hhatto/nude.py 在图像处理和计算机视觉应用中,检测图像中的不适当内容(例如裸露图像)是一个重要的任务。nudepy 是一个基于 Python 的库,专门用于检测图像中的不适当内容。该

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip

论文翻译:arxiv-2024 Benchmark Data Contamination of Large Language Models: A Survey

Benchmark Data Contamination of Large Language Models: A Survey https://arxiv.org/abs/2406.04244 大规模语言模型的基准数据污染:一项综述 文章目录 大规模语言模型的基准数据污染:一项综述摘要1 引言 摘要 大规模语言模型(LLMs),如GPT-4、Claude-3和Gemini的快

HTML提交表单给python

python 代码 from flask import Flask, request, render_template, redirect, url_forapp = Flask(__name__)@app.route('/')def form():# 渲染表单页面return render_template('./index.html')@app.route('/submit_form',