python使用odbc连接db2、sqlserver数据库

先介绍安装odbc驱动,如果已安装跳过次环节

一、Linux环境下安装odbc驱动

参考链接:linux环境odbc驱动安装 - 哔哩哔哩

也可参考微软官网(Windows驱动也有介绍):安装 Microsoft ODBC Driver for SQL Server (Linux) - ODBC Driver for SQL Server | Microsoft Learn

ODBC Driver是一种动态链接库 (DLL),支持 ODBC 的应用程序(如 Excel)可以用它来访问 ODBC 数据源。每个 ODBC 驱动程序针对一个数据库管理系统 (DBMS),如 SQL Server、Access 等等。

1. 安装前检查环境gcc/make编译器

[root@dca01 tmp]# rpm -qa | egrep 'gcc|make'

# 如果没有以上工具,可以搭建yum源快速安装

[root@dca01 tmp]# yum -y install gcc make

2.下载ODBC驱动


下载地址:http://ftp.unixodbc.org/

3. 安装ODBC驱动【以unixODBC-2.3.1版本为例】

[root@loaclhost ~]# tar -xvf unixODBC-2.3.1.tar.gz
[root@loaclhost ~]# cd unixODBC-2.3.1/

#--prefix=/test指定安装目录为/test,如果不指定会默认安装到/usr/local,根据需要确定是否指定其他安装目录;如果是arm架构机器,执行 . /configure --prefix=/test --build=arm-linux,高版本unixODBC不区分架构使用./configure --prefix=/test即可

[root@loaclhost unixODBC-2.3.1]# ./configure --prefix=/test

[root@localhost unixODBC-2.3.1]# make

[root@localhost unixODBC-2.3.1]# make install

# 输出odbc driver配置项路径等内容,注意下方截图为2.3.1版本,重点关注 unixODBC 2.3.1所在行下面的内容;如果执行后发现drivers,system data sources等项配置的路径跟实际情况不符合,可以执行export ODBCSYSINI=/test/etc ,重新执行odbcinst -j后如果没有问题,更新至环境变量

[root@localhost unixODBC-2.3.1]# odbcinst -j


4.配置文件编写

USER DATA SOURCES 对应的文件里面内容为空,不需要写配置项

1.odbc.ini

#此处的odbc.ini路径是通过odbcinst -j输出的SYSTEM DATA DOURCES项的路径

vim /usr/local/etc/odbc.ini

#将以下内容根据实际情况填写

[dm8] #driver name 用于isql 测试

Description = DM ODBC DSND

# 这里填的驱动需与 odbcinst.ini 中的节点名称相同

Driver = DM8 ODBC DRIVER

# 达梦数据库的地址,也可以填写具体ip,例127.0.0.1

SERVER = localhost

# 数据库用户名,根据数据库的实际情况填写

UID = SYSDBA

# 数据库密码,根据实际情况填写

PWD = Dameng123

# 达梦数据库端口,根据实际情况填写

TCP_PORT = 5238


2.odbcinst.ini 

#此处的odbc.ini路径是通过odbcinst -j输出的DRIVERS项的路径

vim /usr/local/etc/odbcinst.ini

#将以下内容根据实际情况填写

[DM8 ODBC DRIVER]

Description = ODBC DRIVER FOR DM8

#此处填写的地址是{DM_HOME}/bin/libdodbc.so,按照实际情况填写,{DM_HOME}为达梦数据库安装目录,举个例子:/test/dmdba/dmdbms/bin/libdodbc.so

DRIVER = /test/dmdba/dmdbms/bin/libdodbc.so


5.验证连接

#如果输出结果为下图,表示连接成功

isql dm8 -v

6.配置odbc常见问题&解决方案

    1.报错 “[IM002][unixODBC][Driver Manager]Data source name not found, and no default driver specified [ISQL]ERROR: Could not SQLConnect”

    a.  配置文件odbcinst.ini和odbc.ini路径是否正确,配置项是否正确

    b.  配置文件odbcinst.ini和odbc.ini中每一行的开头不允许有空格

    c.  如果发现odbcinst.ini路径不符合预期,可以通过export ODBCSYSINI=/DCE/rc110/etc/进行变更,注意后面的路径前缀根据实际情况变更

     2. 报错[IM004] [Microsoft][ODBC Driver Manager] Driver's SQLAllocHandle on SQL_HANDLE_ENV

    a.  检查odbcinst.ini文件配置的driver路径是否存在,注意指向的是libdodbc.so的path

     3. 安装unixODBC完成但是执行odbcinst -j 提示command not found

    a.  使用root账户编辑/etc/profile ,将odbcinst所在目录追加到环境变量

    4. 报错"[01000][unixODBC][Driver Manager]Can’t open lib ‘/dm8/dmdba/dmdbms/bin/libdodbc.so’ : file not found [ISQL]ERROR: Could not SQLConnect"

    a.  配置环境变量LD_LIBRARY_PATH

#以root身份编辑
vim /etc/profile
#/dm8/dmdba/dmdbms为达梦数据库安装目录即前面提到的{DM_HOME}
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/dm8/dmdba/dmdbms/bin/"
export PATH=$PATH:/dm8/dmdba/dmdbms/bin
#在对应用户身份下的目录执行
source /etc/profile

    b. 确认libdodbc.so所在路径当前用户有权限,如果没有权限需要切换到root用户修改一下文件夹权限

     #注意此处的路径根据实际安装情况来

chmod 755 {DM_HOME}


     5. symbol lookup error: /home/***/bin/libdodbc.so: undefined symbol : os_mutex2_create

        a. 检查环境变量,一般是LD_LIBRARY_PATH环境变量配置问题;目前遇到这个问题是在非root用户下,发现/etc/profile中设置的环境变量,和 ~/.bashrc中设置有冲突,删除/etc/profile下对应内容,并在~/.bashrc中设置即可

二、编写python代码连接数据库

参考链接:使用ODBC连接db2数据库_zwwangoo的博客-CSDN博客 

import sys
import traceback
import pandas as pd
import pyodbc
from urllib.parse import quote_plus as urlquote
# 数据库信息示例
from sqlalchemy import create_engine



def db_query(sql, dbtype='doris', conp=None):
    """
    执行sql返回DataFrame类型数据
    conp= [user,passwd,host,port, db]

    create_engine 还有很多可选参数,这里介绍几个重要的参数:

    echo :为 True 时候会把sql语句打印出来,当然,你可以通过配置logger来控制输出,这里不做讨论。
    pool_size: 是连接池的大小,默认为5个,0表示连接数无限制
    pool_recycle: MySQL 默认情况下如果一个连接8小时内容没有任何动作(查询请求)就会自动断开链接,出现 MySQL has gone away的错误。设置了 pool_recycle 后 SQLAlchemy 就会在指定时间内回收连接。如果设置为3600 就表示 1小时后该连接会被自动回收。
    pool_pre_ping : 这是1.2新增的参数,如果值为True,那么每次从连接池中拿连接的时候,都会向数据库发送一个类似 select 1 的测试查询语句来判断服务器是否正常运行。当该连接出现 disconnect 的情况时,该连接连同pool中的其它连接都会被回收。
    :param sql:
    :param dbtype:
    :param conp:
    :return:
    """
    con = None
    df = pd.DataFrame()
    err = None
    sql = sql.replace("'null'", 'null')
    if not conp: return None, 0
    try:
        if dbtype == 'postgresql':
            con = create_engine("postgresql://%s:%s@%s:%s/%s" % (
                conp[0], conp[1], conp[2], conp[3], conp[4]), echo=True,
                                pool_pre_ping=True, encoding='utf-8')
            if len(conp) == 5: conp.append('public')
            sql = "set search_path to %s;" % conp[5] + sql
        elif dbtype == 'oracle':
            con = create_engine('oracle://%s:%s@%s:%s/%s' % (
                conp[0], conp[1], conp[2], conp[3], conp[4]), echo=True,
                                pool_pre_ping=True, encoding='utf-8')
        elif dbtype == 'sqlite':
            con = create_engine('sqlite:///%s' % conp)

        elif dbtype == 'doris':
            con = create_engine('mysql+pymysql://%s:%s@%s:%s/%s?charset=utf8' % (
                conp[0], conp[1], conp[2], conp[3], conp[4]), echo=True,
                                pool_pre_ping=True, encoding='utf-8')
        elif dbtype == 'sqlserver':
            params = urlquote((f"DRIVER={{SQL Server}};SERVER={conp[2]};PORT={conp[3]};DATABASE={conp[4]};UID={conp[0]};PWD={conp[1]}"))
            connect_string = (f"mssql+pyodbc:///?odbc_connect={params}")
            con = create_engine(connect_string, echo=True, pool_pre_ping=True, encoding='utf-8')
        elif dbtype == 'db2':
            con = create_engine("db2+ibm_db://%s:%s@%s:%s/%s?charset=utf8" % (conp[0], conp[1], conp[2], conp[3], conp[4]), echo=True, pool_pre_ping=True, encoding='utf-8')

        else:
            con = create_engine('mysql+pymysql://%s:%s@%s:%s/%s?charset=utf8' % (
                conp[0], conp[1], conp[2], conp[3], conp[4]), echo=True, pool_pre_ping=True, encoding='utf-8')

        df = pd.read_sql(sql, con)
        con.dispose()
        return df, 1
    except Exception as e:
        err = traceback.format_exc()
        print(err)
    finally:
        if con is not None: con.dispose()
        if not df.empty and len(df) != 0:
            return df, 1
        else:
            return err, 0

 

你可能感兴趣的:(数据库,sqlserver,db)