构建数仓层次/导入数据
创建五个用户用来分层,并直接赋予DBA角色,方便后期使用
查看权限是否赋予成功
SELECT * FROM DBA_ROLE_PRIVS WHERE granted_role = 'DBA';
将数据文件导入数据源(DB)
将数据导入oracle的命令(在电脑的cmd,即命令提示符中输入命令):
imp 用户名/密码@ip地址:端口号/库名 file=dmp文件路径/文件名 full=y
ODS贴源层
建表
(字段类型+注释信息)
DECLARE-- 获取DB用户的表名CURSOR C_TABLES IS SELECT TABLE_NAME FROM DBA_TABLES WHERE OWNER = 'DB';-- 获取DB用户下所有表的字段CURSOR C_COLUMNS (P_TABLE VARCHAR2) ISSELECT TABLE_NAME,COLUMN_NAME,DATA_TYPE,DATA_LENGTH,DATA_PRECISION,DATA_SCALEFROM DBA_TAB_COLUMNS WHERE OWNER = 'DB' AND TABLE_NAME = P_TABLE;-- 获取所有的字段注释CURSOR C_COL_COMMENTS (P_TABLE VARCHAR2) ISSELECT COLUMN_NAME,COMMENTSFROM DBA_COL_COMMENTS WHERE OWNER = 'DB' AND TABLE_NAME = P_TABLE;V_SQL VARCHAR2(2000); -- 构建sql语句V_DATA_TYPE VARCHAR2(2000); -- 构建 数据类型V_COMMENT_SQL VARCHAR2(2000); -- 构建 添加字段注释的脚本
BEGINFOR X IN C_TABLES LOOPBEGIN -- 如果表存在则删除EXECUTE IMMEDIATE 'DROP TABLE ODS.'||X.TABLE_NAME ||' PURGE';EXCEPTION WHEN OTHERS THENDBMS_OUTPUT.PUT_LINE(SQLERRM);END;-- 构建创建表的语句V_SQL := 'CREATE TABLE ODS.'||X.TABLE_NAME||'(';-- 遍历 列 游标FOR Y IN C_COLUMNS(X.TABLE_NAME) LOOPV_DATA_TYPE := Y.DATA_TYPE;-- 处理精度和小数(number)IF Y.DATA_PRECISION IS NOT NULL THENV_DATA_TYPE := V_DATA_TYPE||'('||Y.DATA_PRECISION;IF Y.DATA_SCALE IS NOT NULL THENV_DATA_TYPE := V_DATA_TYPE ||','||Y.DATA_SCALE;END IF;V_DATA_TYPE := V_DATA_TYPE||')';ELSEV_DATA_TYPE := V_DATA_TYPE||'('||Y.DATA_LENGTH||')';IF Y.DATA_TYPE IN ('DATE','TIMESTAMP') THENV_DATA_TYPE := Y.DATA_TYPE;END IF;END IF;V_SQL := V_SQL||Y.COLUMN_NAME||' '||V_DATA_TYPE;V_SQL := V_SQL ||',';END LOOP;V_SQL := SUBSTR(V_SQL,1,LENGTH(V_SQL)-1);V_SQL := V_SQL||')';-- DBMS_OUTPUT.PUT_LINE(V_SQL);EXECUTE IMMEDIATE V_SQL;-- 给字段添加注释FOR V IN C_COL_COMMENTS(X.TABLE_NAME) LOOPV_COMMENT_SQL := 'COMMENT ON COLUMN ODS.'||X.TABLE_NAME||'.'||V.COLUMN_NAME||' IS' ||''''||V.COMMENTS||'''';EXECUTE IMMEDIATE V_COMMENT_SQL;END LOOP;END LOOP;END;
数据导入
从DB用户(数据源)导入到ODS(贴源层)
DECLARE-- 获取DB用户的表名CURSOR C_TABLES IS SELECT TABLE_NAME FROM DBA_TABLES WHERE OWNER = 'DB';V_SQL VARCHAR2(2000);
BEGINFOR V IN C_TABLES LOOPV_SQL := 'INSERT INTO ODS.'||V.TABLE_NAME ||' SELECT * FROM'||' DB.'||V.TABLE_NAME;EXECUTE IMMEDIATE V_SQL;END LOOP;END;
分析建表的PLSQL
获取DB用户的所有表>>dba_table视图
SELECT table_name
FROM dba_tables
WHERE owner = 'DB';
获取表的字段>>DBA_TAB_COLUMNS 视图
SELECT * FROM DBA_TAB_COLUMNS
WHERE OWNER = 'DB' AND TABLE_NAME = 'CI_CIE_CORP_CUST_INFO';
获取表字段的注释>> DBA_COL_COMMENTS视图
SELECT * FROM DBA_COL_COMMENTS
WHERE OWNER = 'DB' AND TABLE_NAME = 'CI_CIE_CORP_CUST_INFO';
建表数量多>>使用PLSQL批量创建表结构
PLSQL的结构
DECLARE--变量声明
BEGIN--执行语句
EXCEPTION--异常处理
END;
declare部分
先在DECLARE部分声明变量>>变量: 表名; 表的字段; 字段的注释>>需要用游标遍历>>声明3个游标
声明游标
字段的游标需要一个参数把表名传递进去; (P_TABLE VARCHAR2)
注释的游标需要一个参数把字段传递进去; (P_TABLE VARCHAR2)
注: 虽然参数名称相同,但是属于两个不同的游标,不会发生冲突
注意数据库之间的区别: 高斯数据库带参数的游标用不了;oracle可以
表名游标只需要获取表名, 过滤条件where OWNER = 'DB'
字段游标需要获取的信息是:
TABLE_NAME(字段所属的表)
,COLUMN_NAME(字段名称)
,DATA_TYPE(数据类型)
,DATA_LENGTH(数据长度)
,DATA_PRECISION(精度,即number数据类型的最大存储长度)
,DATA_SCALE(number数据类型的小数点保留位数)
过滤条件: WHERE OWNER = 'DB' AND TABLE_NAME = P_TABLE
注释游标需要获取的信息:
COLUMN_NAME(注释名称)
,COMMENTS(注释)
过滤条件: WHERE OWNER = 'DB' AND TABLE_NAME = P_TABLE
声明变量:
V_SQL VARCHAR2(2000); --变量: 建表sql
V_DATA_TYPE VARCHAR2(2000); -- 变量: 字段类型
V_COMMENT_SQL VARCHAR2(2000); -- 变量: 构建 添加字段注释的脚本
begin部分
遍历表游标
FOR X IN C_TABLES LOOPBEGIN -- 如果表存在则删除EXECUTE IMMEDIATE 'DROP TABLE ODS.'||X.TABLE_NAME ||' PURGE';EXCEPTION WHEN OTHERS THENDBMS_OUTPUT.PUT_LINE(SQLERRM);END;-- 构建创建表的语句V_SQL := 'CREATE TABLE ODS.'||X.TABLE_NAME||'(';
用 for 循环遍历表名游标>> 游标值传递给变量X
处理如果表存在的情况>>嵌套一个PLSQL,用来删除表
EXECUTE IMMEDIATE 用来执行动态sql
删除表的sql 语句: DROP TABLE 表名
在表名之前加用户名ODS, 以防止脚本被非ODS用户执行时误删该用户的表
|| 字符串连接符, 可以将变量值与静态文本一起连接,以构建完整的 SQL 语句
purge关键字的作用:
指示数据库立即从数据库的回收站(Recycle Bin)中删除表,而不是将表放入回收站以供后续恢复。
>>避免回滚错误表数据
WHEN OTHERS THEN
:异常处理子句
DBMS_OUTPUT.PUT_LINE 是oracle的输出语句
SQLERRM
是一个预定义的变量,它包含了最近一次 SQL 错误的错误消息。
DBMS_OUTPUT.PUT_LINE(SQLERRM);可以让开发者在 SQL Developer等数据库客户端工具中看到被捕获的错误信息
给建表变量赋值 '建表语句' V_SQL := 'CREATE TABLE ODS.'||X.TABLE_NAME||'(';
建表sql示例(不是建表PLSQL里的):
CREATE TABLE employees (emp_id NUMBER(6) name VARCHAR2(50), phone_number CHAR(15), hire_date DATE, salary NUMBER(8, 2), );
遍历字段游标
FOR Y IN C_COLUMNS(X.TABLE_NAME) LOOP
用for循环遍历字段游标, 用参数 X.TABLE_NAME 传递表名,把游标值传递给变量Y
上一个游标(表游标)的遍历后赋值给变量X, 而TABLE_NAME是X的数据域
V_DATA_TYPE := Y.DATA_TYPE;
把Y变量的DATA_TYPE的这个数据域赋值给变量 V_DATA_TYPE
即把字段游标的DATA_TYPE数据赋值给变量 V_DATA_TYPE
IF Y.DATA_PRECISION IS NOT NULL THENV_DATA_TYPE := V_DATA_TYPE||'('||Y.DATA_PRECISION;IF Y.DATA_SCALE IS NOT NULL THENV_DATA_TYPE := V_DATA_TYPE ||','||Y.DATA_SCALE;END IF;V_DATA_TYPE := V_DATA_TYPE||')';ELSEV_DATA_TYPE := V_DATA_TYPE||'('||Y.DATA_LENGTH||')';IF Y.DATA_TYPE IN ('DATE','TIMESTAMP') THENV_DATA_TYPE := Y.DATA_TYPE;END IF;
END IF;
用if 语句处理数据类型的精度(最大存储长度)和保留小数点数, 即 DATA_PRECISION 和 Y.DATA_SCALE
IF Y.DATA_PRECISION IS NOT NULL 为 ture
即 数据类型是number类型
格式: number(最大存储长度)或 number(最大存储长度, 保留小数位数)
>>需要在数据类型后面拼接存储长度(Y.DATA_PRECISION)
IF Y.DATA_SCALE IS NOT NULL 即进一步判断number类型有没有被定义保留小数位的位数,
ture >>重新给变量V_DATA_TYPE 赋值, 即在原来已经拼接了精度的基础上拼接保留小数位的位数(Y.DATA_SCALE)
注意: number数据类型的精度和保留小数位之间是用逗号隔开, 需要拼接逗号
最后拼接右括号)
IF Y.DATA_PRECISION IS NOT NULL 为 false
即 数据类型是不是 number类型, 即属于 char(n) 和 varcahr(n) 和 date 等
给变量数据类型 拼接数据长度变量>>V_DATA_TYPE||'('||Y.DATA_LENGTH||')';
用 if 进一步判断变量数据类型是否属于'DATE','TIMESTAMP'这两个数据类型>>这两个类型不需要定义长度
V_SQL := V_SQL||Y.COLUMN_NAME||' '||V_DATA_TYPE;V_SQL := V_SQL ||',';
给建表变量(V_SQL)重新赋值>>在原基础上拼接了字段名变量和字段类型变量和逗号
变量V_SQL的第一次赋值如下
V_SQL := 'CREATE TABLE ODS.'||X.TABLE_NAME||'(';
现在加上拼接后
V_SQL := 'CREATE TABLE ODS.'||X.TABLE_NAME||'('||Y.COLUMN_NAME||' '||V_DATA_TYPE||','
即create tabel ODS.表名(字段名称 数据类型,
END LOOP;
V_SQL := SUBSTR(V_SQL,1,LENGTH(V_SQL)-1);V_SQL := V_SQL||')';
END LOOP;是字段游标循环的结束
建表语句中,最后一个字段的数据类型后面不需要逗号, 使用substr函数去掉最后一个逗号,在给变量 V_SQL拼接右括号
最后建表语句完成
create tabel ODS.表名(字段名称 数据类型, ......)
-- DBMS_OUTPUT.PUT_LINE(V_SQL);
EXECUTE IMMEDIATE V_SQL;
用oracle的输出语句打印出建表变量V_SQL的实际拼接结果, 以检查是否正确>>验证后注释掉
动态执行建表变量V_SQL
遍历注释游标
-- 给字段添加注释FOR V IN C_COL_COMMENTS(X.TABLE_NAME) LOOPV_COMMENT_SQL := 'COMMENT ON COLUMN ODS.'||X.TABLE_NAME||'.'||V.COLUMN_NAME||' IS' ||''''||V.COMMENTS||'''';EXECUTE IMMEDIATE V_COMMENT_SQL;END LOOP;END LOOP;END;
用for循环遍历注释游标C_COL_COMMENTS, 给游标传递的参数是表名X.TABLE_NAME
在循环里面给注释变量V_COMMENT_SQL赋值,赋值内容是添加注释的sql
oracle给表中的列添加注释的语法是
表名, 列名是变量
注释内容需要单引号, 单引号需要转义, 转义符号 ' >> 4个单引号, 最外层的一对单引号是引用字符串的单引号, 里面的一对单引号,一个是要拼接的单引号,一个是转义字符
第一个结束的循环是注释游标循环的结束, 第二个结束的循环是表游标循环的结束
end 是PLSQL的结束标志