数据库

位置:IT落伍者 >> 数据库 >> 浏览文章

OracleSQL精妙SQL语句讲解


发布日期:2019年12月30日
 
OracleSQL精妙SQL语句讲解

行列转换 行转列

DROP TABLE t_change_lc;

CREATE TABLE t_change_lc (card_code VARCHAR() q NUMBER bal NUMBER);

INSERT INTO t_change_lc

SELECT card_code ROWNUM q trunc(dbms_randomVALUE * ) bal FROM dual CONNECT BY ROWNUM <=

UNION

SELECT card_code ROWNUM q trunc(dbms_randomVALUE * ) bal FROM dual CONNECT BY ROWNUM <= ;

SELECT * FROM t_change_lc;

SELECT acard_code

SUM(decode(aq abal )) q

SUM(decode(aq abal )) q

SUM(decode(aq abal )) q

SUM(decode(aq abal )) q

FROM t_change_lc a

GROUP BY acard_code

ORDER BY ;

行列转换 列转行

DROP TABLE t_change_cl;

CREATE TABLE t_change_cl AS

SELECT acard_code

SUM(decode(aq abal )) q

SUM(decode(aq abal )) q

SUM(decode(aq abal )) q

SUM(decode(aq abal )) q

FROM t_change_lc a

GROUP BY acard_code

ORDER BY ;

SELECT * FROM t_change_cl;

SELECT tcard_code

trn q

decode(trn tq tq tq tq) bal

FROM (SELECT a* brn

FROM t_change_cl a

(SELECT ROWNUM rn FROM dual CONNECT BY ROWNUM <= ) b) t

ORDER BY ;

行列转换 行转列 合并

DROP TABLE t_change_lc_comma;

CREATE TABLE t_change_lc_comma AS SELECT card_codequarter_||q AS q FROM t_change_lc;

SELECT * FROM t_change_lc_comma;

SELECT tcard_code substr(MAX(sys_connect_by_path(tq ;)) ) q

FROM (SELECT acard_code

aq

row_number() over(PARTITION BY acard_code ORDER BY aq) rn

FROM t_change_lc_comma a) t

START WITH trn =

CONNECT BY tcard_code = PRIOR tcard_code

AND trn = PRIOR trn

GROUP BY tcard_code;

行列转换 列转行 分割

DROP TABLE t_change_cl_comma;

CREATE TABLE t_change_cl_comma AS

SELECT tcard_code substr(MAX(sys_connect_by_path(tq ;)) ) q

FROM (SELECT acard_code

aq

row_number() over(PARTITION BY acard_code ORDER BY aq) rn

FROM t_change_lc_comma a) t

START WITH trn =

CONNECT BY tcard_code = PRIOR tcard_code

AND trn = PRIOR trn

GROUP BY tcard_code;

SELECT * FROM t_change_cl_comma;

SELECT tcard_code

substr(tq

instr(; || tq ; rn)

instr(tq || ; ; rn) instr(; || tq ; rn)) q

FROM (SELECT acard_code aq brn

FROM t_change_cl_comma a

(SELECT ROWNUM rn FROM dual CONNECT BY ROWNUM <= ) b

WHERE instr(; || aq ; rn) > ) t

ORDER BY ;

实现一条记录根据条件多表插入

DROP TABLE t_ia_src;

CREATE TABLE t_ia_src AS SELECT a||ROWNUM c b||ROWNUM c FROM dual CONNECT BY ROWNUM<=;

DROP TABLE t_ia_dest_;

CREATE TABLE t_ia_dest_(flag VARCHAR() c VARCHAR());

DROP TABLE t_ia_dest_;

CREATE TABLE t_ia_dest_(flag VARCHAR() c VARCHAR());

DROP TABLE t_ia_dest_;

CREATE TABLE t_ia_dest_(flag VARCHAR() c VARCHAR());

SELECT * FROM t_ia_src;

SELECT * FROM t_ia_dest_;

SELECT * FROM t_ia_dest_;

SELECT * FROM t_ia_dest_;

INSERT ALL

WHEN (c IN (aa)) THEN

INTO t_ia_dest_(flagc) VALUES(flagc)

WHEN (c IN (aa)) THEN

INTO t_ia_dest_(flagc) VALUES(flagc)

ELSE

INTO t_ia_dest_(flagc) VALUES(flag||flagc||c)

SELECT cc f flag f flag FROM t_ia_src;

如果存在就更新不存在就插入用一个语句实现

DROP TABLE t_mg;

CREATE TABLE t_mg(code VARCHAR() NAME VARCHAR());

SELECT * FROM t_mg;

MERGE INTO t_mg a

USING (SELECT the code code the name NAME FROM dual) b

ON (de = de)

WHEN MATCHED THEN

UPDATE SET aNAME = bNAME

WHEN NOT MATCHED THEN

INSERT (code NAME) VALUES (de bNAME);

抽取/删除重复记录

DROP TABLE t_dup;

CREATE TABLE t_dup AS SELECT code_||ROWNUM code dbms_randomstring(z) NAME FROM dual CONNECT BY ROWNUM<=;

INSERT INTO t_dup SELECT code_||ROWNUM code dbms_randomstring(z) NAME FROM dual CONNECT BY ROWNUM<=;

SELECT * FROM t_dup;

SELECT * FROM t_dup a WHERE aROWID <> (SELECT MIN(bROWID) FROM t_dup b WHERE de=de);

SELECT de bNAME

FROM (SELECT de

aNAME

row_number() over(PARTITION BY de ORDER BY aROWID) rn

FROM t_dup a) b

WHERE brn > ;

IN/EXISTS的不同适用环境

t_orderscustomer_id有索引

SELECT a*

FROM t_employees a

WHERE aemployee_id IN

(SELECT bsales_rep_id FROM t_orders b WHERE bcustomer_id = );

SELECT a*

FROM t_employees a

WHERE EXISTS (SELECT

FROM t_orders b

WHERE bcustomer_id =

AND aemployee_id = bsales_rep_id);

t_employeesdepartment_id有索引

SELECT a*

FROM t_employees a

WHERE adepartment_id =

AND EXISTS

(SELECT FROM t_orders b WHERE aemployee_id = bsales_rep_id);

SELECT a*

FROM t_employees a

WHERE adepartment_id =

AND aemployee_id IN (SELECT bsales_rep_id FROM t_orders b);

FBI

DROP TABLE t_fbi;

CREATE TABLE t_fbi AS

SELECT ROWNUM rn dbms_randomSTRING(z) NAME SYSDATE + dbms_randomVALUE * dt FROM dual

CONNECT BY ROWNUM <=;

CREATE INDEX idx_nonfbi ON t_fbi(dt);

DROP INDEX idx_fbi_;

CREATE INDEX idx_fbi_ ON t_fbi(trunc(dt));

SELECT * FROM t_fbi WHERE trunc(dt) = to_date(yyyymmdd) ;

不建议使用

SELECT * FROM t_fbi WHERE to_char(dt yyyymmdd) = ;

LOOP中的COMMIT/ROLLBACK

DROP TABLE t_loop PURGE;

create TABLE t_loop AS SELECT * FROM user_objects WHERE =;

SELECT * FROM t_loop;

逐行提交

DECLARE

BEGIN

FOR cur IN (SELECT * FROM user_objects) LOOP

INSERT INTO t_loop VALUES cur;

COMMIT;

END LOOP;

END;

模拟批量提交

DECLARE

v_count NUMBER;

BEGIN

FOR cur IN (SELECT * FROM user_objects) LOOP

INSERT INTO t_loop VALUES cur;

v_count := v_count + ;

IF v_count >= THEN

COMMIT;

END IF;

END LOOP;

COMMIT;

END;

真正的批量提交

DECLARE

CURSOR cur IS

SELECT * FROM user_objects;

TYPE rec IS TABLE OF user_objects%ROWTYPE;

recs rec;

BEGIN

OPEN cur;

WHILE (TRUE) LOOP

FETCH cur BULK COLLECT

INTO recs LIMIT ;

forall 实现批量

FORALL i IN recsCOUNT

INSERT INTO t_loop VALUES recs (i);

COMMIT;

EXIT WHEN cur%NOTFOUND;

END LOOP;

CLOSE cur;

END;

悲观锁定/乐观锁定

DROP TABLE t_lock PURGE;

CREATE TABLE t_lock AS SELECT ID FROM dual;

SELECT * FROM t_lock;

常见的实现逻辑隐含bug

DECLARE

v_cnt NUMBER;

BEGIN

这里有并发性的bug

SELECT MAX(ID) INTO v_cnt FROM t_lock;

here for other operation

v_cnt := v_cnt + ;

INSERT INTO t_lock (ID) VALUES (v_cnt);

COMMIT;

END;

高并发环境下安全的实现逻辑

DECLARE

v_cnt NUMBER;

BEGIN

对指定的行取得lock

SELECT ID INTO v_cnt FROM t_lock WHERE ID= FOR UPDATE;

在有lock的情况下继续下面的操作

SELECT MAX(ID) INTO v_cnt FROM t_lock;

here for other operation

v_cnt := v_cnt + ;

INSERT INTO t_lock (ID) VALUES (v_cnt);

COMMIT; 提交并且释放lock

END;

硬解析/软解析

DROP TABLE t_hard PURGE;

CREATE TABLE t_hard (ID INT);

SELECT * FROM t_hard;

DECLARE

sql_ VARCHAR();

BEGIN

hard parse

java中的同等语句是 Statementexecute()

FOR i IN LOOP

sql_ := insert into t_hard(id) values( || i || );

EXECUTE IMMEDIATE sql_;

END LOOP;

COMMIT;

soft parse

java中的同等语句是 PreparedStatementexecute()

sql_ := insert into t_hard(id) values(:id);

FOR i IN LOOP

EXECUTE IMMEDIATE sql_

USING i;

END LOOP;

COMMIT;

END;

正确的分页算法

SELECT *

FROM (SELECT a* ROWNUM rn

FROM (SELECT * FROM t_employees ORDER BY first_name) a

WHERE ROWNUM <= )

WHERE rn > ;

分页算法(why not this one)

SELECT a* ROWNUM rn

FROM (SELECT * FROM t_employees ORDER BY first_name) a

WHERE ROWNUM <= AND ROWNUM > ;

分页算法(why not this one)

SELECT b*

FROM (SELECT a* ROWNUM rn

FROM t_employees a

WHERE ROWNUM < =

ORDER BY first_name) b

WHERE brn > ;

OLAP

小计合计

SELECT CASE

WHEN adeptno IS NULL THEN

合计

WHEN adeptno IS NOT NULL AND aempno IS NULL THEN

小计

ELSE

|| adeptno

END deptno

aempno

aename

SUM(asal) total_sal

FROM scottemp a

GROUP BY GROUPING SETS((adeptno)(adeptno aempno aename)());

分组排序

SELECT adeptno

aempno

aename

asal

可跳跃的rank

rank() over(PARTITION BY adeptno ORDER BY asal DESC) r

密集型rank

dense_rank() over(PARTITION BY adeptno ORDER BY asal DESC) r

不分组排序

rank() over(ORDER BY sal DESC) r

FROM scottemp a

ORDER BY adeptnoasal DESC;

当前行数据和前/后n行的数据比较

SELECT aempno

aename

asal

上面一行

lag(asal) over(ORDER BY asal DESC) lag_

下面三行

lead(asal ) over(ORDER BY asal DESC) lead_

FROM scottemp a

ORDER BY asal DESC;

上一篇:技术感悟:我对Oracle索引的理解

下一篇:oracle存储过程的基本语法及注意事项