数据库语法总结(14)——杂项补充

今天这篇是我们数据库语法的最后一章,本章补充一些之前章节没有说到的知识点

1、行转列的结果集

我们在数据库语法总结(12)——报表的制作和整形-CSDN博客    的第1节中也提到了这项功能,不过我们现在要用一种新的函数来实现,pivot运算生成符语法为:pivot(聚合函数(展示字段) for  表头字段 in (可能出现的值)

select [1] as classno_1,
       [2] as classno_2,
       [3] as classno_3
from (select classno,c_num from tb_class) c
pivot(
    count(c.c_num)
    for c.classno in ([1],[2],[3])
)as classpivot

2、列转行的结果集

有行转列,那我们就会想到列转行,同样的有运算符unpivot,语法为:

SELECT 列名称,需定义的列1名称,需定义的列2名称 from 表名称 unpivot (需定义的列2名称 for 需定义的列1名称 in(列2值1,列2值2,列2值3))

select c_num,classno
from(select classno_1,
            classno_2,
            classno_3
    from tb_classpivot c
    unpivot(
        c.c_num
        for c.classno in ('classno_1','classno_2','classno_3')
    )as classunpivot
)

大概是这个意思,可能语法会有一些问题,我没有在数据库实际操作,想要深入了解也可以参考Oracle使用pivot和unpivot函数实现行列转换_oracle_脚本之家

3、 行列转换

关于行列转换其实还有很多的方法可以实现,像我们之前提到的

行转列:max和decode、pivot、case when和group by 等等

列转行:union all、unpivot、cillection(需要创建集合)、model(部分数据库后期提供的高级函数)

具体格式呢我们在这就不过多的解释了,我们对应掌握一两种就可以了,下面这位博主的文章介绍的很详细,大家可以参考:oracle中行列转换总结_oracle 行转列-CSDN博客

4、 查找当前年份的天数

我们之前 数据库语法总结(9)——操作日期 中的第2节已经讲述过这个问题,我们在这列举一下其他的方式,先获取当前年份最后一天,然后转成3位的字符串天数模式就可以得到当年天数

SELECT to_char(add_months(trunc(sysdate,'y'),12)-1,'DDD') AS days
FROM dual

5、在Oracle中将整数转换为二进制形式

比如我们想要将整数2转换二进制就是10。本质是利用上面第3节中的高级函数model

下面这篇文章第3节介绍的很详细,大家可以参考,我们在此转载引用一下

选读SQL经典实例笔记20_Oracle语法示例 - 知乎

ENAME        SAL SAL_BINARY
---------- ----- --------------------
SMITH        800 1100100000
ALLEN       1600 11001000000
WARD        1250 10011100010
JONES       2975 101110011111
MARTIN      1250 10011100010
BLAKE       2850 101100100010
CLARK       2450 100110010010
SCOTT       3000 101110111000
KING        5000 1001110001000
TURNER      1500 10111011100
ADAMS       1100 10001001100
JAMES        950 1110110110
FORD        3000 101110111000
MILLER      1300 10100010100
select ename,
       sal,
       (
       select bin
         from dual
        model
        dimension by ( 0 attr )
        measures ( sal num,
                   cast(null as varchar2(30)) bin,
                   '0123456789ABCDEF' hex
                 )
        rules iterate (10000) until (num[0] <= 0) (
          bin[0] = substr(hex[cv()],mod(num[cv()],2)+1,1)||bin[cv()],
          num[0] = trunc(num[cv()]/2)
        )
       ) sal_binary
  from emp

 

6、将排序后的等级数据进行分组转列

例如我们想获取表中的排名,然后把相同排名的放在同一列中展示。

思路肯定是先用开窗函数dense_rank() over() 进行排序,然后再用上面行转列的其中一个方法转置

 select max(case when job='CLERK'
                then ename else null end) as clerks,
       max(case when job='ANALYST'
                then ename else null end) as analysts,
       max(case when job='MANAGER'
                then ename else null end) as mgrs,
       max(case when job='PRESIDENT'
                then ename else null end) as prez,
       max(case when job='SALESMAN'
                then ename else null end) as sales
  from (
select job,
       ename,
       row_number()over(partition by job order by ename) rn
  from emp
       ) x
 group by rn

可以参考一下文章SQL 变换结果集成多行|极客教程 

或者以下文章,按照固定第一列3个数据,第二列3个数据,剩下数据在第三列的方式,原理大概相同(参考第8节)SQL Cookbook 系列 - 若干另类目标_d10[any]=case when deptno[cv()]=10 then d10[cv()] -CSDN博客

7、给不同的两个结果集分别行转列成一个结果集后添加标题

我们直接引用以下博主的例子啊,大家掌握理解即可选读SQL经典实例笔记15_窗口函数-CSDN博客 

数据表的内容: 

select * from it_research
DEPTNO ENAME
------ --------------------
   100 HOPKINS
   100 JONES
   100 TONEY
   200 MORALES
   200 P.WHITAKER
   200 MARCIANO
   200 ROBINSON
   300 LACY
   300 WRIGHT
   300 J.TAYLOR
select * from it_apps
DEPTNO ENAME
------ -----------------
   400 CORRALES
   400 MAYWEATHER
   400 CASTILLO
   400 MARQUEZ
   400 MOSLEY
   500 GATTI
   500 CALZAGHE
   600 LAMOTTA
   600 HAGLER
   600 HEARNS
   600 FRAZIER
   700 GUINN
   700 JUDAH
   700 MARGARITO

想要的结果:

RESEARCH             APPS
-------------------- ---------------
100                  400
  JONES                MAYWEATHER
  TONEY                CASTILLO
  HOPKINS            MARQUEZ
200                         MOSLEY
  P.WHITAKER       CORRALES
  MARCIANO    500
  ROBINSON          CALZAGHE
  MORALES             GATTI
300                  600
  WRIGHT               HAGLER
  J.TAYLOR             HEARNS
  LACY                    FRAZIER
                                LAMOTTA
                         700
                               JUDAH
                               MARGARITO
                               GUINN

思路:使用笛卡尔积变成想要的行数,再用max和decode 进行转置

select max(decode(flag2,0,it_dept)) research,
        max(decode(flag2,1,it_dept)) apps
   from (
 select sum(flag1)over(partition by flag2
                           order by flag1,rownum) flag,
        it_dept, flag2
   from (
 select 1 flag1, 0 flag2,
        decode(rn,1,to_char(deptno),'  '||ename) it_dept
   from (
 select x.*, y.id,
        row_number()over(partition by x.deptno order by y.id) rn
   from (
 select deptno,
        ename,
        count(*)over(partition by deptno) cnt
   from it_research
        ) x,
        (select level id from dual connect by level <= 2) y
        )
  where rn <= cnt+1
 union all
 select 1 flag1, 1 flag2,
        decode(rn,1,to_char(deptno),'  '||ename) it_dept
   from (
 select x.*, y.id,
        row_number()over(partition by x.deptno order by y.id) rn
   from (
 select deptno,
        ename,
        count(*)over(partition by deptno) cnt
   from it_apps
        ) x,
        (select level id from dual connect by level <= 2) y
        )
  where rn <= cnt+1
        ) tmp1
        ) tmp2
  group by flag

 

8、Oracle中将标量子查询转换为复合子查询

什么叫标量子查询,就是只能返回一个值,例如,进行如下的语句就会报错 :

select e.deptno,
       e.ename,
       e.sal,
       (select d.dname,d.loc,sysdate today
          from dept d
         where e.deptno=d.deptno)
  from emp e

 当然,一般情况下,我们可以把 EMP 表和 DEPT 表连接起来,进行查询即可。在此我们引入一种新的方式,复合子查询:将标量查询的结果集设置为一个对象

--首先添加一个新的对象类型 generic_obj
create type generic_obj
    as object (
    val1 varchar2(10),
    val2 varchar2(10),
    val3 date
);
--然后进行查询
select x.deptno,
       x.ename,
       x.multival.val1 dname,
       x.multival.val2 loc,
       x.multival.val3 today
  from (
select e.deptno,
       e.ename,
       e.sal,
       (select generic_obj(d.dname,d.loc,sysdate+1)
          from dept d
         where e.deptno=d.deptno) multival
  from emp e
       ) x

 9、将一列数据按照分割字符转置为行

我们有如下数据:

STRINGS
-----------------------------------
entry:stewiegriffin:lois:brian:
entry:moe::sizlack:
entry:petergriffin:meg:chris:
entry:willie:
entry:quagmire:mayorwest:cleveland:
entry:::flanders:
Entry:robo:tchi:ken:


想要的结果为:

VAL1            VAL2            VAL3
--------------- --------------- ---------------
moe                                     sizlack
petergriffin      meg              chris
quagmire        mayorwest    cleveland
robo                tchi                ken
stewiegriffin    lois                 brian
willie
                                             flanders

实现方式:

with cartesian as (
    select level id from dual connect by level<=100
)

select max(decode(id,1,sunstr(strings,p1+1,p2-1))) val1,
       max(decode(id,2,sunstr(strings,p1+1,p2-1))) val2,
       max(decode(id,3,sunstr(strings,p1+1,p2-1))) val3
from (
    select v.strings,
           c.id,
           instr(v.strings,':',1,c.id) p1,
           instr(v.strings,':',1,c.id+1)-instr(v.strings,':',1,c.id) p2
    from v,cartesian c
    where c.id<=(length(v.strings)-length(replace(v.strings,':')))-1
) group by strings order by 1

 

10、计算占总百分比

我们在 数据库语法总结(7)——数字处理_db2求中位数-CSDN博客  中提到过这一部分内容,当然如果是Oracle数据库,我们还可以使用内置函数ratio_to_report来实现

select job,num_emps,
       sum(round(pct)) pct_of_all_salaries
from (
    select job,
           count(*)over(partition by job) num_emps,
           ratio_to_report(sal)over()*100 pct
    from emp
) group by job,num_emps

 SQL Cookbook 系列 - 若干另类目标_d10[any]=case when deptno[cv()]=10 then d10[cv()] -CSDN博客

 

11、查询某一组数据中是否包含某一个值

例如,查询学生在一个学期内参加考试的次数及其通过的次数

select student_id,
       test_id,
       grade_id,
       period_id,
       test_date,
       decode( grp_p_f,1,lpad('+',6),lpad('-',6) ) metreq,
       decode( grp_p_f,1,0,
               decode( test_date,last_test,1,0 ) ) in_progress
  from (
select V.*,
       max(pass_fail)over(partition by
                     student_id,grade_id,period_id) grp_p_f,
       max(test_date)over(partition by
                     student_id,grade_id,period_id) last_test
  from V
       ) x

下面这篇文章介绍的很详细,我们可以具体参考

参考文章SQL 测试一组数据中是否存在某个值|极客教程 

下面呢,我查看网上有很多博客上大家分享的一张SQL图解析,放在这供大家参考

 

好了,到这篇暂时就是我们的结尾总结了,日后如果有的更深入的数据库方面的了解,会继续来补充。接下来的时间可能会比较紧张,所以文章可能有不好的地方大家多多包含

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值