oracle基础函数语法入门学习总结

个人对sql语句的一些基础理解

  • 准备数据
CREATE TABLE learn_sql(
l_id NUMBER(8),
l_date DATE DEFAULT SYSDATE,
l_str VARCHAR2(200)
);
INSERT INTO learn_sql (l_id,l_str)VALUES(1,'小明');
  • 最最最基础的sql语句,不考虑group分组以及聚合函数
SELECT * FROM learn_sql; -- 这里的“*”将会被隐式转化为多个字段,即以下语句(所有字段),这里不多做赘述
SELECT l_id,l_date,l_str FROM learn_sql;
  • 聚合函数,这个函数其实是跟group by分不开的
最基础的count(1),将整体作为一个group
SELECT count(1)
FROM learn_sql l;

--准备数据
INSERT INTO learn_sql (l_id,l_str)VALUES(2,'小青');
INSERT INTO learn_sql (l_id,l_str)VALUES(3,'小黑');
INSERT INTO learn_sql (l_id,l_str)VALUES(4,'小红');
INSERT INTO learn_sql (l_id,l_str)VALUES(9,'小蓝');
--查询语句
SELECT count(1),'你好'
FROM learn_sql l
GROUP BY CASE WHEN 1=1 THEN l.l_id ELSE 1 END
HAVING COUNT(1)=2;
-- 至于为什么能写case函数,因为它最后能返回一个字段,在此处它返回了一个l_id字段,decode也是如此
-- having里面最好不要写乱七八糟的东西,能在where里写的就不在having里写, having是最后筛选的
就比如:
-- 1
SELECT count(1),SUM(l.l_id),CASE WHEN 1=1 THEN l.l_id ELSE 1 END "表的id"
FROM learn_sql l
GROUP BY CASE WHEN 1=1 THEN l.l_id ELSE 1 END
HAVING 
CASE WHEN 1=1 THEN l.l_id ELSE 1 END = 2;

-- 2. 
SELECT count(1),SUM(l.l_id),CASE WHEN 1=1 THEN l.l_id ELSE 1 END "表的id"
FROM learn_sql l
WHERE CASE WHEN 1=1 THEN l.l_id ELSE 1 END = 2
GROUP BY CASE WHEN 1=1 THEN l.l_id ELSE 1 END
-- 这里最好选择2这种方式,能在where里面过滤的就不要到having里过滤,因为having是二次过滤
-- 除非是像以下这种问题,where不能过滤的聚合函数,需要放在having里面过滤, having本来也就是为了进行二次过滤出现的
SELECT count(1),SUM(l.l_id),l.l_id "表的id"
FROM learn_sql l
GROUP BY l.l_id
HAVING 
COUNT(1)>=1;
  • 对于总结:最关键的应该是类型了吧。哪里可以写什么东西,感觉没有必要去记,只要写上去或者得到的类型结果集(一般分为两种情况:结果集rs<=1和>1)是该处所需要的类型就行了,sql语句认清本质即可
-- 只要类型对了,就算 select 的是 * 也可以照用不误, 主要看返回值(不推荐用*)
CREATE TABLE test_1206 (tid NUMBER(8));
INSERT INTO test_1206 VALUES(1);
SELECT (SELECT * FROM test_1206),e.* FROM employees e;
这里是因为只插入了一条数据,且只有一列
-- 拓展:行转列函数
SELECT wm_concat(l.l_str) NAME FROM learn_sql l;

古典问题

  1. 查询表中的管理层,或者非管理层
  • 查询管理层
--因为in里面可以写null,eg:1 in (null,2) 1=null(假)继续过滤..
SELECT COUNT(1)
  FROM employees e1
 WHERE e1.employee_id IN (SELECT e2.manager_id FROM employees e2);
--exists
SELECT COUNT(1)
  FROM employees e
 WHERE EXISTS
 (SELECT 1 FROM employees e2 WHERE e2.manager_id = e.employee_id);
  • 查询不是管理层的员工
--not in需要加过滤条件   eg:1 not in(2,3,null); 当到了1!=null(假)直接跳出过滤
SELECT COUNT(1)
  FROM employees e
 WHERE e.employee_id NOT IN
       (SELECT e2.manager_id
          FROM employees e2
         WHERE e2.manager_id IS NOT NULL);
--not exist
SELECT COUNT(1)
  FROM employees outere
 WHERE NOT EXISTS (SELECT 1
          FROM employees innere
         WHERE outere.employee_id = innere.manager_id);
  • 层级查询
SELECT LEVEL
	  ,PRIOR e.last_name
      ,e.*
  FROM employees e
CONNECT BY PRIOR e.employee_id = e.manager_id
 START WITH e.last_name = 'King'
 ORDER BY LEVEL DESC;
##基础函数
###数字的玩法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YXcpDL1T-1591502447019)(https://i.imgur.com/FMD7TuX.png)]
改变金钱前面的字符
alter session set NLS_CURRENCY = ‘¥';
SELECT to_char(432553425.1
              ,'L000,000,000,000.000')
  FROM dual;
--¥000,432,553,425.100
SELECT to_char(2341.3241
              ,'L0999,999,999.0000')
  FROM dual;
-- ¥0000,002,341.3241
SELECT to_char(2341.3241
              ,'L9999,999,999.0000')
  FROM dual;
-->2,341.3241

日期转换

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eocH3jYb-1591502447029)(https://i.imgur.com/XKK538U.png)]

–>twenty seventeen

SELECT to_char(SYSDATE
              ,'year')
  FROM dual;

–>2017

SELECT to_char(SYSDATE
              ,'yyyy')
  FROM dual;

  • –>12
SELECT to_char(SYSDATE
              ,'mm')
  FROM dual;
SELECT to_char(SYSDATE
              ,'month')
  FROM dual;
-->december 
SELECT to_char(SYSDATE
              ,'mon')
  FROM dual;
-->dec

–>5 这个月的第几天

SELECT to_char(SYSDATE
              ,'dd')
  FROM dual;

–tuesday

SELECT to_char(SYSDATE
              ,'day')
  FROM dual; 

–>fifth

SELECT to_char(SYSDATE
              ,'ddspth')
  FROM dual;

–>tue

SELECT to_char(SYSDATE
              ,'dy')
  FROM dual;
  • 格式化时间

–>02:13:54:pm

SELECT to_char(SYSDATE
              ,'hh:mi:ss:am')
  FROM dual;

–>现在是2017年12月05日 下午 16:19:58 星期二

SELECT REPLACE('现在是' || to_char(SYSDATE
                               ,'yyyy"年"') ||
               to_char(to_char(SYSDATE
                              ,'mm')
                      ,'99') || '月' ||
               to_char(to_char(SYSDATE
                              ,'DD')
                      ,'00') || '日'
              ,' '
              ,'') || ' ' || decode(to_char(SYSDATE
                                           ,'am')
                                   ,'am'
                                   ,'上午'
                                   ,'下午') || ' ' ||
       to_char(SYSDATE
              ,'hh24:mi:ss') || decode(to_char(SYSDATE
                                              ,'dy')
                                      ,'tue'
                                      ,' 星期二') 我的日期
      ,SYSDATE 默认日期
  FROM dual;

字符串的一些玩法

--INSTR(源字符串, 要查找的字符串, 从第几个字符开始, 要找到第几个匹配的序号)返回找到的位置,如果找不到则返回0.
SELECT INSTR('hello world','d',1,1) FROM dual;  --结果为11
SELECT INSTR('hello world','o',1,2) FROM dual;  -- 结果为8

比较屌一点的函数–>分析函数

###partition函数,块函数,分组函数。。随你叫吧

  • 这里以
  • 求一个员工的employees表里面的信息,以及这个员工所在部门的最大工资,(注:有员工不在任何部门)

SELECT MAX(e.salary) over(PARTITION BY e.department_id) “最大工资”
,e.*
FROM employees e
ORDER BY e.employee_id;

SELECT e2.max_sal “最大工资”
,e.*
FROM employees e
,(SELECT e.department_id
,MAX(e.salary) max_sal
FROM employees e
GROUP BY e.department_id) e2
WHERE e.department_id = e2.department_id
ORDER BY e.employee_id;

  • 以上结果看的眼花的话请看以下sql

SELECT DISTINCT (e2.max_sal) 最大工资
,e2.department_id
FROM employees e
,(SELECT e.department_id
,MAX(e.salary) max_sal
FROM employees e
GROUP BY e.department_id) e2
WHERE e.department_id = e2.department_id
ORDER BY e2.department_id;

SELECT DISTINCT (MAX(e.salary) over(PARTITION BY e.department_id)) 最大工资
,e.department_id
FROM employees e
ORDER BY e.department_id;

  • 请再次比较以下sql,注意where条件(null!=null)

SELECT DISTINCT (e2.max_sal) 最大工资
,e2.department_id
FROM employees e
,(SELECT e.department_id
,MAX(e.salary) max_sal
FROM employees e
GROUP BY e.department_id) e2
WHERE e.department_id = e2.department_id
OR (e.department_id IS NULL
AND e2.department_id IS NULL)
ORDER BY e2.department_id;

排名函数

  • 入门级,对50号部门的员工从工资方面进行rank(),dense_rank(),row_number()的排序

SELECT e.salary
,e.department_id"部门"
,rank() over(ORDER BY e.salary DESC) rank
, – 重复的不算一个 1,1,1,4,4,6,6,6,9…
dense_rank() over(ORDER BY e.salary DESC) dense_rank
, – 重复的算一个 1,1,1,1,2,2,2,2,3…
row_number() over(ORDER BY e.department_id DESC) row_number – 从小到大无重复值 1,2,3,4,5,6…
FROM employees e
WHERE e.department_id = 50;

  • 进阶级别 从各个部门出发来为每个员工进行排名

SELECT d.department_name
,e.last_name
,e.salary
,rank() over(PARTITION BY d.department_name ORDER BY e.salary DESC) dept_salary_rank1
,dense_rank() over(PARTITION BY d.department_name ORDER BY e.salary DESC) dept_salary_rank2
,row_number() over(PARTITION BY d.department_name ORDER BY e.salary DESC) dept_salary_rank3
FROM employees e
,departments d
WHERE 1 = 1
AND e.department_id = d.department_id;

视图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hg9zbXhp-1591502447031)(https://i.imgur.com/tWqOrLq.png)]

  • 准备点数据
-- 创建表test_1206
CREATE TABLE test_1206 (
ID NUMBER(8),
NAME VARCHAR2(20),
birthday DATE DEFAULT SYSDATE 
);
--修改表名字
ALTER TABLE test_1206 RENAME TO table_1206;
-- 查询表内容
SELECT * FROM table_1206;-- 结果为空
--插入一条数据
INSERT INTO table_1206 VALUES (1,'xiaoli',to_date('19960206','yyyymmdd')); 
-- 查询表内容
SELECT * FROM table_1206; -- 有结果
commie; --就练习一次,这个随你开心就好

简单视图

--创建视图
CREATE VIEW view_1206 
AS 
SELECT * FROM table_1206 WHERE ID = 1;
-- 通过视图获取信息
SELECT * FROM view_1206; -- 可以查到结果(注意where条件)
-- 从视图向表中插入数据
INSERT INTO view_1206 VALUES(4,'xiaoli',SYSDATE);-- where条件不影响插入
SELECT * FROM TABLE_1206; --注意where条件,所以从表中直接查询,查询结果为已经插入
-- update也一样,注意where条件,逻辑说得过去就行,因为视图毕竟就是一个子查询

复杂视图

-- 创建视图
CREATE VIEW view_1206_complicated 
AS 
(SELECT NAME,COUNT(1) 统计同名的人 FROM table_1206 GROUP BY NAME);
select * FROM view_1206_complicated; --通过视图查询
-- 现在你也应该大约了解为什么复杂视图不能进行DML操作了吧

删除视图

DROP VIEW view_1206_complicated;
  • 总结
--最简单的方法去理解视图,上面那条简单视图插入的效果相同,复杂先抛开不说,首先它极有可能是不具备业务意义的
INSERT INTO
  (SELECT * FROM table_1206 WHERE id = 1)
VALUES
  (7
  ,'Tom'
  ,SYSDATE);
-- 视图就是对用的频繁的子查询进行缩写,暂且可以认为它是一张表

序列

创建序列

create sequence my_index
minvalue 1        --最小值
nomaxvalue        --不设置最大值
start with 1      --从1开始计数
increment by 1    --每次加1个
nocycle           --一直累加,不循环
nocache;          --不建缓冲区
/*
如果你给出了cache值那么系统将自动读取你的cache值大小个seq,
这样在反复操作时会加快运行速度,但如果遭遇意外情况如当机了或oracle死了,
则下次取出的seq值将和上次的不连贯.如果没有强迫症连或者业务要求不连贯无所谓建议用cache.
假如缓冲区为200,这次用到了50,当机器关机后,下次在开启机器,会从201开始
*/

使用序列

SELECT my_index.nextval FROM dual;
SELECT my_index.currval FROM dual;--刚创建的序列不能直接得到当前值,需要用nextval初始化 

insert进阶(注意别名)

  • 一个来源插入多个目标表(无条件)
INSERT ALL INTO sal_history
VALUES
  (empid
  ,hiredate
  ,sal) INTO mgr_history
VALUES
  (empid
  ,mgr
  ,sal)
  SELECT employee_id empid
        ,hire_date   hiredate
        ,salary      sal
        ,manager_id  mgr
    FROM employees
   WHERE employee_id > 200;
  • 一个来源插入多个目标表(有条件)
INSERT ALL INTO sal_history
VALUES
  (empid
  ,hiredate
  ,sal) INTO mgr_history
VALUES
  (empid
  ,mgr
  ,sal)
  SELECT employee_id empid
        ,hire_date   hiredate
        ,salary      sal
        ,manager_id  mgr
    FROM employees
   WHERE employee_id > 200;
  • 一个来源插入多个目标表(有条件,首次匹配即跳到下一条,也就是说满足一个条件就插入,但是只插入一次)
INSERT FIRST WHEN sal > 25000 THEN INTO special_sal
VALUES
  (deptid
  ,sal) WHEN hiredate LIKE
  ('%00%') THEN INTO hiredate_history_00
VALUES
  (deptid
  ,hiredate) WHEN hiredate LIKE
  ('%99%') THEN INTO hiredate_history_99
VALUES
  (deptid
  ,hiredate) ELSE INTO hiredate_history
VALUES
  (deptid
  ,hiredate)
  SELECT department_id deptid
        ,SUM(salary) sal
        ,MAX(hire_date) hiredate
    FROM employees
   GROUP BY department_id;
  • 列转行(一行变多行,交叉报表的反操作,就是选择性插入查询结果,具有分类的效果)
INSERT ALL INTO sales_info
VALUES
  (employee_id
  ,week_id
  ,sales_mon) INTO sales_info
VALUES
  (employee_id
  ,week_id
  ,sales_tue) INTO sales_info
VALUES
  (employee_id
  ,week_id
  ,sales_wed) INTO sales_info
VALUES
  (employee_id
  ,week_id
  ,sales_thur) INTO sales_info
VALUES
  (employee_id
  ,week_id
  ,sales_fri)
  SELECT employee_id
        ,week_id
        ,sales_mon
        ,sales_tue
        ,sales_wed
        ,sales_thur
        ,sales_fri
    FROM sales_source_data;

delete进阶

进阶第一段如果不是像我一样有强迫症,就别看了。

  • 准备数据
CREATE TABLE test_bin AS
  SELECT e.employee_id
        ,e.last_name
    FROM employees e;
SELECT * FROM test_bin;
  • 运行下面语句注意观察,最好截图
SELECT * FROM tab;
  • 删库跑路
drop TABLE test_bin;
  • 运行下面语句注意观察,对比上次查询结果
SELECT * FROM tab;
  • 查询回收站的数据
SELECT * FROM recyclebin;
  • 如想查询已经删除的库,注意双引号
SELECT * FROM "BIN$owBmXtYwQbGx1UIC/tv3kA==$0";

– 清空回收站,这次就真的得跑路了。。。。。

purge recyclebin;
  • delete直接清空表,仅仅一次,删的连渣都不剩了。。。。
CREATE TABLE test_bin AS
  SELECT e.employee_id
        ,e.last_name
    FROM employees e;

SELECT * FROM test_bin;

DROP TABLE test_bin PURGE;

SELECT * FROM recyclebin;

闪回(注意:闪回不局限delete)

  • 准备数据

    CREATE TABLE timestamp_test_table AS
    SELECT e.employee_id
    ,e.last_name
    FROM employees e;
    SELECT * FROM timestamp_test_table; – 查询数据是否插入,首先看看是有数据的哦,可别说我骗你
    COMMIT;–DDL是已经带有commit功能的,这个提交是为了让你玩的放心
  • 等几分钟,删库跑路(这里为什么要等几分钟。。。。)

    DELETE FROM timestamp_test_table;
    COMMIT;
    SELECT * FROM timestamp_test_table; – 这可是真的删了哦
  • 查询一分钟之前数据库的东西,这就叫闪回

    SELECT * FROM timestamp_test_table AS OF TIMESTAMP SYSDATE-1/(2460);
    – 下面这句是查询二十分钟之前的数据库的东西
    (时间自己把控)
    SELECT * FROM timestamp_test_table AS OF TIMESTAMP SYSDATE-20/(24*60);

其他

全局临时表

  • 全局临时表 在不同的回话之间可以屏蔽数据,可以有触发器,检查约束,索引 等。比如在程序的执行过程的当前回话中需要临时存放一些数据,这些数据是其他回话无法访问的,此时全局临时表就是一个很好的方案。

###基于会话

  • CREATE global temporary TABLE temp_table_session
    

(tid NUMBER,tname VARCHAR2(20))
ON COMMIT preserve rows;

  • 插入数据


    INSERT INTO temp_table_session
    SELECT e.employee_id
    ,e.last_name
    FROM employees e;
    SELECT * FROM temp_table_session;
    COMMIT;
    SELECT * FROM temp_table_session;

  • 重新开启一个会话或者重启客户端,重新连接,随你


    SELECT * FROM temp_table_session;–查不到数据啦。。。。

###基于事务

CREATE global temporary TABLE temp_table_session2
(tid NUMBER,tname VARCHAR2(20)) ON COMMIT DELETE ROWS;

  • 插入数据

    INSERT INTO temp_table_session2
    SELECT e.employee_id
    ,e.last_name
    FROM employees e;
    SELECT * FROM temp_table_session2;
    COMMIT;
    SELECT * FROM temp_table_session2;

你可能感兴趣的:(oracle数据库)