视频监控在线时长统计SQL

-- 当天的所有记录
with data_today_rn as (
    select 
         t1.id
        ,t1.occur_time
        ,t1.device_id
        ,t1.event_type
        ,row_number() over(partition by t1.device_id order by t1.occur_time asc ,t1.id asc ) as rn_asc
        ,row_number() over(partition by t1.device_id order by t1.occur_time desc,t1.id desc) as rn_desc
    from ODS_VIDEO_DEVICE_EVENT t1
    where to_date(occur_time) = '2021-11-18'
        and event_type in ('上线','离线')
        -- and t1.device_id = '3a001506-9646-c4fd-825b-5b404eac6d47'
) -- 当天所有记录
,data_cnt_online_offline as (
    select 
         device_id
        ,count(case when event_type = '上线' then 1 end) as cnt_online
        ,count(case when event_type = '离线' then 1 end) as cnt_offline
    from data_today_rn
    group by 
         device_id
) -- 统计当天上线和离线次数
,data_relevance_filter as (
    select 
         t1.id
        ,t2.id         as t2_id
        ,t1.occur_time
        ,t2.occur_time as t2_occur_time
        ,t1.device_id
        ,t2.device_id  as t2_device_id
        ,t1.event_type
        ,t2.event_type as t2_event_type
        ,t1.rn_asc
        ,t2.rn_asc     as t2_rn_asc
        ,t1.rn_desc
        ,t2.rn_desc    as t2_rn_desc
        ,round((cast(cast(t2.occur_time as timestamp) as bigint) - cast(cast(t1.occur_time as timestamp) as bigint)) / 3600,4) as hour_diff
        ,round((cast(cast(t2.occur_time as timestamp) as bigint) - cast(cast(concat(to_date(t2.occur_time),' 00:00:00') as timestamp) as bigint)) / 3600,4) as hour_diff_first
        ,round((cast(cast(concat(date_add(to_date(t1.occur_time),1),' 00:00:00') as timestamp) as bigint) - cast(cast(t1.occur_time as timestamp) as bigint)) / 3600,4) as hour_diff_end
        ,case 
            when t2.rn_asc = 1  and t2.event_type = '离线' then '第一条是离线'
            when t1.rn_desc = 1 and t1.event_type = '上线' then '最后一条是上线'
            else '上线离线'
        end as flag
    from data_today_rn t1
    full join data_today_rn t2
        on t1.device_id = t2.device_id and (t1.rn_asc + 1 ) = t2.rn_asc
    where (t1.event_type = '上线' and t2.event_type = '离线')
        or (t2.rn_asc = 1  and t2.event_type = '离线') -- 第一条是离线
        or (t1.rn_desc = 1 and t1.event_type = '上线') -- 最后一条是上线
) -- 将两条记录错位关联,并过滤数据
-- select * from data_relevance_filter order by nvl(device_id,t2_device_id),nvl(rn_asc,t2_rn_asc) ;
,data_the_day_etl as (
    select
         to_date(nvl(occur_time,t2_occur_time)) as day
        ,nvl(id,t2_id) as id
        -- ,t2_id
        -- ,occur_time
        -- ,t2_occur_time
        ,nvl(device_id,t2_device_id) as device_id
        -- ,event_type
        -- ,t2_event_type
        ,nvl(rn_asc,0) as rn_asc
        -- ,t2_rn_asc
        -- ,nvl(rn_desc,0) as rn_desc
        -- ,t2_rn_desc
        ,case 
            when flag = '第一条是离线'   then hour_diff_first
            when flag = '最后一条是上线' then hour_diff_end
            else hour_diff
        end as hour_diff_fix
        -- ,hour_diff
        -- ,hour_diff_first
        -- ,hour_diff_end
        ,flag
    from data_relevance_filter
) -- 根据标签计算出记录的上线时长
-- select * from data_the_day_etl order by device_id,rn_asc;
,data_the_day_cnt as (
    select 
         day
        ,device_id
        ,sum(hour_diff_fix) as hour_diff_sum
    from data_the_day_etl
    group by 
         day
        ,device_id
) -- 统计当天记录的设备的上线时长
-- select * from data_the_day_cnt;
,data_the_day_befor as (
    select 
         '2021-11-18' as day
        ,device_id
        ,case 
            when event_type = '上线' then 24
            when event_type = '离线' then 0
        end as hour_diff
    from (
        select
             t1.id
            ,t1.occur_time
            ,t1.device_id
            ,t1.event_type
            ,row_number() over(partition by t1.device_id order by t1.occur_time desc) as rn
        from ODS_VIDEO_DEVICE_EVENT t1
        where to_date(occur_time) < '2021-11-18'
            and event_type in ('上线','离线')
    ) t2
    where t2.rn = 1
) -- 当天之前的最后一条记录
-- select * from data_the_day_befor;
,data_device_online_duration as (
    select
         nvl(t1.day,t2.day)                 as day
        ,nvl(t1.device_id,t2.device_id)     as device_id
        ,nvl(t1.hour_diff_sum,t2.hour_diff) as hour_diff
    from data_the_day_cnt t1
    full join data_the_day_befor t2
        on t1.device_id = t2.device_id and t1.day = t2.day
) -- 统计当天的上线时长
-- select * from data_device_online_duration limit 100;
,data_device_project_mapping as (
    select 
         t2.id
        ,t2.device_id
        ,t2.proj_id
    from (
        select
             t1.id
            ,t1.device_id
            ,t1.proj_id
            ,row_number() over(partition by t1.device_id order by t1.occur_time asc ,t1.id asc) as rn 
        from ODS_VIDEO_DEVICE_EVENT t1
        where nvl(t1.proj_id,'') <> ''
    ) t2
    where t2.rn = 1
) -- 设备项目映射表
-- select * from data_device_project_mapping;
insert overwrite table dwd_fact_video_device_event partition (etl_dt)
select
     t1.day
    ,t1.device_id
    ,t1.hour_diff
    ,t3.cnt_online
    ,t3.cnt_offline
    ,t2.proj_id
    ,t2.proj_name
    ,t2.corp_id
    ,t2.corp_name
    ,current_timestamp() as etl_timestamp
    ,t1.day              as etl_dt
from data_device_online_duration t1
left join (
    select 
         t21.device_id
        ,t21.proj_id
        ,t22.name as proj_name
        ,t22.corp_id
        ,t23.name as corp_name
    from data_device_project_mapping t21
    inner join (select * from ODS_PROJECT where db_name = 'DB_NAME') t22
        on t21.proj_id = t22.id
    left join (select * from ODS_ORGANIZATION where db_name = 'DB_NAME') t23
        on t22.corp_id = t23.id
) t2
    on t1.device_id = t2.device_id
left join data_cnt_online_offline t3
    on t1.device_id = t3.device_id
;

原文地址:https://www.cnblogs.com/chenzechao/p/15692587.html