课程目标
-
目标:自动化的ODS层与DWD层构建
-
实现
- 掌握Hive以及Spark中建表的语法规则
- 实现项目开发环境的构建
- 自己要实现所有代码注释
- ODS层与DWD层整体运行测试成功
数仓分层
-
ODS层 :原始数据层
-
来自于Oracle中数据的采集
-
数据存储格式:AVRO
-
ODS区分全量和增量
-
实现
-
数据已经采集完成
/data/dw/ods/one_make/full_imp /data/dw/ods/one_make/incr_imp -
step1:创建ODS层数据库:one_make_ods
-
step2:根据表在HDFS上的数据目录来创建分区表
-
step3:申明分区
-
-
-
DWD层:明细数据层
-
来自于ODS层数据(没有做ETL处理)
-
数据存储格式:ORC
-
不区分全量和增量的
-
实现
- step1:创建DWD层数据库:one_make_dwd
- step2:创建DWD层的每一张表
- step3:从ODS层抽取每一张表的数据写入DWD层对应的表中
-
Hive建表语法
-
实施
CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name ( col1Name col1Type [COMMENT col_comment], co21Name col2Type [COMMENT col_comment], co31Name col3Type [COMMENT col_comment], co41Name col4Type [COMMENT col_comment], co51Name col5Type [COMMENT col_comment], …… coN1Name colNType [COMMENT col_comment] ) [PARTITIONED BY (col_name data_type ...)] [CLUSTERED BY (col_name...) [SORTED BY (col_name ...)] INTO N BUCKETS] [ROW FORMAT row_format] row format delimited fields terminated by lines terminated by [STORED AS file_format] [LOCATION hdfs_path] TBLPROPERTIES-
EXTERNAL:外部表类型
- 内部表、外部表、临时表
-
PARTITIONED BY:分区表结构
- 普通表、分区表、分桶表
-
CLUSTERED BY:分桶表结构
-
ROW FORMAT:指定分隔符
- 列的分隔符:\001
- 行的分隔符:\n
-
STORED AS:指定文件存储类型
- ODS:avro
- DWD:orc
-
LOCATION:指定表对应的HDFS上的地址
- 默认:/user/hive/warehouse/dbdir/tbdir
-
TBLPROPERTIES:指定一些表的额外的一些特殊配置属性
-
Avro建表语法
-
实施
- Hive官网:cwiki.apache.org/confluence/…
- DataBrics官网:docs.databricks.com/spark/2.x/s…
- Avro用法:cwiki.apache.org/confluence/…
-
指定文件类型
-
方式一:指定类型
stored as avro -
方式二:指定解析类
--解析表的文件的时候,用哪个类来解析 ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.avro.AvroSerDe' --读取这张表的数据用哪个类来读取 STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat' --写入这张表的数据用哪个类来写入 OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat'
-
-
指定Schema
-
方式一:手动定义Schema
CREATE TABLE embedded COMMENT "这是表的注释" ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.avro.AvroSerDe' STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat' -- TBLPROPERTIES TBLPROPERTIES ( 'avro.schema.literal'='{ "namespace": "com.howdy", "name": "some_schema", "type": "record", "fields": [ { "name":"string1","type":"string"}] }' ); -
方式二:加载Schema文件
CREATE TABLE embedded COMMENT "这是表的注释" ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.avro.AvroSerDe' STORED as INPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat' -- TBLPROPERTIES TBLPROPERTIES ( 'avro.schema.url'='file:///path/to/the/schema/embedded.avsc' );
-
-
建表语法
指定文件类型、指定Schema各有两种方式,两两组合应有四种建表语法,这里只给出其中常用的两种(排除了手动定义Schema的方式)
-
方式一:指定类型和加载Schema文件
create external table one_make_ods_test.ciss_base_areas comment '行政地理区域表' PARTITIONED BY (dt string) stored as avro -- 指定类型 location '/data/dw/ods/one_make/full_imp/ciss4.ciss_base_areas' TBLPROPERTIES ('avro.schema.url'='/data/dw/ods/one_make/avsc/CISS4_CISS_BASE_AREAS.avsc'); -
方式二:指定解析类和加载Schema文件
create external table one_make_ods_test.ciss_base_areas comment '行政地理区域表' PARTITIONED BY (dt string) ROW FORMAT SERDE -- 指定解析类 'org.apache.hadoop.hive.serde2.avro.AvroSerDe' STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat' location '/data/dw/ods/one_make/full_imp/ciss4.ciss_base_areas' TBLPROPERTIES ('avro.schema.url'='/data/dw/ods/one_make/avsc/CISS4_CISS_BASE_AREAS.avsc');-- 中文是需要变化的部分 create external table 数据库名称.表名 comment '表的注释' partitioned by ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.avro.AvroSerDe' STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat' location '这张表在HDFS上的路径' TBLPROPERTIES ('这张表的Schema文件在HDFS上的路径')-- 创建了一个名为 ciss_base_areas 的外部表,按 dt 字段进行分区,使用 Avro 格式,数据存储在指定的 HDFS 路径,并指定了 Avro 文件位置 -- 1. 创建外部表 create external table: 指定创建一个外部表,数据存储在 Hive 外部,删除表时不会删除数据。 -- 2. 表注释 comment '行政地理区域表' -- 3. 分区字段 -- PARTITIONED BY: 指定表按某个字段分区,这里是 dt 字段,类型为字符串。 PARTITIONED BY (dt string) -- 4. 固定写法 ROW FORMAT SERDE、STORED AS INPUTFORMAT、OUTPUTFORMAT -- 5. 数据位置 -- location: 指定实际数据存储的位置,这里是 HDFS 中的路径。 location '/data/dw/ods/one_make/full_imp/ciss4.ciss_base_areas' -- 6. 表属性 -- TBLPROPERTIES: 设置表的属性,这里指定 Avro 数据的模式文件位置(.avsc 文件),用于描述数据的结构。 TBLPROPERTIES ('avro.schema.url'='/data/dw/ods/one_make/avsc/CISS4_CISS_BASE_AREAS.avsc');
-
初始化Oracle、Hive连接
# ==============todo: 1-初始化Oracle、Hive连接,读取表的名称==============#
# 输出信息
recordLog('ODS&DWD Building AND Load Data')
# 定义一个分区变量:指定当前要操作的 Hive 分区的值为 20210101
partitionVal = '20210101'
# 调用了获取连接的工具类,构建一个 Oracle 的连接对象
oracleConn = OracleHiveUtil.getOracleConn()
# 调用了获取连接的工具类,构建一个 Spark 的连接对象
hiveConn = OracleHiveUtil.getSparkHiveConn()
# 调用文件工具类,加载 表明文件,返回存放所有表名信息的列表(全量表、增量表)
tableList = FileUtil.readFileContent("E:\Python_DataDevelop\1、Spark离线数仓工业项目\dw\ods\meta_data\tablenames.txt")
# 调用表名工具类,基于传递的所有表名,将增量表与全量表进行划分到不同的列表中,并返回一个存放全量表、增量表的列表
# tableNameList[0] : 全量表
# tableNameList[1] : 增量表
tableNameList = TableNameUtil.getODSTableNameList(tableList)
# ------------------测试:输出获取到的连接以及所有表名
# print(oracleConn)
# print(hiveConn)
# for tbnames in tableNameList:
# print("---------------------")
# for tbname in tbnames:
# print(tbname)
Oracle 连接的实现方法
def getOracleConn():
"""
用户获取Oracle的连接对象:cx_Oracle.connect(host='', port='', username='', password='', param='')
:return:
"""
# 创建 Oracle 连接对象
oracleConn = None #构建Oracle连接对象
try:
ORACLE_HOST = ConfigLoader.getOracleConfig('oracleHost') # 通过加载类,获取Oracle连接主机地址 oracle.bigdata.cn
ORACLE_PORT = ConfigLoader.getOracleConfig('oraclePort') # 通过加载类,获取Oracle连接端口 1521
ORACLE_SID = ConfigLoader.getOracleConfig('oracleSID') # 通过加载类,获取Oracle连接的SID helowin
ORACLE_USER = ConfigLoader.getOracleConfig('oracleUName') # 通过加载类,获取Oracle连接的用户名 ciss
ORACLE_PASSWORD = ConfigLoader.getOracleConfig('oraclePassWord') # 通过加载类,获取Oracle连接的密码 123456
dsn = cx_Oracle.makedsn(ORACLE_HOST, ORACLE_PORT, ORACLE_SID) # 构建 DSN
oracleConn = cx_Oracle.connect(ORACLE_USER, ORACLE_PASSWORD, dsn) # cx_Oracle 通过 用户名、密码、dsn 构建真正的 Oracle 连接
# 异常处理
except cx_Oracle.Error as error:
print(error)
# 返回 Oracle 连接
return oracleConn
Hive 连接的实现方法
def getSparkHiveConn():
"""
用户获取SparkSQL的连接对象
:return:
"""
# 构建SparkSQL的连接对象
sparkHiveConn = None
try:
SPARK_HIVE_HOST = ConfigLoader.getSparkConnHiveConfig('sparkHiveHost') # 通过加载类,获取 Spark 连接主机地址 spark.bigdata.cn
SPARK_HIVE_PORT = ConfigLoader.getSparkConnHiveConfig('sparkHivePort') # 通过加载类,获取 Spark 连接端口 10001
SPARK_HIVE_UNAME = ConfigLoader.getSparkConnHiveConfig('sparkHiveUName') # 通过加载类,获取 Spark 连接的用户名 root
SPARK_HIVE_PASSWORD = ConfigLoader.getSparkConnHiveConfig('sparkHivePassWord') # 通过加载类,获取 Spark 连接的密码 123456
# 构建 Spark 连接
sparkHiveConn = hive.Connection(host=SPARK_HIVE_HOST, port=SPARK_HIVE_PORT, username=SPARK_HIVE_UNAME, auth='CUSTOM', password=SPARK_HIVE_PASSWORD)
# 异常处理
except Exception as error:
print(error)
# 返回 Spark 连接
return sparkHiveConn
ODS层建库
# ==============todo: 2-ODS层建库==============#
# 构建一个建库建表的类的对象:实例化的时候给连接赋值(Oracle和Hive的连接实例)
cHiveTableFromOracleTable = CHiveTableFromOracleTable(oracleConn, hiveConn)
# 打印日志
recordLog('ODS层创建数据库')
# 连接实例调用创建数据库的方法:传递 ODS 层的数据库名称
# CreateMetaCommon.ODS_NAME:'one_make_ods',ODS层 数据库的名称
cHiveTableFromOracleTable.executeCreateDbHQL(CreateMetaCommon.ODS_NAME)
print(f"{CreateMetaCommon.ODS_NAME}库构建成功!")
class CHiveTableFromOracleTable:
# 构建当前类的对象时,初始化Oracle和Hive的连接
def __init__(self, oracleConn, hiveConn):
self.oracleConn = oracleConn
self.hiveConn = hiveConn
# 创建数据库方法
def executeCreateDbHQL(self, dbName):
"""
根据传递的数据库名称,在Hive中创建数据库
:param dbName: 数据库名称
:return: None
"""
# 构建 建库 语句
createDbHQL = 'create database if not exists ' + dbName
# 获取 hive 连接的游标
cursor = self.hiveConn.cursor()
try:
# 游标执行 建库 语句
cursor.execute(createDbHQL)
# 异常处理
except hive.Error as error:
print(error)
# 执行结束,最后释放游标
finally:
if cursor:
cursor.close()
ODS层建表
# ==============todo: 3-ODS层建表==============#
# 打印日志
recordLog('ODS层创建全量表...')
# 取出全量表的表名
fullTableList = tableNameList[0]
# 取出每张全量表的表名
# FULL_IMP:'full_imp',ODS层 全量表存放的路径名
for tblName in fullTableList:
# 创建全量表:ODS层数据库名称、全量表的表名、全量表存放的路径
cHiveTableFromOracleTable.executeCreateTableHQL(CreateMetaCommon.ODS_NAME, tblName, CreateMetaCommon.FULL_IMP)
# 打印日志
recordLog('ODS层创建增量表...')
# 取出增量表的表名
incrTableList = tableNameList[1]
# INCR_IMP:'incr_imp',ODS层 增量表存放的路径名
for tblName in incrTableList:
# 创建增量表:ODS层数据库名称、增量表的表名、增量表存放的路径
cHiveTableFromOracleTable.executeCreateTableHQL(CreateMetaCommon.ODS_NAME, tblName, CreateMetaCommon.INCR_IMP)
全量表、增量表建表
class CHiveTableFromOracleTable:
# 构建当前类的对象时,初始化Oracle和Hive的连接
...
# 创建数据库方法
...
# 执行Hive建表
def executeCreateTableHQL(self, dbName, tableName, dynamicDir):
"""
用于根据传递的数据库名称、表名在Hive中创建对应的表,self为当前类的实例对象
:param dbName: 数据库名称【ODS、DWD】
:param tableName: 表名
:param dynamicDir: 全量或者增量【full_imp、incr_imp】
:return: None
"""
# 构建一个空的列表:用于拼接字符串:SQL语句
buffer = []
# 构建一个游标对象
cursor = None
try:
# 从 Oracle 获取表的元数据:表的信息 = 表名 + 表的注释 + list[列的信息]
tableMeta = OracleMetaUtil.getTableMeta(self.oracleConn, tableName.upper())
# 拼接SQL:create external table if not exists one_make_ods.
buffer.append("create external table if not exists " + dbName + ".")
# 拼接SQL:ciss_base_areas
buffer.append(tableName.lower())
# 拼接SQL:列的信息,ODS层不执行
# 拼接SQL:列的信息,DWD层用于拼接每一列的信息
buffer = getODSStringBuffer(buffer, dbName, tableMeta)
# 拼接SQL:如果表有注释,将表的注释拼接到建表语句中
if tableMeta.tableComment:
buffer.append(" comment '" + tableMeta.tableComment + "' \n")
# 拼接SQL:指定分区
buffer.append(' partitioned by (dt string) ')
# 拼接SQL:Schema的路径,文件的存储格式
# ods > avro、dwd > orc
buffer.append(CreateMetaCommon.getTableProperties(dbName, tableName))
# ODS => ods,DWD => dwd
dbFolderName = CreateMetaCommon.getDBFolderName(dbName)
# ODS => ciss4.,DWD => 空
userName = CreateMetaCommon.getUserNameByDBName(dbName)
# 拼接SQL:location
# CreateMetaCommon.getDynamicDir(dbName,dynamicDir):设置为 full_imp 还是 incr_imp
buffer.append(" location '/data/dw/" + dbFolderName + "/one_make/" + CreateMetaCommon.getDynamicDir(dbName,dynamicDir) + "/" + userName + tableName + "'")
# 获取 SaprkSQl 的游标
cursor = self.hiveConn.cursor()
# 将 buffer 列表转为字符串,并执行 SQL 语句
cursor.execute(''.join(buffer))
logging.warning(f'oracle表转换{dbFolderName}后的Hive DDL语句为:\n{"".join(buffer)}')
# 异常处理
except Exception as exception:
print(exception)
# 释放游标
finally:
if cursor:
cursor.close()
ODS层申明分区
# ==============todo: 4-ODS层申明分区==============#
recordLog('创建ods层全量表分区...')
# 构建用于申明分区的类对象
createHiveTablePartition = CreateHiveTablePartition(hiveConn)
# 全量表执行44次创建分区操作
for tblName in fullTableList:
# 调用申明分区的方法,申明全量表的分区:ods层的数据库名称、表名、full_imp(全量表路径)、'20210101'(20分区参数)
createHiveTablePartition.executeCPartition(CreateMetaCommon.ODS_NAME, tblName, CreateMetaCommon.FULL_IMP, partitionVal)
recordLog('创建ods层增量表分区...')
# 增量表执行57次创建分区操作
for tblName in incrTableList:
# 调用申明分区的方法,申明全量表的分区:ods层的数据库名称、表名、incr_imp(增量表路径)、'20210101'(20分区参数)
createHiveTablePartition.executeCPartition(CreateMetaCommon.ODS_NAME, tblName, CreateMetaCommon.INCR_IMP, partitionVal)
申明分区实现的类
class CreateHiveTablePartition(object):
def __init__(self, hiveConn):
self.hiveConn = hiveConn
def executeCPartition(self, dbName, hiveTName, dynamicDir, partitionDT):
"""
用于实现给Hive表的数据手动申明分区
:param dbName: 数据库名称
:param hiveTName: 表名称
:param dynamicDir: 全量或者增量
:param partitionDT: 分区值
:return: None
"""
# 构建空列表,用于拼接SQL语句
buffer = []
# 定义一个游标
cursor = None
try:
# SQL拼接:alter table one_make_ods.
buffer.append("alter table " + dbName + ".")
# SQL拼接:alter table one_make_ods.表名
buffer.append(hiveTName)
# SQL拼接:alter table one_make_ods.表名 add if not exists partition (dt='
buffer.append(" add if not exists partition (dt='")
# SQL拼接:alter table one_make_ods.表名 add if not exists partition (dt='分区值
buffer.append(partitionDT)
# SQL拼接:alter table one_make_ods.表名 add if not exists partition (dt='分区值)
# location '/data/dw/ods数据库名称/onemake/全量表 或 增量表/ciss4.
buffer.append("') location '/data/dw/" + CreateMetaCommon.getDBFolderName(dbName) +
"/one_make/" + CreateMetaCommon.getDynamicDir(dbName, dynamicDir) + "/ciss4.")
# SQL拼接:...location '/data/dw/ods数据库名称/onemake/全量表 或 增量表/ciss4.表名/分区值'
buffer.append(hiveTName)
buffer.append("/")
buffer.append(partitionDT)
buffer.append("'")
# 实例化SparkSQL游标
cursor = self.hiveConn.cursor()
# 执行SQL语句
cursor.execute(''.join(buffer))
# 输出日志
logging.warning(f'执行创建hive\t{hiveTName}表的分区:{partitionDT},\t分区sql:\n{"".join(buffer)}')
# 异常处理
except Exception as e:
print(e)
# 释放游标
finally:
if cursor:
cursor.close()
DWD层建库
# ==============todo: 5-DWD层建库建表==============#
# 5.1 建库记录日志
recordLog('DWD层创建数据库')
# 创建DWD层数据库
# 连接实例调用创建数据库的方法:传递 ODS 层的数据库名称
# CreateMetaCommon.DWD_NAME:'one_make_dwd',DWD层 数据库的名称
cHiveTableFromOracleTable.executeCreateDbHQL(CreateMetaCommon.DWD_NAME)
class CHiveTableFromOracleTable:
# 构建当前类的对象时,初始化Oracle和Hive的连接
...
# 创建数据库方法
def executeCreateDbHQL(self, dbName):
"""
根据传递的数据库名称,在Hive中创建数据库
:param dbName: 数据库名称
:return: None
"""
# 构建 建库 语句
createDbHQL = 'create database if not exists ' + dbName
# 获取 hive 连接的游标
cursor = self.hiveConn.cursor()
try:
# 游标执行 建库 语句
cursor.execute(createDbHQL)
# 异常处理
except hive.Error as error:
print(error)
# 执行结束,最后释放游标
finally:
if cursor:
cursor.close()
DWD层建表
# ==============todo: 5-DWD层建库建表==============#
# 5.2 建表记录日志
recordLog('DWD层创建表...')
# 将全量表、增量表的全部表名数据 整理到 一个列表中
allTableName = [i for j in tableNameList for i in j]
for tblName in allTableName:
cHiveTableFromOracleTable.executeCreateTableHQL(CreateMetaCommon.DWD_NAME, tblName, None)
全量表、增量表建表
class CHiveTableFromOracleTable:
# 构建当前类的对象时,初始化Oracle和Hive的连接
...
# 创建数据库方法
...
# 执行Hive建表
def executeCreateTableHQL(self, dbName, tableName, dynamicDir):
"""
用于根据传递的数据库名称、表名在Hive中创建对应的表,self为当前类的实例对象
:param dbName: 数据库名称【ODS、DWD】
:param tableName: 表名
:param dynamicDir: 全量或者增量【full_imp、incr_imp】
:return: None
"""
# 构建一个空的列表:用于拼接字符串:SQL语句
buffer = []
# 构建一个游标对象
cursor = None
try:
# 从 Oracle 获取表的元数据:表的信息 = 表名 + 表的注释 + list[列的信息]
tableMeta = OracleMetaUtil.getTableMeta(self.oracleConn, tableName.upper())
# 拼接SQL:create external table if not exists one_make_ods.
buffer.append("create external table if not exists " + dbName + ".")
# 拼接SQL:ciss_base_areas
buffer.append(tableName.lower())
# 拼接SQL:列的信息,ODS层不执行
# 拼接SQL:列的信息,DWD层用于拼接每一列的信息
buffer = getODSStringBuffer(buffer, dbName, tableMeta)
# 拼接SQL:如果表有注释,将表的注释拼接到建表语句中
if tableMeta.tableComment:
buffer.append(" comment '" + tableMeta.tableComment + "' \n")
# 拼接SQL:指定分区
buffer.append(' partitioned by (dt string) ')
# 拼接SQL:Schema的路径,文件的存储格式
# ods > avro、dwd > orc
buffer.append(CreateMetaCommon.getTableProperties(dbName, tableName))
# ODS => ods,DWD => dwd
dbFolderName = CreateMetaCommon.getDBFolderName(dbName)
# ODS => ciss4.,DWD => 空
userName = CreateMetaCommon.getUserNameByDBName(dbName)
# 拼接SQL:location
# CreateMetaCommon.getDynamicDir(dbName,dynamicDir):设置为 full_imp 还是 incr_imp
buffer.append(" location '/data/dw/" + dbFolderName + "/one_make/" + CreateMetaCommon.getDynamicDir(dbName,dynamicDir) + "/" + userName + tableName + "'")
# 获取 SaprkSQl 的游标
cursor = self.hiveConn.cursor()
# 将 buffer 列表转为字符串,并执行 SQL 语句
cursor.execute(''.join(buffer))
logging.warning(f'oracle表转换{dbFolderName}后的Hive DDL语句为:\n{"".join(buffer)}')
# 异常处理
except Exception as exception:
print(exception)
# 释放游标
finally:
if cursor:
cursor.close()
DWD层数据抽取
# ==============todo: 6-DWD层数据抽取==============#
# 记录日志
recordWarnLog('DWD层加载数据,此操作将启动Spark JOB执行,请稍后...')
for tblName in allTableName:
recordLog(f'加载dwd层数据到{tblName}表...')
try:
LoadData2DWD.loadTable(oracleConn, hiveConn, tblName, partitionVal)
except Exception as error:
print(error)
recordLog('完成!!!')
数据加载实现类
def loadTable(orclConn, hiveConn, tableName, partitionValue):
"""
加载ODS层表的数据到DWD层
:param orclConn: Oracle连接对象
:param hiveConn: Hive连接对象
:param tableName: 表名
:param partitionValue: 分区值
:return: None
"""
tableMeta = OracleMetaUtil.getTableMeta(orclConn, tableName.upper())
buffer = [
"insert overwrite table " + CreateMetaCommon.DWD_NAME + "." + tableMeta.tableName + " partition(dt=" + partitionValue + ")\n",
"select\n"]
# 拼接所有列名
allColumns = ', '.join(cname for cname in tableMeta.getColumnNameList())
buffer.append(allColumns + "\n")
buffer.append("from " + CreateMetaCommon.ODS_NAME + "." + tableMeta.tableName + "\n")
buffer.append("where dt='" + partitionValue + "'")
logging.warning(f'SparkSql插入数据,sql\n{"".join(buffer).lower()}')
# 将整个SQL语句转换为小写
loadSQL = ''.join(buffer).lower()
# 获取Hive连接的一个游标
cursor = hiveConn.cursor()
# 执行SQL语句,加载数据
cursor.execute(loadSQL)