数仓搭建实操(传统数仓oracle):[构建数仓层次|ODS贴源层]

构建数仓层次/导入数据

创建五个用户用来分层,并直接赋予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) IS
   SELECT 
      TABLE_NAME
      ,COLUMN_NAME
      ,DATA_TYPE
      ,DATA_LENGTH
      ,DATA_PRECISION
      ,DATA_SCALE
    FROM DBA_TAB_COLUMNS 
    WHERE OWNER = 'DB' AND TABLE_NAME = P_TABLE;
    
    -- 获取所有的字段注释
    CURSOR C_COL_COMMENTS (P_TABLE VARCHAR2) IS
    SELECT 
       COLUMN_NAME
       ,COMMENTS
    FROM 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); -- 构建 添加字段注释的脚本
BEGIN
  FOR X IN C_TABLES LOOP
    
    BEGIN -- 如果表存在则删除
      EXECUTE IMMEDIATE 'DROP TABLE ODS.'||X.TABLE_NAME ||' PURGE';
     EXCEPTION 
       WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE(SQLERRM);
    END;
    
    -- 构建创建表的语句
    V_SQL := 'CREATE TABLE ODS.'||X.TABLE_NAME||'(';
    
    -- 遍历 列 游标
    FOR Y IN C_COLUMNS(X.TABLE_NAME) LOOP
      V_DATA_TYPE := Y.DATA_TYPE;
      -- 处理精度和小数(number)
      IF Y.DATA_PRECISION IS NOT NULL THEN
        V_DATA_TYPE := V_DATA_TYPE||'('||Y.DATA_PRECISION;
        
        IF Y.DATA_SCALE IS NOT NULL THEN
          V_DATA_TYPE := V_DATA_TYPE ||','||Y.DATA_SCALE;
        END IF;
        
        V_DATA_TYPE := V_DATA_TYPE||')';
      
      ELSE
        V_DATA_TYPE := V_DATA_TYPE||'('||Y.DATA_LENGTH||')';
        
        IF Y.DATA_TYPE IN ('DATE','TIMESTAMP') THEN
            V_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) LOOP
      V_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);
BEGIN
  FOR V IN C_TABLES LOOP
    V_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 LOOP
    
    BEGIN -- 如果表存在则删除
      EXECUTE IMMEDIATE 'DROP TABLE ODS.'||X.TABLE_NAME ||' PURGE';
     EXCEPTION 
       WHEN OTHERS THEN
          DBMS_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 THEN
    V_DATA_TYPE := V_DATA_TYPE||'('||Y.DATA_PRECISION;
        
        IF Y.DATA_SCALE IS NOT NULL THEN
          V_DATA_TYPE := V_DATA_TYPE ||','||Y.DATA_SCALE;
        END IF;
        
    V_DATA_TYPE := V_DATA_TYPE||')';
      
ELSE
    V_DATA_TYPE := V_DATA_TYPE||'('||Y.DATA_LENGTH||')';
        
        IF Y.DATA_TYPE IN ('DATE','TIMESTAMP') THEN
            V_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) LOOP
      V_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的结束标志

相关推荐
new出对象17 分钟前
数据库增删查改sql语句
数据库·sql·oracle
m0_7482466129 分钟前
超详细:数据库的基本架构
数据库·架构
Themberfue1 小时前
SQL ①-数据库 || MySQL
数据库·sql·mysql·数据库系统·数据库管理系统
Good Note1 小时前
Golang的静态强类型、编译型、并发型
java·数据库·redis·后端·mysql·面试·golang
RisingWave中文开源社区2 小时前
一文详解物化视图(MV):定义、优势和用例
数据库·sql·数据分析
PingCAP2 小时前
TiDB Chat2Query 深度解析:我们如何打造一款更高效、准确的智能 SQL 生成工具?
数据库
威哥爱编程2 小时前
如何解决 MySQL 数据库服务器 CPU 飙升的情况
数据库·mysql
vip1024p3 小时前
第二篇:MySQL安装与配置(基于小皮面板(phpstudy))
数据库·mysql·adb
limts3 小时前
Oracle中补全时间的处理
数据库·oracle