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)
  • 相关阅读:
    ZipArchive 的使用
    Bootstrap使用心得
    SQL SERVER 级联删除
    ASP.NET 使用C#代码设置页面元素中的样式或属性
    GDI+中发生一般性错误之文件被占用
    .Net 中资源的使用方式
    一张图全解析个性化邮件那么重要
    看天猫EDM营销学企业EDM营销
    细数EDM营销中存在的两大盲点
    如何进行EDM邮件内容的撰写
  • 原文地址:https://www.cnblogs.com/highriver/p/2689325.html
Copyright © 2011-2022 走看看