zoukankan      html  css  js  c++  java
  • 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)
  • 相关阅读:
    前端笔试题----JavaScript部分
    前端笔试题----html,css部分
    JS基础--执行环境及作用域
    关于css3 flex布局
    Ceph万兆内网与系统万兆迁移
    从0开始的InfiniBand硬件踩坑过程
    Redis实战与分析
    ceph osd 自动挂载的N种情况
    集群IPtables转发与防火墙
    ceph 常见问题百科全书---luminous安装部署篇
  • 原文地址:https://www.cnblogs.com/highriver/p/2689325.html
Copyright © 2011-2022 走看看