postgres类似oracle的decode实现

假设存在下面二张表

t_media:

mediaid   flags

11111    1<<17

22222    1<<18

33333    1<<17

44444    1<<2

t_media_locations:

mediaid  locationid

11111  999999

22222  999999  

33333    999999

现在有一个需求需要统计locationid=999999下面flags=1<<17和flag=1<<18的media数量,最初的丑陋实现如下:

SELECT
    a_tmp.locationid,a_tmp.attraction_count,r_tmp.restructant_count
FROM
    (
        SELECT
            COUNT(1)AS attraction_count,
            tmp.locationid
        FROM
            (
                SELECT
                    A . ID,
                    b.locationid
                FROM
                    t_media A,
                    t_media_locations b
                WHERE
                    A . ID = b.mediaid
                AND b.locationid IN(999999)
                AND A .flags & 134217728 > 0
                GROUP BY
                    A . ID,
                    b.locationid
            )tmp
        GROUP BY
            tmp.locationid
    )AS a_tmp,
    (
        SELECT
            COUNT(1)AS restructant_count,
            tmp.locationid
        FROM
            (
                SELECT
                    A . ID,
                    b.locationid
                FROM
                    t_media A,
                    t_media_locations b
                WHERE
                    A . ID = b.mediaid
                AND b.locationid IN(999999)
                AND A .flags & 268435456 > 0
                GROUP BY
                    A . ID,
                    b.locationid
            )tmp
        GROUP BY
            tmp.locationid
    )AS r_tmp
WHERE
    a_tmp.locationid = r_tmp.locationid


如此多的联表,性能肯定很差,改进如下:

SELECT
sum ( CASE WHEN (flags & 268435456 > 0)  THEN 1 ELSE 0 END ),sum ( CASE WHEN (flags & 134217728 > 0)  THEN 1 ELSE 0 END ),b.locationid
FROM
    t_media a,
    t_media_locations b
WHERE
    a.id= b.mediaid
AND b.locationid IN(99999)
and a.flags is not null
group by b.locationid


小结:

1.如果不需要locationid,group by的操作也可以省略,注意,聚合函数本身针对多记录操作并不一定是group by之后才使用,group by分组记录也是多记录。所以聚合函数使用的字段不需要出现在group by里。但是如果是直接select字段,postgres就需要group by该字段,有的db是不需要的比如sql lite.

2.postgres对于oracle中的decode函数的替代:CASE WHEN .....

3.flag这样的type类型值在db中直接存储为int,postgres的位与运算符&可以直接计算。

4.count(expr)如果expr是一个boolean值,count会被误用。

错误的使用方式:

SELECT
--错误的统计行数的方式
count((flags & 134217728 > 0) )
FROM
    t_media a,
    t_media_locations b
WHERE
    a.id= b.mediaid
AND b.locationid IN(999999)

正确的方式就是case when使用之后sum:

SELECT
sum( CASE WHEN (flags & 134217728 > 0)  THEN 1 ELSE 0 END )
FROM
    t_media a,
    t_media_locations b
WHERE
    a.id= b.mediaid
AND b.locationid IN(999999)

 

 

 

PostgreSQL使用基于约束的分区来实现分区表,它是通过使用约束来实现分区的,每个分区都有一个唯一约束来限制分区键的范围。在查询时,PostgreSQL会将查询转化为对特定分区的查询,以提高查询效率。 在底层实现方面,PostgreSQL使用了一个称为“继承”的机制来实现分区表。继承是一种将属性从一个表传递到另一个表的机制。在继承关系中,子表继承了父表的属性,并且可以添加自己的属性。 在分区表中,每个分区都是一个子表,它继承了父表的所有属性,并且添加了自己的约束。当我们向分区表中插入数据时,PostgreSQL会根据数据的分区键值,将数据插入到相应的分区子表中。当我们查询分区表时,PostgreSQL会将查询转化为对特定的分区子表的查询,以提高查询效率。 例如,我们可以创建一个分区表sales,它是按照销售日期进行分区的,每个分区子表都继承了sales表的所有属性,并且添加了自己的约束。当我们插入数据时,PostgreSQL会根据数据的销售日期,将数据插入到相应的分区子表中。当我们查询数据时,PostgreSQL会将查询转化为对特定的分区子表的查询,以提高查询效率。 下面是一个示例,演示分区表的底层实现: ``` CREATE TABLE sales ( sale_id bigint, sale_date date, sale_amount numeric ); CREATE TABLE sales_q1_2020 ( CONSTRAINT sales_q1_2020_check CHECK (sale_date >= '2020-01-01' AND sale_date < '2020-04-01') ) INHERITS (sales); CREATE TABLE sales_q2_2020 ( CONSTRAINT sales_q2_2020_check CHECK (sale_date >= '2020-04-01' AND sale_date < '2020-07-01') ) INHERITS (sales); CREATE TABLE sales_q3_2020 ( CONSTRAINT sales_q3_2020_check CHECK (sale_date >= '2020-07-01' AND sale_date < '2020-10-01') ) INHERITS (sales); CREATE TABLE sales_q4_2020 ( CONSTRAINT sales_q4_2020_check CHECK (sale_date >= '2020-10-01' AND sale_date < '2021-01-01') ) INHERITS (sales); ``` 在这个示例中,我们创建了一个父表sales和四个子表,每个子表都继承了sales表的所有属性,并且添加了自己的约束。当我们向sales表中插入数据时,PostgreSQL会根据数据的销售日期,将数据插入到相应的分区子表中。当我们查询数据时,PostgreSQL会将查询转化为对特定的分区子表的查询,以提高查询效率。 总的来说,分区表的底层实现使用了继承机制来实现分区表的分区和查询优化。这种机制可以有效地组织和管理大量的数据,提高查询效率和可扩展性。但是需要注意的是,使用分区表也会带来一些额外的管理和维护的负担。需要在权衡利弊之后,谨慎选择是否使用分区表。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值