oracle怎么分组字段 oracle 分组
Oracle如何对一个多值字段进行分组统计
CREATE TABLE info (
济宁ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为成都创新互联公司的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:18982081108(备注:SSL证书合作)期待与您的合作!
users varchar(100)
);
INSERT INTO info VALUES('userA@userB@userC');
INSERT INTO info VALUES('userB@userC@userD');
INSERT INTO info VALUES('userC@userD@userE');
COLUMN "用户" FORMAT A15
SELECT
to_char(strvalue) as "用户",
count(*) AS "用户数"
FROM
info,
table(fn_split( info.users, '@'))
GROUP BY
to_char(strvalue)
ORDER BY
1;
用户 用户数
--------------- ----------
userA 1
userB 2
userC 3
userD 2
userE 1
上面这样的效果, 是否满足你的需求?
如果满足的话, 你再往下看, 下面是 存储过程的相关代码
Oracle 需要首先在数据库中, 创建好 类型 与 函数。
来实现一个 split 功能的处理。
-- 定义一个对象类型.
CREATE OR REPLACE TYPE ty_row_str_split as object (strValue VARCHAR2 (4000));
/
-- 定义一个 表/数组类型, 内容是前面定义的那个对象.
CREATE OR REPLACE TYPE ty_tbl_str_split IS TABLE OF ty_row_str_split;
/
--------------------
-- 字符分割函数.
-- 参数1: 被分割的源字符串
-- 参数2: 用于拆分的字符串。
--------------------
CREATE OR REPLACE FUNCTION fn_split(
p_str IN VARCHAR2,
p_delimiter IN VARCHAR2)
RETURN ty_tbl_str_split IS
j INT := 0;
i INT := 1;
-- 被分割的源字符串 的长度.
len INT := 0;
-- 分隔字符串的长度
len1 INT := 0;
-- 暂存的中间每一个单元的文本信息.
str VARCHAR2(4000);
-- 预期返回结果.
str_split ty_tbl_str_split := ty_tbl_str_split();
BEGIN
-- 被分割的源字符串 的长度.
len := LENGTH(p_str);
-- 分隔字符串的长度.
len1 := LENGTH(p_delimiter);
-- 遍历 被分割的源字符串.
WHILE j len LOOP
-- 在被分割的源字符串中, 查询 分隔字符串.
j := INSTR(p_str, p_delimiter, i);
IF j = 0 THEN
-- j=0 意味着没有找到.
-- 可以理解为是查询到最后一个单元了.
-- 设置 j := len, 让外部的循环处理可以结束了.
j := len;
-- 获取最后一个单元的内容.
str := SUBSTR(p_str, i);
-- 结果追加一行.
str_split.EXTEND;
-- 设置结果内容.
str_split(str_split.COUNT) := ty_row_str_split(strValue = str);
IF i = len THEN
EXIT;
END IF;
ELSE
-- 如果在被分割的源字符串中,找到了 分隔字符串.
-- 首先,获取分割的内容.
str := SUBSTR(p_str, i, j - i);
-- 然后设置索引, 下一次再查找的时候,从指定的索引位置开始(不是从0开始找了)
i := j + len1;
-- 结果追加一行.
str_split.EXTEND;
-- 设置结果内容.
str_split(str_split.COUNT) := ty_row_str_split(strValue = str);
END IF;
END LOOP;
RETURN str_split;
END fn_split;
/
函数创建完毕以后,可以开始做查询的处理.
SQL select to_char(strvalue) as Value from table(fn_split('aa,bb,cc',','));
VALUE
-------------------------------------------------------------------------------
aa
bb
cc
oracle怎么根据一个数分组
首先你的starttime是什么类型的,数字?字符?还是时间?
要出来08:00-08:30这种结果简单,只要查询的时候加一个关联就可以,
比如select starttime||'-'||endtime from table.当然试过是时间的字段类型,比如date什么的,那就转换成字符型的,反正现在看来主要是字符型。
再说分组,分组可以用case when手动分组。
按照你给的图片个人觉得可以这么分
select case when starttime=0800 and endtime=10:00 then 1
when starttime=0900 and endtime=12:00 then 2
when starttime=1330 and endtime=15:30 then 3
when starttime=1530 and endtime=17:30 then 4
end 分组, starttime||'-'||endtime from table
这个语句中的具体写法,可能会因为数据类型的原因什么的,导致语句不能直接用,需要转换一下数据类型,但是大体上的意思和写法就是这样了。
oracle里面怎么多个字段分组排序
分组排序用group by,若需要条件则在后面加having。
多个字段的话用order by,比如:order by a,b
order by 可以让表按a排序,遇到重复的再按b再排一次序,做到把想要的字段与其他无关字段分开比较。
关于oracle怎么做多次分组
以NO字段为主,进行分组。
select a.no,sum(a.金额) from table a group by a.no
同一个NO,会对应不同的姓名。
select a.no,a.姓名,sum(a.金额) from table a group by a.no,a.姓名
看不懂
目标语句:当收费醒目包含‘盐’这一项,则统计no='10' 且 姓名=‘张三’,所有收费项目对...
select a.项目,sum(a.金额) from table a where a.收费项目= '1' and a.no = '10' and a.姓名=‘张三’ group by a.项目
oracle 字段分开
左(外)连接:LEFT OUTER JOIN…ON;
右(外)连接:RIGHT OUTER JOIN…ON;
全(外)连接:FULL OUTER JOIN…ON; -- 把两张表中没有的数据都显示
SELECT * FROM emp RIGHT OUTER JOIN dept ON(emp.deptno=dept.deptno);
在Oracle之外的数据库都使用以上的SQL:1999语法操作,所以这个语法还必须会一些(如果你一直使用的都是Oracle就可以不会了)。
再次强调:多表查询的性能肯定不高,而且性能一定要在大数据量的情况下才能够发现。
四、统计函数及分组查询
1、统计函数
在之前学习过一个COUNT()函数,此函数的功能可以统计出表中的数据量,实际上这个就是一个统计函数,而常用的统计函数有如下几个:
COUNT():查询表中的数据记录;
AVG():求出平均值;
SUM():求和;
MAX():求出最大值;
MIN():求出最小值;
范例:测试COUNT()、AVG()、SUM()
统计出公司的所有雇员,每个月支付的平均工资及总工资。
SELECT MAX(sal),MIN(sal) FROM emp;
注意点:关于COUNT()函数
COUNT()函数的主要功能是进行数据的统计,但是在进行数据统计的时候,如果一张表中没有统计记录,COUNT()也会返回数据,只是这个数据是“0”。
SELECT COUNT(ename) FROM BONUS;
如果使用的是其他函数,则有可能返回null,但是COUNT()永远都会返回一个具体的数字,这一点以后在开发之中都会使用到。
2、分组查询
在讲解分组操作之前首先必须先明确一点,什么情况下可能分组,例如:
公司的所有雇员,要求男性一组,女性一组,之后可以统计男性和女性的数量;
按照年龄分组,18岁以上的分一组,18岁以下的分一组;
按照地区分组:北京人一组,上海人一组,四川一组;
这些信息如果都保存了数据库之中,肯定在数据的某一列上会存在重复的内容,例如:按照性别分组的时候,性别肯定有重复(男和女),按照年龄分组(有一个范围的重复),按照地区分组有一个地区的信息重复。
所以分组之中有一个不成文的规定:当数据重复的时候分组才有意义,因为一个人也可以一组(没什么意义)。
SELECT [DISTINCT] *|分组字段1 [别名] [,分组字段2 [别名] ,…] | 统计函数
FROM 表名称 [别名], [表名称 [别名] ,…]
[WHERE 条件(s)]
[GROUP BY 分组字段1 [,分组字段2 ,…]]
[ORDER BY 排序字段 ASC | DESC [,排序字段 ASC | DESC]];
范例:按照部门编号分组,求出每个部门的人数,平均工资
SELECT deptno, COUNT(empno), AVG(sal)
FROM emp
GROUP BY deptno;
范例:按照职位分组,求出每个职位的最高和最低工资
SELECT job, MAX(sal), MIN(sal)
FROM emp
GROUP BY job;
但是现在一旦分组之后,实际上对于语法上就会出现了新的限制,对于分组有以下要求:
分组函数可以在没有分组的时候单独用使用,可是却不能出现其他的查询字段;
分组函数单独使用:
SELECT COUNT(empno) FROM emp;
错误的使用,出现了其他字段:
SELECT empno,COUNT(empno) FROM emp;
如果现在要进行分组的话,则SELECT子句之后,只能出现分组的字段和统计函数,其他的字段不能出现:
正确做法:
SELECT job,COUNT(empno),AVG(sal)
FROM emp
GROUP BY job;
错误的做法:
SELECT deptno,job,COUNT(empno),AVG(sal)
FROM emp
GROUP BY job;
分组函数允许嵌套,但是嵌套之后的分组函数的查询之中不能再出现任何的其他字段。
范例:按照职位分组,统计平均工资最高的工资
1、先统计出各个职位的平均工资
SELECT job,AVG(sal)
FROM emp
GROUP BY job;
2、平均工资最高的工资
SELECT MAX(AVG(sal))
FROM emp
GROUP BY job;
范例:查询出每个部门的名称、部门的人数、平均工资
1、确定所需要的数据表:
dept表:每个部门的名称;
emp表:统计出部门的人数、平均工资;
2、确定已知的关联字段:emp.deptno=dept.deptno;
范例:将dept表和emp表的数据关联
SELECT d.dname,e.empno,e.sal
FROM dept d, emp e
WHERE d.deptno=e.deptno;
DNAME EMPNO SAL
-------------- ---------- ----------
ACCOUNTING 7782 2450
ACCOUNTING 7839 5000
ACCOUNTING 7934 1300
RESEARCH 7369 800
RESEARCH 7876 1100
RESEARCH 7902 3000
RESEARCH 7788 3000
RESEARCH 7566 2975
SALES 7499 1600
SALES 7698 2850
SALES 7654 1250
SALES 7900 950
SALES 7844 1500
SALES 7521 1250
已选择14行。
此时的查询结果中,可以发现在dname字段上显示出了重复的数据,按照之前对分组的理解,只要数据重复了,那么就有可
能进行分组的查询操作,但是此时与之前的分组不太一样,之前的分组是针对于一张实体表进行的分组(emp、dept都属于实体表),但是对于以上的数据是
通过查询结果显示的,所以是一张临时的虚拟表,但是不管是否是实体表还是虚拟表,只要是有重复,那么就直接进行分组。
SELECT d.dname,COUNT(e.empno),AVG(e.sal)
FROM dept d, emp e
WHERE d.deptno=e.deptno
GROUP BY d.dname;
但是这个分组并不合适,因为部门一共有四个部门(因为现在已经引入了dept表,dept表存在了四个部门的信息),所以应该通过左右连接改变查询的结果。
SELECT d.dname,COUNT(e.empno),NVL(AVG(e.sal),0)
FROM dept d, emp e
WHERE d.deptno=e.deptno(+)
GROUP BY d.dname;
之前的所有操作都是针对于单个字段分组的,而实际上分组操作之中也可以实现多字段分组。
范例:要求显示每个部门的编号、名称、位置、部门的人数、平均工资
1、确定所需要的数据表:
dept表:每个部门的名称;
emp表:统计出部门的人数、平均工资;
2、确定已知的关联字段:emp.deptno=dept.deptno;
范例:将emp表和dept表关联查询
SELECT d.deptno,d.dname,d.loc,e.empno,e.sal
FROM dept d,emp e
WHERE d.deptno=e.deptno(+);
DEPTNO DNAME LOC EMPNO SAL
---------- -------------- ------------- ---------- ----------
10 ACCOUNTING NEW YORK 7782 2450
10 ACCOUNTING NEW YORK 7839 5000
10 ACCOUNTING NEW YORK 7934 1300
20 RESEARCH DALLAS 7369 800
20 RESEARCH DALLAS 7876 1100
20 RESEARCH DALLAS 7902 3000
20 RESEARCH DALLAS 7788 3000
20 RESEARCH DALLAS 7566 2975
30 SALES CHICAGO 7499 1600
30 SALES CHICAGO 7698 2850
30 SALES CHICAGO 7654 1250
30 SALES CHICAGO 7900 950
30 SALES CHICAGO 7844 1500
30 SALES CHICAGO 7521 1250
40 OPERATIONS BOSTON
已选择15行。
此时存在了重复数据,而且这个重复的数据平均在了三列上(deptno,dname,loc),所以在分组上的GROUP BY子句中就可以写上三个字段:
SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),NVL(AVG(e.sal),0)
FROM dept d,emp e
WHERE d.deptno=e.deptno(+)
GROUP BY d.deptno,d.dname,d.loc;
以上就是多字段分组,但是不管是单字段还是多字段,一定要有一个前提,存在了重复数据。
范例:要求统计出每个部门的详细信息,并且要求这些部门的平均工资高于2000;
在以上程序的基础上完成开发,在之前唯一所学习的限定查询的语法只有WHERE子句,所以下面先使用WHERE完成要求。
SELECT d.deptno,d.dname,d.loc,COUNT(e.empno) mycount,NVL(AVG(e.sal),0) myavg
FROM dept d,emp e
WHERE d.deptno=e.deptno(+) AND AVG(e.sal)2000
GROUP BY d.deptno,d.dname,d.loc;
现在出现了如下的错误提示:
WHERE d.deptno=e.deptno(+) AND AVG(e.sal)2000
*
第 3 行出现错误:
ORA-00934: 此处不允许使用分组函数
本错误提示的核心意思就是在WHERE子句之中不能使用统计函数,之所以在WHERE子句之中不能使用,实际上跟WHERE子句的主要功能有关,WHERE的主要功能是从全部的数据之中取出部分数据。
此时如果要对分组后的数据再次进行过滤,则使用HAVING子句完成,那么此时的SQL语法格式如下:
SELECT [DISTINCT] *|分组字段1 [别名] [,分组字段2 [别名] ,…] | 统计函数
FROM 表名称 [别名], [表名称 [别名] ,…]
[WHERE 条件(s)]
[GROUP BY 分组字段1 [,分组字段2 ,…]]
[HAVING 分组后的过滤条件(可以使用统计函数)]
[ORDER BY 排序字段 ASC | DESC [,排序字段 ASC | DESC]];
下面使用HAVING进行过滤。
SELECT d.deptno,d.dname,d.loc,COUNT(e.empno) mycount,NVL(AVG(e.sal),0) myavg
FROM dept d,emp e
WHERE d.deptno=e.deptno(+)
GROUP BY d.deptno,d.dname,d.loc
HAVING AVG(sal)2000;
注意点:WHERE和HAVING的区别
WHERE:是在执行GROUP BY操作之前进行的过滤,表示从全部数据之中筛选出部分的数据,在WHERE之中不能使用统计函数;
HAVING:是在GROUP BY分组之后的再次过滤,可以在HAVING子句中使用统计函数;
思考题:显示非销售人员工作名称以及从事同一工作雇员的月工资的总和,并且要满足从事同一工作的雇员的月工资合计大于$5000,输出结果按月工资的合计升序排列:
第一步:查询出所有的非销售人员的信息
SELECT * FROM emp WHERE job'SALESMAN';
第二步:按照职位进行分组,并且使用SUM函数统计
SELECT job,SUM(sal)
FROM emp
WHERE job'SALESMAN'
GROUP BY job;
第三步:月工资的合计是通过统计函数查询的,所以现在这个对分组后的过滤要使用HAVING子句完成
SELECT job,SUM(sal)
FROM emp
WHERE job'SALESMAN'
GROUP BY job
HAVING SUM(sal)5000;
第四步:按照升序排列
SELECT job,SUM(sal) sum
FROM emp
WHERE job'SALESMAN'
GROUP BY job
HAVING SUM(sal)5000
ORDER BY sum ASC;
以上的题目就融合分组操作的大部分语法的使用,而且以后遇到问题,要慢慢分析。
五、子查询
子查询 = 简单查询 + 限定查询 + 多表查询 + 统计查询的综合体;
在之前强调过多表查询不建议大家使用,因为性能很差,但是多表查询最有利的替代者就是子查询,所以子查询在实际的开发之中使用的相当的多;
所谓的子查询指的就是在一个查询之中嵌套了其他的若干查询,嵌套子查询之后的查询SQL语句如下:
SELECT [DISTINCT] *|分组字段1 [别名] [,分组字段2 [别名] ,…] | 统计函数 ,(
SELECT [DISTINCT] *|分组字段1 [别名] [,分组字段2 [别名] ,…] | 统计函数
FROM 表名称 [别名], [表名称 [别名] ,…]
[WHERE 条件(s)]
[GROUP BY 分组字段1 [,分组字段2 ,…]]
[HAVING 分组后的过滤条件(可以使用统计函数)]
[ORDER BY 排序字段 ASC | DESC [,排序字段 ASC | DESC]])
FROM 表名称 [别名], [表名称 [别名] ,…] ,(
SELECT [DISTINCT] *|分组字段1 [别名] [,分组字段2 [别名] ,…] | 统计函数
FROM 表名称 [别名], [表名称 [别名] ,…]
[WHERE 条件(s)]
[GROUP BY 分组字段1 [,分组字段2 ,…]]
[HAVING 分组后的过滤条件(可以使用统计函数)]
[ORDER BY 排序字段 ASC | DESC [,排序字段 ASC | DESC]])
[WHERE 条件(s) (
SELECT [DISTINCT] *|分组字段1 [别名] [,分组字段2 [别名] ,…] | 统计函数
FROM 表名称 [别名], [表名称 [别名] ,…]
[WHERE 条件(s)]
[GROUP BY 分组字段1 [,分组字段2 ,…]]
[HAVING 分组后的过滤条件(可以使用统计函数)]
[ORDER BY 排序字段 ASC | DESC [,排序字段 ASC | DESC]])]
[GROUP BY 分组字段1 [,分组字段2 ,…]]
[HAVING 分组后的过滤条件(可以使用统计函数)]
[ORDER BY 排序字段 ASC | DESC [,排序字段 ASC | DESC]];
理论上子查询可以出现在查询语句的任意位置上,但是从个人而言,子查询出现在WHERE和FROM子句之中较多;
以下的使用特点为个人总结,不是官方声明的:
WHERE:子查询一般只返回单行列、多行单列、单行多列的数据;
FROM:子查询返回的一般是多行的数据,当作一张临时表出现。
范例:要求查询出工资比SMITH还要高的全部雇员信息
要想完成本程序,首先必须要知道SMITH的工资是多少:
SELECT sal FROM emp WHERE ename='SMITH';
由于此时返回的是单列的数据,所以这个子句查询可以在WHERE中出现。
SELECT * FROM emp
WHERE sal(
SELECT sal
FROM emp
WHERE ename='SMITH');
范例:要求查询出高于公司平均工资的全部雇员信息
公司的平均工资应该使用AVG()函数求出。
SELECT AVG(sal) FROM emp;
此时数据的返回结果是单行单列的数据,在WHERE之中出现。
SELECT * FROM emp
WHERE sal(
SELECT AVG(sal)
FROM emp);
以上所返回的是单行单列,但是在子查询之中,也可以返回单行多列的数据,只是这种子查询很少出现。
范例:子查询返回单行多列数据
SELECT * FROM emp
WHERE (job,sal)=(
SELECT job,sal
FROM emp
WHERE ename='ALLEN');
如果现在的子查询返回的是多行单列数据的话,这个时候就需要使用三种判断符判断了:IN、ANY、ALL;
1、 IN操作符:用于指定一个子查询的判断范围
这个操作符的使用实际上与之前讲解的IN是一样的,唯一不同的是,里面的范围由子查询指定了。
SELECT * FROM emp
WHERE sal in (
SELECT sal
FROM emp
WHERE job='MANAGER');
但是在使用IN的时候还要注意NOT IN的问题,如果使用NOT IN操作,在子查询之中,如果有一个内容是null,则不会查询出任何的结果。
2、 ANY操作符:与每一个内容想匹配,有三种匹配形式
=ANY:功能与IN操作符是完全一样的;
SELECT * FROM emp
WHERE sal=ANY (
SELECT sal
FROM emp
WHERE job='MANAGER');
ANY:比子查询中返回记录最小的还要大的数据;
SELECT * FROM emp
WHERE salANY (
SELECT sal
FROM emp
WHERE job='MANAGER');
ANY:比子查询中返回记录的最大的还要小;
SELECT * FROM emp
WHERE salANY (
SELECT sal
FROM emp
WHERE job='MANAGER');
3、 ALL操作符:与每一个内容相匹配,有两种匹配形式:
ALL:比子查询中返回的最大的记录还要大
SELECT * FROM emp
WHERE salALL (
SELECT sal
FROM emp
WHERE job='MANAGER');
ALL:比子查询中返回的最小的记录还要小
SELECT * FROM emp
WHERE salALL (
SELECT sal
FROM emp
WHERE job='MANAGER');
以上的所有子查询都是在WHERE子句中出现的,那么下面再来观察在FROM子句中出现的查询,这个子查询一般返回的是多行多列的数据,当作一张临时表的方式来处理。
范例:查询出每个部门的编号、名称、位置、部门人数、平均工资
回顾:最早的时候使用的是多字段分组统计完成的:
SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(e.sal)
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno,d.dname,d.loc;
这个时候实际上是产生了笛卡尔积,一共产生了56条记录;
新的解决方案:通过子查询完成,所有的统计查询只能在GROUP BY中出现,所以在子查询之中负责统计数据,而在外部的查询之中,负责将统计数据和dept表数据相统一。
SELECT d.deptno,d.dname,d.loc,temp.count,temp.avg
FROM dept d,(
SELECT deptno dno,COUNT(empno) count,AVG(sal) avg
FROM emp
GROUP BY deptno) temp
WHERE d.deptno=temp.dno(+);
现在的程序中所操作的数据量:
子查询中统计的记录是14条记录,最终统计的显示结果是3条记录;
dept表之中一共有4条记录;
如果现在产生笛卡尔积的话只有12条记录,再加上雇员的14条记录,一共才26条记录;
通过如上的分析,可以发现,使用子查询的确要比使用多表查询更加节省性能,所以在开发之中子查询出现是最多的,而且在给
出一个不成文的规定:大部分情况下,如果最终的查询结果之中需要出现SELECT子句,但是又不能直接使用统计函数的时候,就在子查询中统计信息,即:有
复杂统计的地方大部分都需要子查询。
oracle中怎么把按'+'拆分字段进行分组
oracle 数据库拆分字段的实现方法:
用正则表达式拆分某一个字段,比如有a,b,c,d,e
sql写法如下:
select regexp_substr('a,b,c,d,e,','[^,]+',1,rownum)
from dual connect by rownum=length(regexp_replace('a,b,c,', '[^,]', null))
结果:
执行结果如下:
1 a
2 b
3 c
4 d
5 e
本文名称:oracle怎么分组字段 oracle 分组
标题路径:http://scyanting.com/article/hgeepp.html