常用資料庫物件、儲存過程
序列:
所謂序列,在oracle中就是一個物件,這個物件用來提供一個有序的資料列,這個有序的資料列的值都不重複。
1.序列可以自動生成唯一值
2.是一個可以被共享的物件
3.典型的用來生成主鍵值的一個物件
4.可以替代應用程式程式碼
5.當sequence的值存放在快取中時可以提高訪問效率。
oracle建立序列語法:
CREATE SEQUENCE name
[INCREMENT BY n]
[START WITH n]
[{MAXVALUE n | NOMAXVALUE}]
[{MINVALUE n | NOMINVALUE}]
[{CYCLE | NOCYCLE}]
[{CACHE n | NOCACHE}]
note:
1.increment by n:表明值每次增長n(步長),如果n是正數就遞增,如果是負數就遞減 預設是1
2.start with n: 從n開始
3.{MAXVALUE n | NOMAXVALUE}: 設定最大值
4.{MINVALUE n | NOMINVALUE}: 設定最小值,start with不能小於最小值。
5.CYCLE | NOCYCLE : 是否迴圈,建議不使用
6.CACHE n | NOCACHE : 是否啟用快取,每次快取n個值
序列的屬性(偽列):
1.nextval : 返回下一個可用的序列值。
就算是被不同的使用者呼叫,每次也返回一個唯一的值。
2.currval :獲取序列當前的值。
在currval呼叫之前,必須保證nextval已經獲取過一次值。
例:create sequence testseq_id_seqt1
maxvalue 5
minvalue 2
CYCLE
NOCACHE;
//第一個值先nextval 後 currval
select testseq_id_seqt1.nextval from dual;
select testseq_id_seqt1.currval from dual;
使用sequence:
create table test_seq(
id number(3) primary key
);
1.向表中插入資料
insert into test_seq values(testseq_id_seq.nextval);
select * from test_seq;
2.檢視序列的當前值
select testseq_id_seq.currval from dual;
3.獲取序列的下一個值。
select testseq_id_seq.nextval from dual;
note:可以通過資料字典user_sequences檢視當前使用者所擁有的序列資訊。
例如:
select sequence_name,min_value,max_value,last_number,INCREMENT_BY,cache_size
from user_sequences
where lower(sequence_name) = 'testseq_id_seq';
修改sequence:
ALTER SEQUENCE name
[INCREMENT BY n]
[{MAXVALUE n | NOMAXVALUE}]
[{MINVALUE n | NOMINVALUE}]
[{CYCLE | NOCYCLE}]
[{CACHE n | NOCACHE}]
note:
1.必須是序列的擁有者,或者具有alter許可權
2.修改後的序列,只對之後的值起作用。
3.不能修改start with,如果想改,只能刪除,重新建立,啟動。
alter sequence testseq_id_seqt1
nomaxvalue
minvalue 2
nocycle
NOCACHE;
刪除sequence:
drop sequence seq_name;
例如:
drop sequence testseq_id_seq;
索引:
索引是關係資料庫中用於存放每一條記錄的一種物件,主要目的是加快資料的讀取速度和完整性檢查。
建立索引是一項技術性要求高的工作。一般在資料庫設計階段的與資料庫結構一道考慮。應用系統的
效能直接與索引的合理直接有關
概念:
1. 類似書的目錄結構
2、 Oracle 的“索引”物件,與表關聯的可選物件,提高SQL查詢語句的速度
3、 索引直接指向包含所查詢值的行的位置,減少磁碟I/O
4、 與所索引的表是相互獨立的物理結構
5、 Oracle 自動使用並維護索引,插入、刪除、更新表後,自動更新索引
//索引由資料庫自動使用
建立:
1.自動建立
當在表中指定了primary Key或者unique約束時會自動建立唯一值索引。
2.使用者建立。
使用者可以建立非唯一值所在以提高在訪問行時的效率。
語法:
CREATE INDEX index_name
ON table_name (column[, column]...);
例如:
create index myIndex on s_emp (last_name);
建立成功後可以通過如下語句檢視:
select index_name,index_type from user_indexes;
select * from user_ind_columns;
建立索引的原則:
1.列經常作為where子句的限定條件或者作為連線條件
2.列包含的資料量很大,並且很多非空的值。空值不能被索引,只有唯一索引才真正提高速度,
一般的索引只能提高30%左右
3.兩個或者更多列頻繁的組合在一起作為where的限定條件或者連線條件
4.列總是作為搜尋條件
5.索引用於查出的資料量佔2%~4%的情況
6.索引不是越多越好,不是索引越多越能加速查詢。
7.要索引的表不經常進行修改操作
刪除索引:
語法:DROP INDEX index_name;
例如:drop index myIndex;
許可權控制
許可權允許使用者訪問屬於其它使用者的物件或執行程式,
ORACLE系統提供許可權:Object 物件級、System 系統級
檢視許可權的資料字典:
字典名 含義
ROLE_SYS_PRIVS System privileges granted to roles
ROLE_TAB_PRIVS Table privileges granted to roles
USER_ROLE_PRIVS Roles accessible by the user
USER_TAB_PRIVS_MADE Object privileges granted on the user's objects
USER_TAB_PRIVS_RECD Object privileges granted to the user
USER_COL_PRIVS_MADE Object privileges granted on the columns of the user's objects
USER_COL_PRIVS_RECD Object privileges granted to the user on specific columns
1.系統許可權(系統許可權是對使用者而言):
系統許可權分類:
DBA: 擁有全部特權,是系統最高許可權,只有DBA才可以建立資料庫結構。
RESOURCE:擁有Resource許可權的使用者只可以建立實體,不可以建立資料庫結構。
CONNECT:擁有Connect許可權的使用者只可以登入Oracle,不可以建立實體,不可以建立資料庫結構。
對於普通使用者:授予connect, resource許可權。
對於DBA管理使用者:授予connect,resource, dba許可權。
DBA擁有最高的系統許可權:
1,可以建立使用者
語法:create user username identified by password;
當用戶建立成功之後,此使用者什麼許可權都沒有,甚至不能登入資料庫。
2. 賦予許可權:
一個使用者應該具有的基本許可權包含:
CREATE SESSION
CREATE TABLE
CREATE SEQUENCE
CREATE VIEW
CREATE PROCEDURE
如果有多個使用者他們都具有相同的許可權(create session,create table,create sequence),賦予許可權的動作過於麻煩,要給每個使用者分別制定這些許可權,因此oracle提出角色的概念,可以將許可權賦值給角色,然後再將角色賦值給使用者。
角色:一組許可權的集合
例如:
grant resource,connect to test;
此時resource,connect就是角色。
查詢resource,connect 具有哪些許可權可以使用:
select privilege,role from role_sys_privs
where role = 'CONNECT' or role ='RESOURCE';
語法:
grant xxxx to user_name ;
例如:
grant create view to test;
3.回收許可權
語法:revoke xxx from user_name;
4.修改密碼:
語法:alter user xxx identified by xxxx;
5.刪除使用者:
語法:drop user username [cascade];
☆note: cascade:當用戶下有表的時候,必須使用cascade級聯刪除。
例如: drop user test cascade;
//查詢有哪些使用者:select username from dba_users;//dba登入
2.物件許可權(針對物件,類似表物件等):
物件許可權:select, update, insert, alter, index, delete, all //all包括所有許可權
物件的 擁有者擁有所有的許可權。
1.給使用者賦予操作物件的許可權:
GRANT object_priv [(columns)]
ON object
TO {user|role|PUBLIC}
[WITH GRANT OPTION]; //允許分配到許可權的使用者繼續將許可權分配給其它使用者
例如:
建立test使用者,建立表test22
grant select on test22 to test;
給test使用者賦予在test22表上進行查詢的權利。
grant update(id) on test22 to test;
給test賦予能夠更新test22表上id列的許可權。
/insert
2.回收許可權:同系統許可權。
語法:revoke xxx on obj from user;
例如:
revoke select , update on test22 from test;
檢視:
所謂檢視就是提取一張或者多張表的資料生成一個對映,管理檢視可以同樣達到操作原表的效果,方便資料的管理以及安全操作。(是基於一個表或多個表或檢視的邏輯表,本身不包含資料,通過它可以對錶裡面的資料進行查詢和修改。檢視基於的表稱為基表)檢視其實就是一條查詢sql語句,用於顯示一個或多個表或其他檢視中的相關資料。檢視將一個查詢的結果作為一個表來使用,因此檢視可以被看作是儲存查詢結果的一個虛擬表。檢視來源於表,所有對檢視資料的修改最終都會被反映到檢視的基表中,這些修改必須服從基表的完整性約束。
檢視的儲存:
與表不同,檢視不會要求分配儲存空間,檢視中也不會包含實際的資料。檢視只是定義了一個查詢,檢視中的資料是從基表中獲取,這些資料在檢視被引用時動態的生成。由於檢視基於資料庫中的其他物件,因此一個檢視只需要佔用資料字典中儲存其定義的空間,而無需額外的儲存空間。
檢視的優勢:
1.資訊隱藏
比如s_emp表中有工資,可以建立檢視,隱藏工資資訊。(可以配合許可權,讓某個使用者只能檢視
檢視,不能查看錶。)通過檢視可以設定允許使用者訪問的列和資料行。
2.使複雜查詢變得簡單,簡化使用者的SQL 語句,實際上就是SQL語句操作的結果作為檢視的基表來使用。
3.資料獨立。
4.相同資料的不同展示形式。
檢視的分類:
1.簡單檢視
2.複雜檢視
比較:
1、簡單檢視只從單表裡獲取資料,複雜檢視從多表;
2、簡單檢視不包含函式和資料組,複雜檢視包含;
3、簡單檢視可以實現DML操作,複雜檢視不可以
簡單檢視 複雜檢視
涉及到的表個數 1 1個或多個
包含函式 不包含 包含
包含組資料 不包含 包含
通過檢視使用DML 可以 不可以
檢視的建立:
CREATE [OR REPLACE] [FORCE|NOFORCE] VIEW view_name
[(alias[, alias]...)]
AS
select 。。。。
[WITH CHECK OPTION [CONSTRAINT constraint]]
[WITH READ ONLY]
note:
1.or replace:若所建立的試圖已經存在,ORACLE自動重建該檢視
2.force| noforce: 即使基表不存在也要建立該檢視 | 基表不存在就不建立此檢視,預設值。
3.alias: 為檢視產生的列定義的別名(相當於給子查詢的結果列起別名)
4.子查詢中可以包含複雜的查詢語法,這些細節都對使用者隱藏。
5.子查詢中不能包含order by子句。
6.WITH CHECK OPTION 插入或修改的資料行必須滿足檢視定義時的約束;換句話說,加上該關鍵詞表示對
view進行dml操作的時候,只能操作select語句中where條件限制的內容
7.WITH READ ONLY :該檢視只讀,不能在這個檢視上進行任何DML操作。
//在沒有WITH CHECK OPTION和 READ ONLY 的情況下,子查詢中不能使用ORDER BY 子句
8.檢視檢視結構: desc view_name;
例如建立簡單檢視(可以通過DML語句修改):
如果許可權不足,sqlplus "/as sysdba"-->grant create view to briupz(表示使用者名稱)
create or replace view myView
as
select id,last_name,start_date
from s_emp
where id <= 4;
此時可以使用:
1.檢視檢視中所有資料資訊
select * from myView;
SELECT view_name,text from user_views;
2.執行插入:
insert into myView values(111,'haha','03-5月-16'); 插入成功!
3.再次檢視,找不到剛插入的資料,因為這條資料不滿足id<=4,但是檢視原始表s_emp,有這條資料。
如果:
create or replace view myView
(id,name,s_date)
as
select id,last_name,start_date
from s_emp
where id <= 4
with check option;
此時可以使用:
1.檢視檢視中所有資料資訊
select * from myView;
2.執行插入:
insert into myView values(121,'haha','03-5月-16'); 插入失敗!,因為檢視的約束時id<=4,現在插入的id值為121,所以失敗!
with check option 插入或修改的資料行必須滿足檢視定義時的約束
檢視上的DML操作應遵循的原則:
1.簡單檢視可以執行DML操作;
2.在檢視包含GROUP 函式,GROUP BY子句,DISTINCT關鍵字時不能刪除資料行;
3.在檢視不出現下列情況時可通過檢視修改基表資料或插入資料:
a.檢視中包含GROUP 函式,GROUP BY子句,DISTINCT關鍵字;
b.使用表示式定義的列;
c.ROWNUM偽列。
d.基表中未在檢視中選擇的其他列定義為非空且無預設值。
建立複雜檢視(不可以通過DML語句修改):
複雜檢視可能包含分組,組函式,多表連線等。
例如:
CREATE or replace VIEW myView
(name, minsal, maxsal, avgsal)
AS SELECT d.name, MIN(e.salary),
MAX(e.salary), AVG(e.salary)
FROM s_emp e, s_dept d
WHERE e.dept_id = d.id
GROUP BY d.name;
create or replace view myView2
(id,name,dept_name,s_date)
as
select se.id,last_name,name,start_date
from s_emp se,s_dept sd
where se.dept_id=sd.id and se.id <= 4
with check option;
insert into myView2 values(112,'aaa','Sales','01-1月-92');//error
檢視檢視資訊
可以使用資料字典user_views;
刪除檢視物件:
DROP VIEW view_name;
儲存過程:
儲存過程(Procedure)是一組為了完成特定功能的SQL語句集合,經編譯後儲存在資料庫中,使用者通過指定儲存過程的名稱並給出引數來執行。
儲存過程中可以包含邏輯控制語句和資料操縱語句,它可以接受引數、輸出引數、返回單個或多個結果集以及返回值。
由於儲存過程在建立時即在資料庫伺服器上進行了編譯並存儲在資料庫中,所以儲存過程執行要比單個的SQL語句塊要快。同時由於在呼叫時只需用提供儲存過程名和必要的引數資訊,所以在一定程度上也可以減少網路流量、簡單網路負擔。
優點
1. 執行速度:對於很簡單的sql,儲存過程沒有什麼優勢。對於複雜的業務邏輯,因為在儲存過程建立的時候,資料庫已經對其進行了一次解析和優化。儲存過程一旦執行,在記憶體中就會保留一份這個儲存過程,這樣下次再執行同樣的儲存過程時,可以從記憶體中直接呼叫,所以執行速度會比普通sql快。
2. 減少網路傳輸:儲存過程直接就在資料庫伺服器上跑,所有的資料訪問都在資料庫伺服器內部進行,不需要傳輸資料到其它伺服器,所以會減少一定的網路傳輸。但是在儲存過程中沒有多次資料互動,那麼實際上網路傳輸量和直接sql是一樣的。而且我們的應用伺服器通常與資料庫是在同一內網,大資料的訪問的瓶頸會是硬碟的速度,而不是網速。
3. 可維護性:的儲存過程有些時候比程式更容易維護,這是因為可以實時更新DB端的儲存過程。有些bug,直接改儲存過程裡的業務邏輯,就搞定了。
4. 增強安全性:提高程式碼安全,防止 SQL注入。這一點sql語句也可以做到。
5. 可擴充套件性:應用程式和資料庫操作分開,獨立進行,而不是相互在一起。方便以後的擴充套件和DBA維護優化。
缺點
1. SQL本身是一種結構化查詢語言,但不是面向物件的的,本質上還是過程化的語言,面對複雜的業務邏輯,過程化的處理會很吃力。同時SQL擅長的是資料查詢而非業務邏輯的處理,如果如果把業務邏輯全放在儲存過程裡面,違背了這一原則。
2. 如果需要對輸入儲存過程的引數進行更改,或者要更改由其返回的資料,則您仍需要更新程式集中的程式碼以新增引數、更新呼叫,等等,這時候估計會比較繁瑣了。
3. 開發除錯複雜,由於IDE的問題,儲存過程的開發除錯要比一般程式困難。
4. 沒辦法應用快取。雖然有全域性臨時表之類的方法可以做快取,但同樣加重了資料庫的負擔。如果快取併發嚴重,經常要加鎖,那效率實在堪憂。
5. 不支援群集,資料庫伺服器無法水平擴充套件,或者資料庫的切割(水平或垂直切割)。資料庫切割之後,儲存過程並不清楚資料儲存在哪個資料庫中。
總結
1. 適當的使用儲存過程,能夠提高我們SQL查詢的效能,
2. 儲存過程不應該大規模使用,濫用。
系統儲存過程:
系統儲存過程是系統建立的儲存過程,目的在於能夠方便的從系統表中查詢資訊或完成與更新資料庫表相關的管理任務或其他的系統管理任務。系統儲存過程主要儲存在master資料庫中,以“sp”下劃線開頭的儲存過程。儘管這些系統儲存過程在master資料庫中,但我們在其他資料庫還是可以呼叫系統儲存過程。有一些系統儲存過程會在建立新的資料庫的時候被自動建立在當前資料庫中。
exec sp_databases; --檢視資料庫
exec sp_tables; --查看錶
exec sp_columns student;--檢視列
exec sp_helpIndex student;--檢視索引
exec sp_helpConstraint student;--約束
exec sp_stored_procedures;
exec sp_helptext 'sp_stored_procedures';--檢視儲存過程建立、定義語句
exec sp_rename student, stuInfo;--修改表、索引、列的名稱
exec sp_renamedb myTempDB, myDB;--更改資料庫名稱
exec sp_defaultdb 'master', 'myDB';--更改登入名的預設資料庫
exec sp_helpdb;--資料庫幫助,查詢資料庫資訊
exec sp_helpdb master;
示例:
--表重新命名
exec sp_rename 'stu', 'stud';
select * from stud;
--列重新命名
exec sp_rename 'stud.name', 'sName', 'column';
exec sp_help 'stud';
--重新命名索引
exec sp_rename N'student.idx_cid', N'idx_cidd', N'index';
exec sp_help 'student';
--查詢所有儲存過程
select * from sys.objects where type = 'P';
select * from sys.objects where type_desc like '%pro%' and name like 'sp%';
使用者自定義儲存過程:
建立語法
create proc | procedure pro_name
[{@引數資料型別} [=預設值] [output],
{@引數資料型別} [=預設值] [output],
....
]
as
SQL_statements
建立不帶引數儲存過程
if (exists (select * from sys.objects where name = 'proc_get_student'))
drop proc proc_get_student
go
create proc proc_get_student
as
select * from student;
--呼叫、執行儲存過程
exec proc_get_student;
修改儲存過程
alter proc proc_get_student
as
select * from student;
帶參儲存過程
if (object_id('proc_find_stu', 'P') is not null)
drop proc proc_find_stu
go
create proc proc_find_stu(@startId int, @endId int)
as
select * from student where id between @startId and @endId
go
exec proc_find_stu 2, 4;
帶萬用字元引數儲存過程
if (object_id('proc_findStudentByName', 'P') is not null)
drop proc proc_findStudentByName
go
create proc proc_findStudentByName(@name varchar(20) = '%j%', @nextName varchar(20) = '%')
as
select * from student where name like @name and name like @nextName;
go
exec proc_findStudentByName;
exec proc_findStudentByName '%o%', 't%';
帶輸出引數儲存過程
if (object_id('proc_getStudentRecord', 'P') is not null)
drop proc proc_getStudentRecord
go
create proc proc_getStudentRecord(
@id int, --預設輸入引數
@name varchar(20) out, --輸出引數
@age varchar(20) output--輸入輸出引數
)
as
select @name = name, @age = age from student where id = @id and sex = @age;
go
--
declare @id int,
@name varchar(20),
@temp varchar(20);
set @id = 7;
set @temp = 1;
exec proc_getStudentRecord @id, @name out, @temp output;
select @name, @temp;
print @name + '#' + @temp;
不快取儲存過程
if (object_id('proc_temp', 'P') is not null)
drop proc proc_temp
go
create proc proc_temp
with recompile
as
select * from student;
go
exec proc_temp;
加密儲存過程
if (object_id('proc_temp_encryption', 'P') is not null)
drop proc proc_temp_encryption
go
create proc proc_temp_encryption
with encryption
as
select * from student;
go
exec proc_temp_encryption;
exec sp_helptext 'proc_temp';
exec sp_helptext 'proc_temp_encryption';
帶遊標引數儲存過程
if (object_id('proc_cursor', 'P') is not null)
drop proc proc_cursor
go
create proc proc_cursor
@cur cursor varying output
as
set @cur = cursor forward_only static for
select id, name, age from student;
open @cur;
go
--呼叫
declare @exec_cur cursor;
declare @id int,
@name varchar(20),
@age int;
exec proc_cursor @cur = @exec_cur output;--呼叫儲存過程
fetch next from @exec_cur into @id, @name, @age;
while (@@fetch_status = 0)
begin
fetch next from @exec_cur into @id, @name, @age;
print 'id: ' + convert(varchar, @id) + ', name: ' + @name + ', age: ' + convert(char, @age);
end
close @exec_cur;
deallocate @exec_cur;--刪除遊標
分頁儲存過程
if (object_id('pro_page', 'P') is not null)
drop proc proc_cursor
go
create proc pro_page
@startIndex int,
@endIndex int
as
select count(*) from product
;
select * from (
select row_number() over(order by pid) as rowId, * from product
) temp
where temp.rowId between @startIndex and @endIndex
go
--drop proc pro_page
exec pro_page 1, 4
--
--分頁儲存過程
if (object_id('pro_page', 'P') is not null)
drop proc pro_stu
go
create procedure pro_stu(
@pageIndex int,
@pageSize int
)
as
declare @startRow int, @endRow int
set @startRow = (@pageIndex - 1) * @pageSize +1
set @endRow = @startRow + @pageSize -1
select * from (
select *, row_number() over (order by id asc) as number from student
) t
where t.number between @startRow and @endRow;
exec pro_stu 2, 2;
儲存過程語法摘抄自:http://www.cnblogs.com/hoojo/archive/2011/07/19/2110862.html