首先就是要安装包,直接使用pip命令安装即可.
pip install pymssql
参考下图,描述了数据库连接在单次访问中的创建与关闭。 值得注意的是
当脚本类型是DML(增、删、改)时,是没有返回集、无法执行fetchall()操作、直接commit()。关闭连接时,数据库连接和游标会被同时关闭(因为游标是基于连接对象创建)A connection can have only one cursor with an active query at any time
简单来讲,一个连接实例,只能完成一次脚本执行。 通过如下示例,来分析只创建一次连接、同时创建多个游标时,会得到什么样的返回结果。
######## 场景1 ######## conn=pymssql.connect('localhost', 'test', 'test', 'AdventureWorksDW2017') cur1=conn.cursor(as_dict=True) cur1.execute('select top 3 * from DimDate where DateKey=%s', '20050101') cur2=conn.cursor(as_dict=True) cur2.execute('select top 3 * from DimDate where DateKey=%s', '20050102') # 同一个连接、不同游标连续提交查询 后,以最后一个游标结果为准,后者会覆盖前者 res_test=cur1.fetchall() res_test2=cur2.fetchall() print('场景1:同一个连接,连续执行,最后获取结果集。游标1:\n',res_test) print('场景1:同一个连接,连续执行,最后获取结果集。游标2:\n',res_test2) conn.close() ''' 场景1:同一个连接,连续执行,最后获取结果集。游标1: [{'DateKey': 20050102, 'FullDateAlternateKey': '2005-01-02', 'DayNumberOfWeek': 1, 'EnglishDayNameOfWeek': 'Sunday', 'SpanishDayNameOfWeek': 'Domingo', 'FrenchDayNameOfWeek': 'Dimanche', 'DayNumberOfMonth': 2, 'DayNumberOfYear': 2, 'WeekNumberOfYear': 2, 'EnglishMonthName': 'January', 'SpanishMonthName': 'Enero', 'FrenchMonthName': 'Janvier', 'MonthNumberOfYear': 1, 'CalendarQuarter': 1, 'CalendarYear': 2005, 'CalendarSemester': 1, 'FiscalQuarter': 3, 'FiscalYear': 2005, 'FiscalSemester': 2}] 场景1:同一个连接,连续执行,最后获取结果集。游标2: [] ''' 返回结果分析会发现结果令人费解、surprising。cur1返回的居然是cur2的查询结果(20050102),而不是(20050101).
导致原因This happens because the underlying TDS protocol does not have client side cursors. The protocol requires that the client flush the results from the first query before it can begin another query
解决办法-walkarounds1、按照第3部分的代码,每次访问都新创建连接对象。 2、同一个连接,每个游标的返回结果都立即留存。参考下边示例。
######## 解决办法 ######## conn=pymssql.connect('localhost', 'test', 'test', 'AdventureWorksDW2017') cur1=conn.cursor(as_dict=True) cur1.execute('select top 3 * from DimDate where DateKey=%s', '20050101') # 在这里,先存储第一个游标的结果 res_test=cur1.fetchall() cur2=conn.cursor(as_dict=True) cur2.execute('select top 3 * from DimDate where DateKey=%s', '20050102') # 再获取第二个游标的结果 res_test2=cur2.fetchall() print('场景2:同一个连接,逐次获得游标的结果集。游标1:\n',res_test) print('场景2:同一个连接,逐次获得游标的结果集。游标2:\n',res_test2) conn.close() ''' 场景2:同一个连接,逐次获得游标的结果集。游标1: [{'DateKey': 20050101, 'FullDateAlternateKey': '2005-01-01', 'DayNumberOfWeek': 7, 'EnglishDayNameOfWeek': 'Saturday', 'SpanishDayNameOfWeek': 'Sábado', 'FrenchDayNameOfWeek': 'Samedi', 'DayNumberOfMonth': 1, 'DayNumberOfYear': 1, 'WeekNumberOfYear': 1, 'EnglishMonthName': 'January', 'SpanishMonthName': 'Enero', 'FrenchMonthName': 'Janvier', 'MonthNumberOfYear': 1, 'CalendarQuarter': 1, 'CalendarYear': 2005, 'CalendarSemester': 1, 'FiscalQuarter': 3, 'FiscalYear': 2005, 'FiscalSemester': 2}] 场景2:同一个连接,逐次获得游标的结果集。游标2: [{'DateKey': 20050102, 'FullDateAlternateKey': '2005-01-02', 'DayNumberOfWeek': 1, 'EnglishDayNameOfWeek': 'Sunday', 'SpanishDayNameOfWeek': 'Domingo', 'FrenchDayNameOfWeek': 'Dimanche', 'DayNumberOfMonth': 2, 'DayNumberOfYear': 2, 'WeekNumberOfYear': 2, 'EnglishMonthName': 'January', 'SpanishMonthName': 'Enero', 'FrenchMonthName': 'Janvier', 'MonthNumberOfYear': 1, 'CalendarQuarter': 1, 'CalendarYear': 2005, 'CalendarSemester': 1, 'FiscalQuarter': 3, 'FiscalYear': 2005, 'FiscalSemester': 2}] '''游标结果默认返回的数据格式为:值为元组的列表对象。每个元组内部表示每行各列的数据,所有元素表示所有行。例如:[(2, ‘a’), (3, ‘b’)]。如果要修改为以字典格式返回,可在定义游标对象时,显示指定属性as_dict。
cur=conn.cursor(as_dict=True) 通过配置参数设定过滤条件 在execute()中,可以设定参数,来获取指定条件的数据。 res_test=cur.execute('select top 3 * from DimDate where DateKey=%s', '20050101') partition函数来获取SQL脚本中的数据表名 在这里的样例中,SQL脚本比较简单,可以利用partition来切分到表名。但是当应对比较复杂的多重子查询时,会得到错误的表名,最终导致表头与数据集不匹配,返回值异常。