ETL基础认知

2023-11-09

1-ETL基础认知(了解)

问题1: 如何将零散的数据,集中输入到数据仓库???

ETL

E: 数据抽取-- 抽取的是其他数据源中的数据

T: 数据转换-- 将数据转换为统一的格式,消除异常值,缺失值,对于错误的逻辑进行修改

L: 数据加载-- 将不同数据源的数据处理后加载到数仓或者输出到指定位置

问题2: ETL主要解决了数据分析中的什么???

数据孤岛问题

问题3: 什么是数据仓库???

存储数据的仓库,其实我们这里说的数据仓库就是存储ETL转换完成数据的数据平台.

在开发中我们有很多种资源但是一般提到节省系统资源,浪费资源 说的是内存, cpu 和 带宽

2-常见的数据存储形式(能够分辨常见的数据形式即可)

结构化数据: 每一个数据都可以使用行索引和列索引标记,同时使用行和列索引可以标记一个唯一的值

  • 数据库中的表
  • Excel
  • CSV数据格式
  • TSV数据格式(其实就是CSV格式的数据,但是分隔符用的是制表位\t)

**半结构化数据:**数据中的一部分数据是结构化数据,或者可以转换为结构化数据

  • JSON数据格式
  • XML数据格式

注意: JSON数据和XML数据在任何情况下,都可以互相转换. 半结构化数据,通常会转换为结构化数据后,再做分析.

非结构化数据:

  • markdown文本
  • word文档
  • mp3
  • avi、mp4

注意: 非结构化数据,一般我们不做分析,可以提取其中的一部分,或者其中的规律,保存为结构化数据后再做分析.

3-Kettle的使用(了解)

ETL工具很多我们知道有这么个东西就行了

4-ETL实战案例需求分析(重点理解)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lGWATkxu-1688340889073)(day01-知识复习.assets/1.png)]

问题1: 这是一个什么行业的业务数据?

零售行业的数据

问题2: 这个案例中有哪几种数据源? 所以采集需求有3个

  • 订单数据-JSON
  • 商品库数据-MySQL
  • 后台日志数据-后台服务log日志文件

问题3: 这个案例中有哪几种数据去向?

  • 数据仓库: 此处使用mysql数据库模拟数据仓库,在真实开发场景下,不会使用该服务作为数仓(数据吞吐量不足)

    当下一个阶段Hadoop+Hive学习完成后,我们会搭建一个真实的数据仓库

  • CSV文件备份: 数据内容和数据仓库完全一致,主要为了做数据备份,恢复数据时使用.(真实业务开发中可能使用各种格式存储)

订单业务逻辑

核心思想: 获取全部的JSON数据文件,与数据库中存储的已采集数据文件进行对比,得到未采集的数据文件进行操作

功能:实现订单数据采集的程序
思路:
① 获取订单文件夹下面有哪些订单JSON文件
② 查询元数据库表中已经被采集的订单JSON文件,来对比确定要采集新的订单JSON文件
③ 针对待采集的新订单JSON文件,进行数据采集(ETL操作->mysql->csv)
④ 将本次采集的订单JSON文件,记录到元数据库的表中

商品业务逻辑

核心思想: 采集数据并记录采集的位置(id,行号,索引…),下一次采集先获取上一次采集的位置,然后继续操作

功能:数据源库中商品数据采集的主程序
思路:
① 查询元数据库表,获取上一次采集商品数据中 updateAt 的最大值
② 根据上一次采集商品数据中 updateAt 的最大值,查询数据源库商品表,获取继上一次采集之后,新增和更新的商品数据
③ 针对新增和更新的商品数据,进行数据采集(ETL->mysql->csv)
④ 将本次采集商品数据中的 updateAt 的最大值,保存到元数据库表中

日志业务逻辑

核心思想: 获取全部的日志数据文件,与数据库中存储的已采集数据文件进行对比,得到未采集的数据文件进行操作

功能:实现后台访问日志数据采集的程序
思路:
① 获取后台访问日志文件夹下面有哪些日志文件
② 查询元数据库表中已经被采集的日志文件,来对比确定要采集新的访问日志文件
③ 针对待采集的新访问日志文件,进行数据采集(ETL操作->mysql->csv)
④ 将本次采集的访问日志文件,记录到元数据库的表中

总结:所有的需求都要做到采集过的数据不重复采集

5-项目结构搭建(操作)

(project name)工程名称: python_etl

工程名称可以随意定义,但是要符合标识符的命名规则:

  • 不能使用关键字
  • 只能使用字母数字和下划线
  • 不能以数字开头
  • 严格区分大小写

标识符: 程序员自己定义的,具有特殊功能或含义的字符组合

关键字: 系统或者解释器定义的,具有特殊功能或者含义的字符组合

5个目录:

  • config:保存整个ETL工程的配置信息
  • model:保存项目的数据模型文件
  • test:保存单元测试的代码文件
  • util:保存项目的工具文件
  • learn:保存项目开发过程中的一些基础知识讲解练习文件(实际不需要)

问题1: 什么时候创建package 什么时候创建directory???

如果你当前目录中的文件可能被其他文件引用就是用package

如果你当前文件目录中的文件不会被任何文件引用就使用directory 例如: logs learn

注意:目录命名时,如果该目录时package,则文件名称必须为标识符, 如果是directory那么只需要没有中文即可.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GgdaRF6L-1688340889074)(day01-知识复习.assets/2.png)]

6-前置知识学习
6.1 日志模块(理解)

import logging

核心理解:

  1. 导入模块 (自己的文件名不要和内置模块名称重名,否则内置模块无法使用)
  2. 日志管理对象: 负责日志的收集工作 - 相当于执法记录仪
  3. 日志处理器: 负责日志的输出形式管理(终端/文件) - 相当于将记录仪连接的打印机
  4. 日志格式: 负责日志的输出格式管理 - 相当于打印机中的墨盒

日志格式:

'%(asctime)s - [%(levelname)s] - %(filename)s[%(lineno)d]:%(message)s'

logging日志模块的基本使用

"""
logging模块: 主要是为了记录程序运行期间产生的日志信息

日志器对象的创建和配置
1. 日志器对象的创建
2. 日志处理器的创建
3. 将日志处理器绑定到日志器对象上

日志的输出
1. 设置日志输出级别
2. 输出不同级别的日志信息
"""
# 0.导入模块
import logging

####################### 日志器对象的创建和配置  #####################
# 1. 日志器对象的创建
logger = logging.getLogger()
# 2. 日志处理器的创建
stream_handler = logging.StreamHandler()
# 3. 将日志处理器绑定到日志器对象上
logger.addHandler(stream_handler)

############################ 日志的输出  #######################
# 1. 设置日志输出级别 (默认warning及warning级别以上的日志信息会被输出)
# 忘记日志自己别的数据值,因为如果使用10 20 30 就会做不到见名知意,降低代码的可读性
logger.setLevel(logging.INFO)

# 2. 输出不同级别的日志信息
"""
日志级别 5个:
debug: 代码调试时输出的日志信息
info: 代码正常运行过程中输出的日志信息
warning: 代码的运行结果可能和预期结果发生偏差时输出的日志信息
error: 代码出现异常时输出的日志信息
critical: 一般我们遇不到,遇到了解决不了的问题 例如: 磁盘或者内存空间已满等.
"""
logger.debug('这是一个debug级别的日志信息')
logger.info('这是一个info级别的日志信息')
logger.warning('这是一个warning级别的日志信息')
logger.error('这是一个error级别的日志信息')
logger.critical('这是一个critical级别的日志信息')

logging日志模块设置日志输出格式

"""
日志器对象的创建和配置
1. 日志器对象的创建
2. 日志处理器的创建
3. 将日志处理器绑定到日志器对象上
4. 创建一个格式对象
5. 将日志格式对象绑定到日志处理器上

日志的输出
1. 设置日志输出级别
2. 输出不同级别的日志信息
"""
# 导包
import logging

##################### 日志器对象的创建和配置 #####################
# 1. 日志器对象的创建
logger = logging.getLogger()

# 2. 日志处理器的创建
stream_handler = logging.StreamHandler()

# 3. 将日志处理器绑定到日志器对象上
logger.addHandler(stream_handler)

# TODO: 4. 创建一个格式对象
fmt = logging.Formatter('%(asctime)s - [%(levelname)s] - %(filename)s[%(lineno)d]:%(message)s')
# TODO: 5. 将日志格式对象绑定到日志处理器上
stream_handler.setFormatter(fmt)

########################## 日志的输出 ##########################
# 1. 设置日志输出级别
logger.setLevel(logging.INFO)
# 2. 输出不同级别的日志信息
logger.debug('这是一个debug级别的日志信息')
logger.info('这是一个info级别的日志信息')
logger.warning('这是一个warning级别的日志信息')
logger.error('这是一个error级别的日志信息')
logger.critical('这是一个critical级别的日志信息')

logging模块将日志输出到文件中

本质就是更换日志处理器类型

StreamHandler: 将日志信息输出到终端上

FileHandler: 将日志信息输出到文件中

"""
日志器对象的创建和配置
1. 日志器对象的创建
2. 创建换一个文件类型的日志处理器
3. 将日志处理器绑定到日志器对象上
4. 创建一个格式对象
5. 将日志格式对象绑定到日志处理器上

日志的输出
1. 设置日志输出级别
2. 输出不同级别的日志信息


常用的日志处理器有两种
StreamHandler: 流式日志处理器,将日志信息输出到终端中
FileHandler: 文件日志处理器,将日志信息输出到文件中
"""
# 导入logging模块
import logging

#################### 日志器对象的创建和配置 ####################
# 1. 日志器对象的创建
logger = logging.getLogger()

# TODO: 2. 创建换一个文件类型的日志处理器
# 注意: filename要传入一个log文件的路径,可以使用绝对路径也可以使用相对路径,但是文件目录一定要存在,文件可以不存在
# 举例: ../logs/test.log 路径中 logs目录必须存在, test.log可以不存在
file_handler = logging.FileHandler(
    filename='../logs/test.log',
    mode='a',
    encoding='utf8'
)
# 3. 将日志处理器绑定到日志器对象上
logger.addHandler(file_handler)
# 4. 创建一个格式对象
fmt = logging.Formatter('%(asctime)s - [%(levelname)s] - %(filename)s[%(lineno)d]:%(message)s')
# 5. 将日志格式对象绑定到日志处理器上
file_handler.setFormatter(fmt)


######################### 日志的输出 #######################
# 1. 设置日志输出级别
logger.setLevel(logging.INFO)
# 2. 输出不同级别的日志信息
logger.debug('这是一个debug级别的日志信息')
logger.info('这是一个info级别的日志信息')
logger.warning('这是一个warning级别的日志信息')
logger.error('这是一个error级别的日志信息')
logger.critical('这是一个critical级别的日志信息')
6.2 time模块(理解)

理解大于记忆

time模块的基本使用:

  • time.sleep(数字):程序休眠几秒钟
  • time.time():获取当前时间的时间戳(以秒为单位)
  • time.time_ns():获取当前时间的时间戳(以纳秒为单位)
  • time.localtime():获取当前的本地时间,结果是一个 struct_time 类的对象
  • time.localtime(时间戳-秒):返回时间戳对应的本地时间,结果是一个 struct_time 类的对象
  • time.mktime(struct_time对象):返回时间对应的时间戳(秒为单位)
  • time.strftime(格式化字符串, 日期):将日期数据(struct_time对象)格式化一个字符串
  • time.strptime(日期字符串,格式化字符串):将日期字符串转换为一个日期数据(struct_time对象)
%Y:4位数字的年份
%m:2位数字的月份
%d:2位数字的日期
%H:24小时制的小时
%M:2位数字的分钟
%S:2位数字的秒
"""
**time模块的基本使用:**

- time.sleep(数字):程序休眠几秒钟
- time.time():获取当前时间的时间戳(以秒为单位)
- time.time_ns():获取当前时间的时间戳(以纳秒为单位)
- time.localtime():获取当前的本地时间,结果是一个 struct_time 类的对象
- time.localtime(时间戳-秒):返回时间戳对应的本地时间,结果是一个 struct_time 类的对象
- time.mktime(struct_time对象):返回时间对应的时间戳(秒为单位)
- time.strftime(格式化字符串, 日期):将日期数据(struct_time对象)格式化一个字符串
- time.strptime(日期字符串,格式化字符串):将日期字符串转换为一个日期数据(struct_time对象)
"""
# 导入模块
import time

# time.sleep(数字):程序休眠几秒钟
print('hello')
time.sleep(1)
print('world')

# time.time():获取当前时间的时间戳(以秒为单位)
date_float1 = time.time()
print(date_float1) # 1672285269.896592

# time.time_ns():获取当前时间的时间戳(以纳秒为单位)
date_float2 = time.time_ns()
print(date_float2) # 1672285402027404100

# time.localtime():获取当前的本地时间,结果是一个 struct_time 类的对象
# time.struct_time(tm_year=2022, tm_mon=12, tm_mday=29, tm_hour=11, tm_min=44, tm_sec=52, tm_wday=3, tm_yday=363, tm_isdst=0)
date1 = time.localtime()
print(date1)
print(date1.tm_year)
print(date1.tm_mon)
...

# time.localtime(时间戳-秒):返回时间戳对应的本地时间,结果是一个 struct_time 类的对象
# 将一个数值型的时间戳,转换为struct_time时间类型
date2 = time.localtime(1672285269.896592)
print(date2)

# time.mktime(struct_time对象):返回时间对应的时间戳(秒为单位)
# 将一个时间从struct_time时间类型转换为数值型的时间戳
date_float3 = time.mktime(date2)
print(date_float3) # 这种方式的转换有时间损失,以秒为单位进行了四舍五入

# time.strftime(格式化字符串, 日期):将日期数据(struct_time对象)格式化一个字符串
# 将时间类型的数据按照一定的格式转换为字符串类型的数据
"""
%Y:4位数字的年份
%m:2位数字的月份
%d:2位数字的日期
%H:24小时制的小时
%M:2位数字的分钟
%S:2位数字的秒
"""
date_str1 = time.strftime('%Y年%m月%d日 %H时%M分%S秒', date2)
print(date_str1)

# time.strptime(日期字符串,格式化字符串):将日期字符串转换为一个日期数据(struct_time对象)
# 将字符串类型的时间数据,转换为struct_time类型数据
# 重点: 时间字符串和时间格式要完全统一,否则无法正常转换
date3 = time.strptime('2022年11月11日 08时02分24秒', '%Y年%m月%d日 %H时%M分%S秒')
print(date3)
6.3 unittest模块(掌握)

问题1:什么叫单元测试?

对于软件中最小的可测试单元进行检测或检查的方式就是单元测试

问题2: 单元测试在企业开发中一般是谁来写??

如果企业中测试工程师能力极强,可以由他来写,但是通常由开发人员来写,测试人员点击运行查看结果即可.

from unittest import TestCase

class 自定义单元测试类(TestCase):
    def setUp(self) -> None:
        """该方法会在每个单元测试方法执行之前自动执行一次,可以做一些单元测试前的初始工作"""
        pass

    # 注意:所有的单元测试方法名必须以 test 开头,否则不能被 unittest 识别
    def test_单元测试方法1(self):
        pass

    def test_单元测试方法2(self):
        pass

    ...

运行单元测试代码,出现如下情况的原因是你的文件名称不符合标识符的命名规则

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XJ59T3Bi-1688340889075)(day01-知识复习.assets/1672287171197.png)]

unittest模块的使用

"""
unittest模块主要是用于做单元测试

1. 创建一个测试类
2. 书写setup方法 在测试方法执行前执行
3. 书写tearDown方法,在测试方法执行后执行
4. 书写测试方法
"""
# 导入unittest模块
from unittest import TestCase

class TestDemo(TestCase):

    def setUp(self) -> None:
        """在测试方法执行前执行"""
        print('setUp方法被执行...')

    def tearDown(self) -> None:
        """在测试方法执行后执行"""
        print('tearDown方法被执行...')

    # 所有的测试方法,必须以test开头,否则无法进行单元测试
    def test_func1(self):
        print('测试方法1被执行....')

    def test_func2(self):
        print('测试方法2被执行....')

注意事项:

  1. 测试文件名称要遵守标识符的命名规则,无论是否被调用
  2. 测试类,必须继承自TestCase
  3. 测试方法必须方法名以test_开头,否则无法识别
  4. -> None提示该方法没有返回值,但是是一个软性限制**(如果不遵循则报警告不会崩溃**)
6.4 OS模块(重要)

os模块的使用:

  • os.getcwd():获取当前程序的运行工作路径
  • os.listdir(目录):获取指定目录下的内容,返回一个list

os.path模块的使用:

  • os.path.abspath(路径):返回指定路径的绝对路径
  • os.path.dirname(路径):返回指定路径的上一级路径
  • os.path.basename(路径):返回指定路径的最后一部分
  • os.path.join(路径1, 路径2):将两个路径进行拼接
  • os.path.isfile(路径):判断指定路径是不是一个文件,是返回True,否则返回False
  • os.path.isdir(路径):判断指定路径是不是一个文件夹,是返回True,否则返回False
"""
os模块的使用:
- os.getcwd():获取当前程序的运行工作路径
- os.listdir(目录):获取指定目录下的内容,返回一个list

os.path模块的使用:

- os.path.abspath(路径):返回指定路径的绝对路径
- os.path.dirname(路径):返回指定路径的上一级路径
- os.path.basename(路径):返回指定路径的最后一部分
- os.path.join(路径1, 路径2):将两个路径进行拼接
- os.path.isfile(路径):判断指定路径是不是一个文件,是返回True,否则返回False
- os.path.isdir(路径):判断指定路径是不是一个文件夹,是返回True,否则返回False
"""
# __file__ 系统内置变量,用来表示当前文件所在位置的绝对路径
print(__file__)

# 导入os 模块
import os

# os.getcwd():获取当前程序的运行工作路径 : 当前文件所在的目录的绝对路径
print(os.getcwd())

# os.listdir(目录):获取指定目录下的内容,返回一个list
# 如果括号内什么也不写,获取的就是当前文件所在目录中所有文件的名称
print(os.listdir())
# 如果在括号内填写目录的路径,则获取的就是指定目录中的文件名称列表
# 注意我们使用的目录层级符号,如果是\要注意转译或者改为/
print(os.listdir('C:\\Users\\admin\\Desktop\\深圳36期-ETL阶段'))
print(os.listdir('C:/Users/admin/Desktop/深圳36期-ETL阶段'))

# os.path.abspath(路径):返回指定路径的绝对路径
print(os.path.abspath('../'))

# os.path.dirname(路径):返回指定路径的上一级路径
# 返回当前路径文件所在目录的路径
print(os.path.dirname(__file__))
# print(os.path.dirname('../')) # 如果给他的是相对路径,那么他返回的也是相对路径,一般获取dirname不适用相对路径
print(os.path.dirname(os.path.abspath('../'))) # 使用的时候转换为绝对路径

# os.path.basename(路径):返回指定路径的最后一部分
# 返回当前路径的文件名称
print(os.path.basename(__file__))
# print(os.path.basename('../')) # 在开发中basename也会使用绝对路径
print(os.path.basename('C:/Users/admin/Desktop/深圳36期-ETL阶段/python_etl'))

# os.path.join(路径1, 路径2):将两个路径进行拼接
# 一般为了防止出现拼接错误,我们会在路径1的末尾添加/,在路径2的开头删除斜杠
print(os.path.join('C:/Users/admin/Desktop/深圳36期-ETL阶段/', 'python_etl/learn(实际开发中不需要)'))

# os.path.isfile(路径):判断指定路径是不是一个文件,是返回True,否则返回False
print(os.path.isfile(__file__))
# os.path.isdir(路径):判断指定路径是不是一个文件夹,是返回True,否则返回False
print(os.path.isdir(__file__))

6.5 pymysql模块(重要)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WSpUdQtp-1688340889075)(day01-知识复习.assets/image-20181006231547917.png)]

操作步骤:

  1. 导入模块
  2. 创建连接
  3. 创建游标
  4. 执行sql/获取查询集
  5. 关闭游标
  6. 关闭连接

分类:

  1. 建表建库语句
  • 直接使用execute进行执行,不需要commit提交
  1. 非查询语句(增删改)
  • 直接使用excute进行执行,需要使用commit提交
  1. 查询语句
  • 直接使用excute进行执行,需要使用cursor.fetchall/fetchone/fetchmany进行结果集查询

数据库和数据表的创建

"""
操作步骤:

1. 导入模块
2. 创建连接
3. 创建游标
4. 执行sql/获取查询集
5. 关闭游标
6. 关闭连接
"""
############################ 数据库的创建 ########################
# # 1. 导入模块
# import pymysql
# # 2. 创建连接
# conn = pymysql.connect(
#     host='127.0.0.1',
#     port=3306,
#     user='root',
#     password='123456',
#     charset='utf8'
# )
# # 3. 创建游标
# cursor = conn.cursor()
# # 4. 执行sql/获取查询集
# sql = 'create database python charset="utf8";'
# row_num = cursor.execute(sql)
# if row_num > 0:
#     print('数据库创建成功...')
#
# # 5. 关闭游标
# cursor.close()
# # 6. 关闭连接
# conn.close()

############################ 数据表的创建 ########################
# 1. 导入模块
import pymysql
# 2. 创建连接
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    charset='utf8',
    database='python'
)
# 3. 创建游标
cursor = conn.cursor()
# 4. 执行sql/获取查询集
sql = 'create table person(id int, name varchar(100));'
row_num = cursor.execute(sql)
if row_num > 0:
    print('数据表创建成功...')
# 5. 关闭游标
cursor.close()
# 6. 关闭连接
conn.close()

数据记录的增删改操作

"""
操作步骤:

1. 导入模块
2. 创建连接
3. 创建游标
4. 执行sql/获取查询集
    在增删改数据时,要注意数据提交
5. 关闭游标
6. 关闭连接
"""
###################### 增 ####################
# 1. 导入模块
import pymysql

# 2. 创建连接
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    charset='utf8',
    database='python'
)
# 3. 创建游标
cursor = conn.cursor()
# 4. 执行sql/获取查询集
sql = 'insert into person values(1, "小明"),(2,"小芳");'
# 执行sql语句
row_num = cursor.execute(sql)
if row_num > 0:
    print('数据记录插入成功....')

# 只要是事务型操作(增删改),就必须提交后才能生效(sql数据的执行都是在内存中的,只有commit之后才能落盘)
conn.commit()

# 5. 关闭游标
cursor.close()
# 6. 关闭连接
conn.close()

###################### 删 ####################
# 1. 导入模块
import pymysql

# 2. 创建连接
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    charset='utf8',
    database='python'
)
# 3. 创建游标
cursor = conn.cursor()
# 4. 执行sql/获取查询集
sql = 'delete from person where id=1;'
# 执行sql语句
row_num = cursor.execute(sql)
if row_num > 0:
    print('数据记录删除成功....')

# 只要是事务型操作(增删改),就必须提交后才能生效(sql数据的执行都是在内存中的,只有commit之后才能落盘)
conn.commit()

# 5. 关闭游标
cursor.close()
# 6. 关闭连接
conn.close()


###################### 该 ####################
# 1. 导入模块
import pymysql

# 2. 创建连接
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    charset='utf8',
    database='python'
)
# 3. 创建游标
cursor = conn.cursor()
# 4. 执行sql/获取查询集
sql = 'update person set name="小华" where id = 2;'
# 执行sql语句
row_num = cursor.execute(sql)
if row_num > 0:
    print('数据记录修改成功....')

# 只要是事务型操作(增删改),就必须提交后才能生效(sql数据的执行都是在内存中的,只有commit之后才能落盘)
conn.commit()

# 5. 关闭游标
cursor.close()

# 6. 关闭连接
conn.close()

数据记录的查询操作

"""
操作步骤:

1. 导入模块
2. 创建连接
3. 创建游标
4. 执行sql/获取查询集
    查询操作不需要数据提交,但是要进行结果集的处理
5. 关闭游标
6. 关闭连接
"""

# 1. 导入模块
import pymysql

# 2. 创建连接
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    charset='utf8',
    database='python'
)

# 3. 创建游标
cursor = conn.cursor()

# 4. 执行sql
sql = 'select * from person where id > 1;'
cursor.execute(sql)
# 获取查询集
# query_set = cursor.fetchall()  # 获取全部的数据
# query_set =  cursor.fetchone()  # 获取一条数据
query_set = cursor.fetchmany(3)  # 获取3条数据
print(query_set)

# 5. 关闭游标
cursor.close()

# 6. 关闭连接
conn.close()

扩展: 大数据主要解决了企业的问题???

如果企业没钱还想计算和存储海量数据,就要使用大数据解决方案,如果有钱直接上超级计算机

大数据解决方案一般是性能,工期和成本之间的博弈,但是一般妥协的都是前两者.

6.6 递归[了解]

递归时数学中的说法,其实就是一个函数内部调用了函数本身,那么这个就是递归

合理递归的要求:

  1. 在函数体内部调用函数本身
  2. 要有明确的递归出口(递归跳出条件)
  3. 不能超出最大调用深度(python默认函数最多嵌套1000层)
# 递归是一种算法
# 什么是算法???  将数学知识以代码的形式呈现出来的一种{思想}

# # 递归就是在函数体内部调用函数本身的一种代码书写形式
# def func1():
#     func1()
#     print('123')
#
# # RecursionError: maximum recursion depth exceeded
# func1()

# 上述内容就是递归,但是不是一个合理的递归,合理的递归有如下三个条件
"""
1. 在函数体内部调用函数本身
2. 要有明确的递归出口(递归跳出条件)
3. 不能超出最大调用深度(python默认函数最多嵌套1000层)
"""

# 举例: 计算1-n的累加和
"""
递归第一步要找规律
f(1) = 1                    = 1
f(2) = 1 + 2                = f(1) + 2
f(3) = 1 + 2 + 3            = f(2) + 3
f(4) = 1 + 2 + 3 + 4        = f(3) + 4
....
f(n) = 1 + 2 + 3 ... + n    = f(n-1) + n

结论:
计算1-n的累加和的规律就是 f(n-1) + n
"""


# 递归第二步.将数学规律转换为代码逻辑
# def sum_1_to_n(n):
#     return sum_1_to_n(n-1) + n
#
# sum_1_to_n(100)

# 递归第三步. 找到递归地跳出条件
# 根据上边的规律,f(1)函数中,没有调用函数本身,则此时就是f函数的递归出口
def sum_1_to_n(n):
    if n == 1:
        return 1
    return sum_1_to_n(n - 1) + n


print(sum_1_to_n(100)) # 5050
# RecursionError: maximum recursion depth exceeded in comparison
print(sum_1_to_n(1000)) # 超出最大的调用深度,所以报错

递归的缺点:

  • 递归的性能消耗极大
  • 如果递归的调用深度或者递归的出口没有限制完全,在使用时极易造成程序崩溃
  • 递归的使用场景不容易辨别

递归的优点:

  • 可以将一个复杂的问题简单化,拆分为多个嵌套的简单问题
  • 使用递归可以减少代码量

递归逻辑图解

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ETL基础认知 的相关文章

  • openpyxl 2.4.2:保存后公式生成的单元格值为空

    我使用 openpyxl 打开文件 编辑一些单元格并保存更改 这是一个例子 import openpyxl book openpyxl load workbook sheet path sheet book active for row i
  • 在 Django 中定义视图和 url。为什么调用函数时不使用括号?

    我已经在经历 Python速成课程 目前正在进行 Django Web应用程序项目 学习日志 阶段 有些东西与我已经学到的相矛盾 views py file from django shortcuts import render def i
  • 打印 scrapy 请求的“响应”

    我正在尝试学习 scrapy 在遵循教程的同时 我正在尝试进行细微的调整 我想简单地从请求中获取响应内容 然后我会将响应传递到教程代码中 但我无法发出请求并获取响应内容 建议就好 from scrapy http import Respon
  • 替换字符串列表中的 \x00 的最佳方法?

    我有一个来自已解析 PE 文件的值列表 其中包括 x00每个部分末尾的空字节 我希望能够删除 x00字符串中的字节而不删除所有字节 x 文件中的 s 我试过做 replace and re sub 但并没有取得太大成功 使用Python 2
  • 如何在 Ubuntu 上安装 Python 模块

    我刚刚用Python写了一个函数 然后 我想将其做成模块并安装在我的 Ubuntu 11 04 上 这就是我所做的 创建 setup py 和 function py 文件 使用 Python2 7 setup py sdist 构建分发文
  • 如何更改充当按钮的范围的文本

    我正在为自定义 Web 应用程序编写自动化测试 我遇到了无法更改跨度文本的问题 我尝试过使用 driver execute script 但没有运气 如果我更好地了解 javascript 这确实会有帮助 据我所知 您无法单击跨度 并且列表
  • 使用正则表达式解析 Snort 警报文件

    我正在尝试使用 Python 中的正则表达式从 snort 警报文件中解析出源 目标 IP 和端口 和时间戳 示例如下 03 09 14 10 43 323717 1 2008015 9 ET MALWARE User Agent Win9
  • Python3 查找 2 个列表中有多少个差异才能相等

    假设我们有 2 个列表 always具有相同的长度和always包含字符串 list1 sot sot ts gg gg gg list2 gg gg gg gg gg sot 我们需要找到 其中有多少项list2应该改变 以便它等于lis
  • 如何在 Windows 上使用 Python 3.6 来安装 Python 2.7

    我想问一下如何使用pip install对于 Python 2 7 当我之前安装并使用 Python 3 6 时 我现在必须使用 Windows 上的 Python 版本 pip install 继续安装 Python 3 6 我需要使用以
  • 行为:如何从另一个文件导入步骤?

    我刚刚开始使用behave http pythonhosted org behave 一个Pythonic BDD框架 使用小黄瓜语法 http docs behat org guides 1 gherkin html 行为需要一个特征 例
  • 如何为多组精灵创建随机位置?

    我尝试使用 blit 和 draw 方法进行 for 循环 并为 PlayerSprite 和 Treegroup 使用不同的变量 for PlayerSprite in Treegroup surface blit PlayerSprit
  • Python unicode 字符代码?

    有没有办法将 Unicode 字符 插入 Python 3 中的字符串 例如 gt gt gt import unicode gt gt gt string This is a full block s unicode charcode U
  • 字典中列表中仅有的几个索引的总和

    如果我有这种类型的字典 a dictionary dog white 3 5 black 6 7 Brown 23 1 cat gray 5 6 brown 4 9 bird blue 3 5 green 1 2 yellow 4 9 mo
  • Python int 太大,无法放入 SQLite

    我收到错误 OverflowError Python int 太大 无法转换为 SQLite INTEGER 来自以下代码块 该文件约25GB 因此必须分部分读取 length 6128765 Works on partitions of
  • urllib2.urlopen() 是否实际获取页面?

    当我使用 urllib2 urlopen 时 我在考虑它只是为了读取标题还是实际上带回整个网页 IE 是否真的通过 urlopen 调用或 read 调用获取 HTML 页面 handle urllib2 urlopen url html
  • 在 pip.conf 中指定多个可信主机

    这是我尝试在我的中设置的 etc pip conf global trusted host pypi org files pythonhosted org 但是 它无法正常工作 参考 https pip pypa io en stable
  • ValueError:无法插入 ID,已存在

    我有这个数据 ID TIME 1 2 1 4 1 2 2 3 我想按以下方式对数据进行分组ID并计算每组的平均时间和规模 ID MEAN TIME COUNT 1 2 67 3 2 3 00 1 如果我运行此代码 则会收到错误 ValueE
  • 是否可以强制浮点数的指数或有效数匹配另一个浮点数(Python)?

    这是我前几天试图解决的一个有趣的问题 是否可以强制一个的有效数或指数float与另一个人一样float在Python中 出现这个问题是因为我试图重新调整一些数据 以便最小值和最大值与另一个数据集匹配 然而 我重新调整后的数据略有偏差 大约小
  • Google App Engine 中的自定义身份验证

    有谁知道或知道我可以在哪里学习如何使用 Python 和 Google App Engine 创建自定义身份验证流程 我不想使用 Google 帐户进行身份验证 并且希望能够创建自己的用户 如果不是专门针对 Google App Engin
  • 如何使用 Django (Python) 登录表单?

    我在 Django 中构建了一个登录表单 现在我遇到了路由问题 当我选择登录按钮时 表单不会发送正确的遮阳篷 我认为前端的表单无法从 查看 py 文件 所以它不会发送任何 awnser 并且登录过程无法工作 该表单是一个简单的静态 html

随机推荐

  • mongovue 导入mysql_【mongo】用户添加、导入数据库、连接VUE

    添加用户 1 安装mongo时最好用apt get install 因为这样可以省去很多麻烦 比如一些环境变量 还有一些文档路径等等的问题 2 确认一下自己的mongodb和mongodb clients的版本 要版本一致才可以 查看mon
  • Linux 中power supply软件架构和相关API

    一 概述 电源管理整体上可以分为两个部分 一个是电池监控 fuel gauge 另外一个是充放电管理 这两部分在内核中也是分为两个驱动来管理 fuelgauge驱动的功能主要是负责向上层Android系统提供当前电池的电量和健康信息等等 同
  • React + MobX - 完全上手指南

    React MobX 完全上手指南 前言 正文 MobX 準備工作 MobX 基本使用 Store Action 組件中 MobX 生效 MobX Decorators MobX Decorators 準備工作 使用 MobX Decora
  • 超详细JDK1.8安装教程

    1 下载并安装 jdk 8u241 windows x64 JDK 8下载地址 https pan baidu com s 1 DN 5RL0mlURsN8dzYjqgw 提取码 rg5n 可自定义目录 之后配置环境变量会用到 一直下一步即
  • QThread使用方法

    QThread使用方法 昨天不小心看到Qt开发人员 Bradley T Hughes Blog中的一片文章 you are doing it wrong 结果看得头昏脑胀 好歹也自学了近1年的Qt 也一直很小心 很认真地阅读Qt和manua
  • Verilog中Case语句

    转自 https blog csdn net CLL caicai article details 104395480 实际问题中常常需要用到多分支选择 使用if语句导致内容繁琐 更明智的做法是使用case语句 case语句是一种多分支选择
  • 七牛云入门使用步骤(图片服务器使用)

    登入七牛云官网得到3个比较重要的参数 如图 1 sk 2 ak 3 测试域名 第一步导入七牛云sdk
  • 数据结构-查找(顺序查找与二分查找的讲解与代码实现)

    顺序查找概念 从表的另一端开始 一次将记录的关键字和给定值进行比较 若某个记录的关键字和给定的值相等 则查找成功 反之则查找失败 ASL 平均查找长度 pi查找概率 ci查找次数 eg 序列1 2 3 查找1的次数为1概率为1 3 2为两次
  • AdaCost

    AdaCost算法 参考 AdaCost Misclassification Cost sensitive Boosting 代价敏感 错分类的损失很大的样例 比如新冠肺炎本来是阳性但是被检测出阴性 Cost sensitive思想是一种符
  • 半导体行业深度报告:从应用到行业的全面复苏

    来源 国金证券 一 2020 2021年全球半导体市场投资展望 多种因素导致全球半导体市场于 2019 年同比下跌近 13 到 4 102 亿美元 而存储器行业同比下跌超过 30 逻辑半导体同比下跌近 2 存储器市场占全球半导体市场达到近三
  • 数据结构:C语言实现二叉树的构建以及遍历操作

    使用二叉链表的存储结构存储二叉树 typedef struct BinNode int data struct BinNode lchild struct BinNode rchild BinNode BinTree BinTree bin
  • [工具使用]SqlMap

    工具使用 SqlMap SqlMap 常用指令 探测目标网站是否存在注入 查询数据库users 查询数据库passwords 查询数据库当前用户 查询当前数据库用户是否是管理员权限 列出数据库的管理员用户名 查询所有数据库 查询当前数据库
  • 利用Pycharm上传代码到GitHub

    前提 必须能正常链接上GitHub网站 并且拥有GitHub账号 在win环境或者Ubuntu环境上必须安装有git 安装好pycharm 并且有上传的代码 pycharm配置GitHub账号 首先需要将准备上传的project配置GitH
  • linux通过端口号定位进程的几种方法

    通过端口号找进程ID Pid 1 概述 日常在linux 服务器上排查问题时 会有根据端口号找对应pid 进程id 的需求 最终通过定位pid来排查问题 本文将介绍如何在linux系统上通过监听端口号找到相关的进程 2 使用netstat命
  • CNN模型 INT8 量化实现方式(一)

    当前CNN模型基本都是 float32 将其转换为 INT8 可以降低模型大小 提升速度 精度降低的也不太多 那么在实际中如何实现这个量化了 在网上找到了三种实践方法 基于腾讯的NCNN Tensorflow Nvidia 的 Tensor
  • 接口抓包,Fiddler抓包使用方法总结,入门到精通辅助实战...

    目录 导读 前言 一 Python编程入门到精通 二 接口自动化项目实战 三 Web自动化项目实战 四 App自动化项目实战 五 一线大厂简历 六 测试开发DevOps体系 七 常用自动化测试工具 八 JMeter性能测试 九 总结 尾部小
  • 【面向对象编程 C++】笔记(完结)

    前言 是为复习做的笔记 内容来自课本和老师的课件 不全面 第10章 类和对象 面向对象 注重过程 把事件分成小模块 类和对象的定义与访问 注意 类定义结束处有分号 类是一种类型 该类型的变量成为对象 类成员的访问特性 成员函数的定义 类内声
  • OpenCV的copyTo()函数讲解及应用

    Index 目录索引 写在前面 函数介绍 案例演示 参考文章 写在前面 继前文的setTo 函数讲解后 本文对和该函数用法类似的OpenCV中的copyTo 函数进行讲解 函数介绍 可以直接在 OpenCV参考文档 中查阅 该函数的用法为
  • MySQL高可用工具heartbeat简介

    MySQL高可用工具heartbeat简介 官网 http www linux ha org wiki Heartbeat 一 HeartBeat的作用 通过HeartBeat 可以将资源 IP以及程序服务等资源 从一台已经故障的计算机快速
  • ETL基础认知

    1 ETL基础认知 了解 问题1 如何将零散的数据 集中输入到数据仓库 ETL E 数据抽取 抽取的是其他数据源中的数据 T 数据转换 将数据转换为统一的格式 消除异常值 缺失值 对于错误的逻辑进行修改 L 数据加载 将不同数据源的数据处理