Backend - 不同DB数据库抛转数据( python 编写 ETL 工具)

目录

一、ETL的理解

二、环境配置

三、创建ETL项目

(一)settings.py文件

(二)exc_etl.py 文件

(三)excute_sql 文件

四、执行ETL项目

(一)执行项目

1. 执行 exc_etl.py 文件

(1)直接右键(选择终端运行)

(2)vscode 软件 debug 该文件(需放置在根目录下,然后launch.js配置)

 2. 生成执行exe档

(1)下载依赖:pyinstaller

(2)终端命令

(3)执行 exe 程序

(二)转移数据后


一、ETL的理解

        ETL 是指经过数据提取(Extract)、数据转换(Transform)和数据加载(Load)的一种数据集成和处理方法。

二、环境配置

1. 建立虚拟环境:Python 3.10.7

2. 安装依赖:psycopg2==2.9.9 (在虚拟环境中执行安装)

三、创建ETL项目

作用:

        实现不同数据库,抛转数据。

        即,实现从“源数据库”提取数据、整理想要的数据、将数据加载到“目的数据库”中。

包括的功能:

        抛转数据(搬移 A 数据库的数据到 B 数据库,即实现 ETL 效果);

        同时操作多个数据库。

连接数据库,可参考另一篇文章:Backend - python 连接 & 操作 PostgreSQL DB(数据库)-CSDN博客

(一)settings.py文件

# 设定数据库
DATABASES = {
    'default': {  # 默认数据库
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'PORT': '5432',
        'NAME': 'Book',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': 'XX.XXX.XX.XX',
    },
    'fromDB': {  # 来源数据库
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'PORT': '5432',
        'NAME': 'FrBook',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': 'XX.XXX.XX.XX4',
    },
    'toDB': { # 目标数据库
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'PORT': '5432',
        'NAME': 'ToBook',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': 'XX.XXX.XX.XX',
    },
}

(二)exc_etl.py 文件

from myApp.views.tools.excute_sql import ExcuteDB
from myProject.settings import DATABASES

def get_data():  # 在来源数据库中查询数据
    return 'select card from "myApp_book" limit 10'

def to_data():  # 新增数据至目的数据库
    return 'INSERT INTO auth_group (name) VALUES %s '

def edit_data():  # 在目的数据库中更新已有数据
    upd_sql = 'name=fr_book.name, btype=fr_book.btype ' # 两个表的字段匹配
    upd_col = 'name, btype' # 更新的字段
    return 'UPDATE "tb_book" SET {} FROM (VALUES %s) AS fr_book ({}) WHERE tb_book.bookid = fr_book.bookid;'.format(upd_sql, upd_col)

def handle_data(from_db, to_db):  # 处理数据
    try:
        get_sql = get_data()
        res_list = from_db.exc_query(get_sql)
        if res_list:
            to_db.exc_bulk_edit([{'sql': to_data(), 'args_list': res_list}] )
    except Exception as e:
        print(str(e) )

if __name__ == '__main__':  # 主程序
    try:
        # 设定来源DB
        from_dbname = DATABASES['fromDB']['NAME']
        from_user = DATABASES['fromDB']['USER']
        from_password = DATABASES['fromDB']['PASSWORD']
        from_port = DATABASES['fromDB']['PORT']
        from_host = DATABASES['fromDB']['HOST']
        from_db = ExcuteDB(from_host, from_dbname, from_user, from_port, from_password)        
        # 设定目的DB
        to_dbname = DATABASES['toDB']['NAME']
        to_user = DATABASES['toDB']['USER']
        to_password = DATABASES['toDB']['PASSWORD']
        to_port = DATABASES['toDB']['PORT']
        to_host = DATABASES['toDB']['HOST']
        to_db = ExcuteDB(to_host, to_dbname, to_user, to_port, to_password)
        
	   # 处理数据
        handle_data(from_db, to_db)
    except Exception as e:
        print(str(e) )

(三)excute_sql 文件

放置位置:myApp.views.tools 中

import psycopg2
from psycopg2.extras import execute_values
class ExcuteDB:
	# ————————————————————————————————————————————— 连接数据库
    def __init__(self, host, dbname, user, port, password):
        self.host = host
        self.dbname = dbname
        self.user = user
        self.port = port
        self.password = password
          # self.conn = self.__postgres  # 连接数据库(放在各种功能方法中,比如exc_query方法)
  
    @property
    def __postgres(self):
        conn = psycopg2.connect(host=self.host,  # 主机地址
                                dbname=self.dbname,  # 数据库名称
                                user=self.user,  # 用户名
                                password=self.password,  # 密码
                                port=self.port)  # 端口号
        return conn
	# ————————————————————————————————————————————— 查询
    def exc_query(self, sql):
        try:
            conn = self.__postgres  # 连接数据库
            cur = conn.cursor()  # 创建游标对象
            cur.execute(sql)  # 执行SQL语句
            res_list = None
            res_list = cur.fetchall()  # 获取记录值,结果是列表包元组:[('1F002', '数据结构怎么学'), ('1F001', '数据库原理')]
            cols_list = [row[0] for row in cur.description]  # 获取栏位名称['card', 'name']
            # data_list的第一种组成方法
            # 1. 结合map、lambda函数
            # 2. 必须先用一个变量存储cur.fetchall(),再执行下面的for循环
            data_list = [dict(map(lambda key, value: [key, value], cols_list, val_list)) for val_list in res_list]  # 组装列表包字典:data_list [{'card': '1F002', 'name': '数据结构怎么学'}, {'card': '1F001', 'name': '数据库原理'}]
            # data_list的另一种组成方法
            # 1. 结合zip函数
            # 2. 可以直接在for循环中使用
            # data_list = [dict(zip(cols_list, val_list)) for val_list in cur.fetchall()]
        except Exception as e:
            print(str(e))
        finally:
            cur.close()  # 关闭游标
            conn.close()  # 关闭数据库连接
		       return {'栏位名+栏位值': data_list, '只有栏位值': res_list}
	# ————————————————————————————————————————————— 单笔更新/插入
	def exc_edit(self, sql):
		        try:
		            conn = self.__postgres  # 连接数据库
		            cur = conn.cursor()  # 创建游标对象
		            cur.execute(sql)  # 执行SQL语句
		            conn.commit()  # 提交事务
		        except Exception as e:
		            conn.rollback()  # 回滚commit事务
		            print(str(e))
		        finally:
		            cur.close()  # 关闭游标
		            conn.close()  # 关闭数据库连接
	# ————————————————————————————————————————————— 批量更新/插入
    def exc_bulk_edit(self, sql_list):
        try:
            conn = self.__postgres  # 连接数据库
            cur = conn.cursor()  # 创建游标对象
            for l in sql_list:  # 循环不同的sql
                sql = l['sql']  # sql语句:'insert into auth_group (card, name, author, btype, price, num) values %s '
                args_list = l['args_list']  # 批量插入的值:[('2F0001', '高等数学', '小星星', '教育', 35, 10), ('2F0002', '线性代数', '小星星', '教育', 40, 12)]
                execute_values(cur, sql, args_list)  # 批量执行
            conn.commit()  # 提交事务
        except Exception as e:
            conn.rollback()  # 回滚commit事务
            print(str(e))
        finally:
            cur.close()  # 关闭游标
            conn.close()  # 关闭数据库连接

四、执行ETL项目

(一)执行项目

1. 执行 exc_etl.py 文件

(1)直接右键(选择终端运行)
(2)vscode 软件 debug 该文件(需放置在根目录下,然后launch.js配置)
{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "myApp",
            "type": "python",
            "request": "launch",
            // "program": "${workspaceFolder}\\manage.py",
            "program": "${workspaceFolder}\\exc_etl.py", // ETL抛转数据执行档
            "args": [
                "runserver",
                "127.0.0.1:8080"
            ],
            "django": true,
            "justMyCode": true
        },
    ]
}

 2. 生成执行exe档

(1)下载依赖:pyinstaller

pyinstaller 的用法,可参考另一篇文章:Backend - pyinstaller 打包 py 文件-CSDN博客

(2)终端命令
pyinstaller -F .\执行档名称.py
(3)执行 exe 程序

执行命令后,会生成 dist 文件夹,双击其中的“执行档名称.exe”

(二)转移数据后

一定要检查每个字段的值,是否精确对应,避免数据错乱。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值