暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

浅析 SQL 数据分析题目——统计表状态列数据情况

SQL干货分享 2021-08-13
820

(CSDN博主:写代码也要符合基本法)
南北大街东西走,十字街头人咬狗
捡起狗来砍砖头,倒叫砖头咬了手
有个老头刚十九,嘴里喝藕就着酒
打小没见过这档事儿,三蹦子拉着火车走

各位看官老爷大家早上好,我是你们的老㲻计小刘。起今天推文的题目可是难坏了我,琢磨来琢磨去也没想出精练准确的标题,唉,没文化是硬伤啊
今天的题目源自前几天,展老师说要出题考考我,他道茴字有四种写法,问我可知道?他说题目是这样的,在一张表里有个状态列,该列的值有多种可能,且会动态的变化。其中有一个状态 S 是受到关注的,现在想要知道的事情是,用一个 SQL 得出表里的数据到底都是 S 状态的,还是既有 S 也有其它状态的,还是没有 S 状态的?
这个需求在小刘看来是一个组合型的需求,比如较此更为简单的有:如何甄别表里是否有 S 状态的数据
高明的老爷们看到这个问题,都会想到用 COUNT,细心的老爷还会加上一句用 ROWNUM = 1 可以优化效率
    SELECT COUNT(1)
    FROM demo_transactions
    WHERE status = 'S'
       AND rownum = 1;
    结果为 1 表示有,结果为 0 表示没有
    但是结果为 1 的时候,其实还说不明白到底表里都是 S 状态的,还是说也有别的状态的
    展老师出的考题,就是不满足于上面这种简单的判断,表里是不是全都是 S 状态的数据对他来说很重要
    当然想看看表里有没有非 S 状态的数据,只消把上面的 SQL 改成 status != 'S' 罢了
    可展老师说的是用一个 SQL 来统计,他还强调这很重要,因为这个 SQL 将来可能只是一个更大的 SQL 里面的一个 DECODE

    然而勇敢小刘,不怕困难!两个 SELECT 合成一个,还不算难事:UNION ALL 起来,外面再 SUM 一下便是
    如此这两个 SQL 也不能用 COUNT 了,因为 SUM 出来是 1,判断不出来是哪个的 1
    这里我们回头想一下为什么用 COUNT,其实是基于 PL/SQL 块的一个默认背景了,用聚合函数不会发生 NO_DATA_FOUND 报错;如今我们本来就是放在 SQL 里面用,所以可以去掉 COUNT,取而代之的是两个“写死”的数,以便 SUM 出来的要么是它俩的和,要么是其中一个值,便于判断
      SELECT nvl(SUM(c), 0) c
      FROM (SELECT 1 c
      FROM demo_transactions
      WHERE status = 'S'
      AND rownum = 1
      UNION ALL
      SELECT 2 c
      FROM demo_transactions
      WHERE status != 'S'
      AND rownum = 1);
      老爷们请看这个 SQL 是不是就很妙,当结果为 0,那说明表是空的;1 说明表里全是 S 状态的;2 说明表里全不是 S 状态的;3 说明表里既有 S 状态的,也有别的状态的

      展老师看了这个答案,甚是欣慰,感觉小刘是个可教之才,于是他趁兴又问我,如果再加一个关注的状态呢,比如 N
      我说,你就没有正经事要做吗
      我说:好说好说
      展老师:来吧,展示
        SELECT nvl(SUM(c), 0) c
        FROM (SELECT 1 c
        FROM demo_transactions
        WHERE status = 'S'
        AND rownum = 1
        UNION ALL
        SELECT 2 c
        FROM demo_transactions
        WHERE status = 'N'
        AND rownum = 1
        UNION ALL
        SELECT 4 c
        FROM demo_transactions
        WHERE status NOT IN ('S', 'N')
        AND rownum = 1);

        大家注意,这次我用的组合是 1、2、4,为什么不是 1、2、3 呢?因为 1 加 2 等于 3,和只有 3 的情况分不开了
        小刘既然发推吹牛了,原因自然不会这么简单。其实这里面蕴含着深刻的道理,这个道理允许我们不断地增加更多关注的状态值
        1、2、4 分别是 2 的 0 次方、1 次方和 2 次方,也就是说它们分别是二进制数字个、十、百位转十进制的结果
        那么将来有了更多想要关注的状态后,每个状态 UNION ALL 的 SELECT 就是 1、2、4、8...最后那个 NOT IN 这些状态的 SELECT 就是前一个数再乘 2
        这样做就能避免某几个数的和不正好等于一个更大的数了吗?答案是肯定的,因为
        上面结论又是由如下公式得出的
        该公式可由归纳演绎法推理,但其实回归到二进制也可以逆向解释一波:二进制里每加一就进位,2 的 n 次方正是 n + 1 位,它本来要在前面的位都是 1 时,再加一才进位到它

        那么问题又来了,就不能是某两个数的和等于另几个数的和吗,比如 A + B = C + D,C 比 A 小点,D 比 B 大点
        不可能,还是不可能
        回归到二进制来说,我们做的其实是二进制转十进制的工作,任何一个子查询的结果都影响的是一个数位的 0 或 1,最终肯定不会造成重复,请大家放心使用
        感谢@风语供稿,改编自真实事件,为文章效果有艺术创作成分

        文章转载自SQL干货分享,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

        评论