PostgreSQL不同表结构的表按主键合并之神操作

Posted liuxiaoddd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PostgreSQL不同表结构的表按主键合并之神操作相关的知识,希望对你有一定的参考价值。

这是一个很古老的问题,公司的研发人员也想了很久用了其他办法实现,但是效率非常低。

解释如下:

员工在8月份某天创建了多条拜访数据;

经理在8月份某天创建了多条拜访数据;

经理在8月份某天创建了多条协访数据;

拜访和协访存在于不同的表中,拜访是call,协访是coach_feedback。

现在要把这两张表的数据合并到一起,达到以下表头:

年月日,姓名,拜访次数,协访次数

 

拜访表:

日期姓名拜访次数
20190801A5
20190802A4
20190802B3
20190804B4

协访表:

日期姓名协访次数
20190802B1
20190803B3

目标表:

日期姓名拜访次数协访次数
20190801A50
20190802A40
20190802B31
20190803B03
20190804B40

 

由于前提必须需要以拜访为主表,所以假设某一天经理没做拜访只做了协访,导致这一天的数据无法抓取。

重点来了:

1. 实现思路是,首先通过union把拜访表和协访表绑定到一起,自己没有的那一列均设为0

2. 第一遍过滤是判断两个次数相加大于0,至少产生过一次拜访或者协访

3. 由于union之后假如某天经理既做了拜访又做了协访,会导致出现两条重复数据,

4. 通过max函数取出较大的值(只要大于0就会取有效值,否则就是0)配合group by达到去重的目的。

具体的SQL如下(字段并非完全匹配,重在理解):

SELECT
    user_id,
    month_day,
    MAX ( call_count ) call_count,
    MAX ( coach_count ) coach_count 

FROM
    (
            SELECT
                "call".OWNER :: BIGINT as  user_id,
                to_char( to_timestamp( call_date / 1000 ) + INTERVAL '8 hours', 'yyyy-mm-dd' ) as month_day,
                SUM ( CASE WHEN CALL.status is not null THEN 1 ELSE 0 END ) call_count,
                0 AS coach_count 
            FROM
                "call" 
            GROUP BY
                CALL.OWNER,
                month_day 
        UNION
        (
                SELECT
                    "coach_feedback".create_by :: BIGINT AS user_id,
                    to_char( to_timestamp( CAST ( coach_feedback.ext ->> 'sign_in_time' AS BIGINT ) / 1000 ) + INTERVAL '8 hours', 'yyyy-mm-dd' )  as month_day,
                    0 AS call_count,
                    SUM ( CASE WHEN coach_feedback.status IS NOT NULL THEN 1 ELSE 0 END ) coach_count 
                FROM
                    "coach_feedback" 
                GROUP BY
                    user_id,
                    month_day 
        ) 
    ) tmp_call_coach 
WHERE
    call_count + coach_count  > 0  
GROUP BY
    user_id,
    month_day

上面SQL跑出来的结果:

这个做完后,发现最简单的办法可能是通过user_info即人的总表来做full join,可能就不会有这么多弯弯,初步考虑是可行的,没有深挖,但是对当前问题来讲,是一个新的思路。

 

额外的收获:

A与B表union时,不能对两个表做order by 操作;

B表的列名会自动以A为准;

B表与A表必须结构一致至少列数一致;

union操作会自动根据相同的列且相同的值做合并,union all则会保留所有;

group by的引用其实除了sum还有max书本学的东西早都忘没了,妙用哉;

以上是关于PostgreSQL不同表结构的表按主键合并之神操作的主要内容,如果未能解决你的问题,请参考以下文章

两张结构相同的表合并到一起的sql语句

mysql中,2个不同数据,同一结构的表,如何合并数据

用SQL语句获得PostgreSQL表的主键

ClickHouse ,选择 top n 并按主键排序的问题

DataTable的MergeCOPYAcceptChange使用说明

使用 PostgreSQL 从许多表中选择并合并相同的属性