ODPS视图使用方案研究


ODPS视图使用方案研究

视图(View)是在表之上建立的虚拟表,它的结构和内容都来自表。一个视图可以对应一个表或多个表。如果您想保留查询结果,但不想创建表占用存储,可以通过视图实现。

基础视图

语法

create [or replace] view [if not exists] view_name
[(col_name [comment col_comment], ...)]
[comment view_comment]
[as select_statement]

说明:

  • 创建视图时,必须有对视图所引用表的读权限。目前提供的视图不是物化视图,执行时会访问视图引用表的数据。需要注意,引用表的权限的变更会影响视图的访问。
  • 视图只能包含一个有效的select语句。
  • 视图可以引用其他视图,但不能引用自己,也不能循环引用。
  • 不可以向视图写入数据。例如:使用insert into或者insert overwrite操作视图。
  • 当视图建好以后,如果视图的引用表发生了变更,有可能导致视图无法访问。例如:删除被引用表。用户需要自己维护引用表及视图之间的对应关系。
  • 如果没有指定if not exists,在视图已经存在时用create view会导致异常。这种情况可以用 create or replace view来重建视图,重建后视图本身的权限保持不变。

样例

-- 1. 创建视图
create view if not exists sale_detail_view (
      store_name  comment '门店名称'
    , customer_id comment '客户ID'
    , price comment '价格'
    , sale_date comment '销售日期'
    , region comment '所属区域'
) comment 'a view for table sale_detail'
as 
select store_name 
    , customer_id
    , price
    , sale_date
    , region
from sale_detail
;

-- 2. 重命名视图
alter view view_name rename to new_view_name;

-- 3. 删除视图
drop view if exists sale_detail_view;

-- 4. 修改视图的所有人
alter view <view_name> changeowner to <new_owner>;

-- 5. 查看视图
desc sale_detail_view;

参数化视图

ODPS(MaxCompute) 里面也有一个阉割版的存储过程—参数化视图。我们知道视图是将固定的计算逻辑存储下来,通过调用视图简化代码。而参数化视图就是可以在视图代码里调用入参变量,从而达到更灵活的使用视图,一个通用逻辑供多种场景使用。

语法

create [or replace] [if not exists] <view_name>( <variable_name> <variable_type> [, <variable_name> <variable_type> ...])
[returns <return_variable> table (<col_name> <col_type> comment <col_comment> [,<col_name> <col_type> comment <col_comment>])]
[comment <view_comment>]
as
{<select_statement> | begin <statements> end}

说明:

  • view_name:必填。视图名称。
  • variable_name:必填。视图变量名称。
  • variable_type:必填。视图变量参数类型。
  • return_variable:可选。视图返回的变量名称。
  • col_name:可选。视图返回列的名称。
  • col_type:可选。视图返回列的类型。
  • col_comment:可选。视图返回列的注释。
  • view_comment:可选。视图的注释。
  • select_statement:条件必选。select子句。
  • statements:条件必选。视图脚本。

样例

-- 1. 创建视图案例-固定返回格式
create or replace view test_view1 (
    -- 入参 (可以是任意类型任意个数)
    @input_a table (
          ida string comment '主键'
        , name  string comment '姓名'
        , * ANY -- 必须大写
    ),
    @input_b table (
          idb string comment '主键'
        , class string comment '班级'
        , * ANY  -- 必须大写
    ),
    @www string comment '其他参数'
)
-- 定义固定出参类型
returns @res table (
     web     string comment '网站'
    ,id      string comment '主键'
    ,name    string comment '姓名'
    ,class   string comment '班级'
)
comment '测试视图_固定返回'
as 
select @www as web
    , a.ida
    , a.name
    , b.class
from @input_a a -- 例子里的表都是入参,也可以是指定的表名
join @input_b b on a.ida = b.idb
;

-- 2. 调用视图案例
-- 准备数据
with tmp_a as (
    select '1' as ida,'Rick' as name,'30' as age
)
,tmp_b as(
    select '1' as idb,'A' as class,'SH' as city
)
-- 调用视图
select * from test_view1(tmp_a,tmp_b,'TEST1');

-- 3. 创建视图案例-不定返回格式
create or replace view test_view2 (
    -- 入参 (可以是任意类型任意个数)
    @input table (
        * ANY
    ),
    @www string comment '其他参数'
)
as 
select @www as web
    , *
from @input
;

-- 4. 调用视图案例
select * from test_view2((select '1' as ida,'Rick' as name,'30' as age),'TEST2');

根据排序字段进行排序

-- 创建视图
create or replace  view orderbyfirstcol(
    @a table(
        columnfororder bigint,
        * ANY
    )
) 
as 
select `(columnfororder)?+.+` 
from (
    select * from @a order by columnfororder desc
) t
;

-- 调用示例
with base as (
    select 1 id, 'test1' name,'I' opt,131012310 dts_time union all
    select 1 id, 'odps' name,'U' opt ,131012316 dts_time union all
    select 2 id, 'test2' name,'I' opt,131012318 dts_time union all
    select 3 id, 'test3' name,'I' opt,131012357 dts_time
),
src as (
    select dts_time as dd, * from base
)
select * from orderbyfirstcol(src);

根据主键合并数据

经常有用户误用参数化视图,将参数化视图的参数当做是宏替换参数来使用。这里说明一下。参数化视图实际上是函数调用,而不是宏替换。

列表达式使用正则表达式可参考SELECT语法介绍>列表达式关于正则表达式的说明

-- 创建合并视图
-- params: @tb1 需要合并的表1
-- params: @tb2 需要合并的表2
-- params: tb__pk1 表的主键,如果是联合主键,建议MD5(CONCAT(PK1,[PK2,[...]]))
-- params: tb__sort_col 排序字段,这里用时间戳的数字类型,根据实际的情况,进行对应调整
create or replace view tools__odps_table_union_all (
    @tb1 table (
        tb__pk1 string,
        tb__sort_col string,
        * ANY 
    ),
    @tb2 table (
        tb__pk1 string,
        tb__sort_col string,
        * ANY
    )
) as
select `(tb__pk1|tb__sort_col|rn)?+.+` 
from (
    select *
        , row_number() over(distribute by tb__pk1 sort by tb__sort_col desc) as rn
    from (
        select * from @tb1
        union all
        select * from @tb2
    )
)
where rn=1
;

-- 合并全表逻辑
with base as (
    select md5(concat(__PK_ID__)) as tb__pk1
        , '00' as tb__sort_col
        , a.*
        , 0 as new_dts_sync_record_id
        , 'I' as new_dts_sync_operation_flag
        , 0 as new_dts_sync_utc_timestamp
        , 'N' as new_dts_sync_before_flag
        , 'Y' as new_dts_sync_after_flag
    from __TABLE_NAME___base a
),
log as (
    select md5(concat(__PK_ID__)) as tb__pk1
        , concat(new_dts_sync_record_id,case when new_dts_sync_after_flag='Y' then '1' else '0' end) as tb__sort_col
        , `(new_dts_sync_.*)?+.+`
        , new_dts_sync_record_id
        , new_dts_sync_operation_flag
        , new_dts_sync_utc_timestamp
        , new_dts_sync_before_flag
        , new_dts_sync_after_flag
    from __TABLE_NAME___log
)
select *
from tools__odps_table_union_all(base,log)
-- where new_dts_sync_after_flag='Y'
;

-- 调用视图案例
with src1 as (
    select 1 id,1 pid, 'test1' name,'I' opt,131012310 dts_time union all
    select 1 id,1 pid, 'odps' name,'U' opt ,131012316 dts_time union all
    select 2 id,1 pid, 'test2' name,'I' opt,131012318 dts_time union all
    select 3 id,1 pid, 'test3' name,'I' opt,131012357 dts_time
),
src2 as (
    select 2 id,1 pid, 'test1' name,'D' opt,131012411 dts_time union all
    select 3 id,1 pid, 'odps' name,'U' opt ,131015123 dts_time union all
    select 4 id,1 pid, 'test4' name,'I' opt,131017318 dts_time
),
base as (
    select md5(concat(id,pid)) as tb__pk1
        , cast(dts_time as string) as tb__sort_col
        , * 
    from src1
),
log as (
    select md5(concat(id,pid)) as tb__pk1
        , cast(dts_time as string) as tb__sort_col
        , * 
    from src2
)
select *
from tools__odps_table_union_all(base,log)
;

文章作者: darebeat
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 darebeat !
 上一篇
ODPS-SQL优化总结 ODPS-SQL优化总结
在数据处理和数据分析过程中,SQL都是主流的数据处理工具。海量数据下的高效数据流转,是数据方向必须直面的一个挑战。
2022-12-02
下一篇 
ODPS重点参数语法-使用小记 ODPS重点参数语法-使用小记
在日常工作中,记录一些用到阿里云odps的常用的参数语法,记录一下,方便查找和定位。
2022-06-17
  目录