目录
(2)vscode 软件 debug 该文件(需放置在根目录下,然后launch.js配置)
一、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”
(二)转移数据后
一定要检查每个字段的值,是否精确对应,避免数据错乱。