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)
  • 相关阅读:
    MongoDB Replica Set 选举过程
    转 Warning:MongoDB Replica Sets配置注意事项
    mongodb与内存
    mongodb的监控与性能优化
    php 5.5.1 编译安装过程
    java知识点积累(一)
    java内存及数据区
    static及静态方法
    接口和抽象类
    Java SE自学阶段的笔记整理
  • 原文地址:https://www.cnblogs.com/highriver/p/2689325.html
Copyright © 2011-2022 走看看