程式設計師常見面試之 資料庫 知識點小結(二)
前言
聚簇索引與非聚簇索引的區別
- 聚簇索引的順序就是資料的物理儲存順序
每個表中只能有一個聚集索引
聚集索引要求:“既不能絕大多數都相同,又不能只有極少數相同”的規則。 - 非聚簇索引的解釋是:索引順序與資料物理排列順序無關
- 一個表最多隻能有一個聚簇索引。
建立索引程式碼
-----------------------------------------------------------
---- Create T_Pet table in tempdb.
-----------------------------------------------------------
USE tempdb
CREATE TABLE T_Pet
(
animal VARCHAR(20),
[name] VARCHAR(20),
sex CHAR(1),
age INT
)
-----------------------------------------------------------
---- Create Unique Clustered Index
-----------------------------------------------------------
CREATE UNIQUE CLUSTERED INDEX T_PetonAnimal1_ ClterIdx ON T_Pet (animal)
非聚集索引程式碼
-----------------------------------------------------------
---- Create T_Pet table in tempdb with NONCLUSTERED INDEX.
-----------------------------------------------------------
USE tempdb
CREATE TABLE T_Pet
(
animal VARCHAR(20),
[name] VARCHAR(20),
sex CHAR(1),
age INT
)
-----------------------------------------------------------
---- Create Unique NonClustered Index
-----------------------------------------------------------
CREATE UNIQUE NONCLUSTERED INDEX T_PetonAnimal1_NonClterIdx ON T_Pet (animal)
NonClustered 和 Clustered 就是聚集和非聚集的區別
稠密和非稠密的區別
稠密就是一條搜尋碼值都有一個索引,
非稠密索引中,只為搜尋碼的某些值建立索引項。非稠密是一個索引對應一些記錄的範圍
Note
輔助索引必須是稠密索引
遊標
比如 select * from table_a 可以得到結果集,遊標用來定位結果集的行,可以對結果集修改等等。
@@FETCH_STATUS 全域性變數可以判斷遊標是不是到了最後,該變數為非0表示到了最後或者出錯
程式碼
Set serveroutput on;
declare
---define Cursor
Cursor cur_policy is
select cm.policy_code, cm.applicant_id, cm.period_prem,cm.bank_code,cm.bank_account
from t_contract_master cm
where cm.liability_state = 2
and cm.policy_type = 1
and cm.policy_cate in ('2','3','4')
and rownum < 5
order by cm.policy_code desc;
curPolicyInfo cur_policy%rowtype;---定義遊標變數
Begin
open cur_policy; ---open cursor
Loop
--deal with extraction data from DB
Fetch cur_policy into curPolicyInfo;
Exit when cur_policy%notfound;
Dbms_Output.put_line(curPolicyInfo.policy_code);
end loop;
Exception
when others then
close cur_policy;
Dbms_Output.put_line(Sqlerrm);
if cur_policy%isopen then
--close cursor
close cur_policy;
end if;
end;
觸發器
觸發器是一個特殊的儲存過程。 ORACLE事件指的是對資料庫的表進行的INSERT、UPDATE及DELETE操作或對檢視進行類似的操作。ORACLE將觸發器的功能擴充套件到了觸發ORACLE,如資料庫的啟動與關閉等
- 觸發時機:指定觸發器的觸發時間。如果指定為BEFORE,則表示在執行DML操作之前觸發,以便防止某些錯誤操作發生或實現某些業務規則;如果指定為AFTER,則表示在執行DML操作之後觸發,以便記錄該操作或做某些事後處理。
- 語句觸發器是對每一個語句觸發一次
- 行觸發器是對語句受影響的每一行觸發一次
行觸發器和語句觸發器的區別表現在:行觸發器要求當一個DML語句操走影響資料庫中的多行資料時,對於其中的每個資料行,只要它們符合觸發約束條件,均啟用一次觸發器;而語句觸發器將整個語句操作作為觸發事件,當它符合約束條件時,啟用一次觸發器。當省略FOR EACH ROW 選項時,BEFORE 和AFTER 觸發器為語句觸發器,而INSTEAD OF 觸發器則為行觸發器。
比如 插入500行的 insert 命令,語句觸發器只觸發一次,而行觸發器出發了500次
- 行觸發器有 for each row子句。語句觸發器沒有for each row 子句
程式碼
BEFORE DELETE 這兒的 before 可以換成 after
for each row 可以有或者省略
例1: 建立一個觸發器, 當職工表 emp 表被刪除一條記錄時,把被刪除記錄寫到職工表刪除日誌表中去。
CREATE TABLE emp_his AS SELECT * FROM EMP WHERE 1=2;
CREATE OR REPLACE TRIGGER tr_del_emp
BEFORE DELETE --指定觸發時機為刪除操作前觸發
ON scott.emp
FOR EACH ROW --說明建立的是行級觸發器
BEGIN
--將修改前資料插入到日誌記錄表 del_emp ,以供監督使用。
INSERT INTO emp_his(deptno , empno, ename , job ,mgr , sal , comm , hiredate )
VALUES( :old.deptno, :old.empno, :old.ename , :old.job,:old.mgr, :old.sal, :old.comm, :old.hiredate );
END;
DELETE emp WHERE empno=7788;
DROP TABLE emp_his;
DROP TRIGGER del_emp;
Oracle 中預設的相關名稱分別為OLD和NEW。觸發器的PL/SQL塊中應用相關名稱時,必須在它們之前加冒號(:),但在WHEN子句中則不能加冒號。
例2:限制對Departments表修改(包括INSERT,DELETE,UPDATE)的時間範圍,即不允許在非工作時間修改departments表。
CREATE OR REPLACE TRIGGER tr_dept_time
BEFORE INSERT OR DELETE OR UPDATE
ON departments
BEGIN
IF (TO_CHAR(sysdate,'DAY') IN ('星期六', '星期日')) OR (TO_CHAR(sysdate, 'HH24:MI') NOT BETWEEN '08:30' AND '18:00') THEN
RAISE_APPLICATION_ERROR(-20001, '不是上班時間,不能修改departments表');
END IF;
END;
其他示例
我為什麼要使用觸發器?比如,這麼兩個表:
Create Table Student( --學生表
StudentID int primary key, --學號
....
)
Create Table BorrowRecord( --學生借書記錄表
BorrowRecord int identity(1,1), --流水號
StudentID int , --學號
BorrowDate datetime, --借出時間
ReturnDAte Datetime, --歸還時間
...
)
用到的功能有:
1.如果我更改了學生的學號,我希望他的借書記錄仍然與這個學生相關(也就是同時更改借書記錄表的學號);
2.如果該學生已經畢業,我希望刪除他的學號的同時,也刪除它的借書記錄。
等等。
這時候可以用到觸發器。對於1,建立一個Update觸發器:
Create Trigger truStudent
On Student --在Student表中建立觸發器
for Update --為什麼事件觸發
As --事件觸發後所要做的事情
if Update(StudentID)
begin
Update BorrowRecord
Set StudentID=i.StudentID
From BorrowRecord br , Deleted d ,Inserted i --Deleted和Inserted臨時表
Where br.StudentID=d.StudentID
end
SQLServer 理解觸發器裡面的兩個臨時的表:Deleted , Inserted 。注意Deleted 與Inserted分別表示觸發事件的表“舊的一條記錄”和“新的一條記錄”。
一個數據庫系統中有兩個虛擬表用於儲存在表中記錄改動的資訊,分別是:
Tables | 虛擬表Inserted | 虛擬表Deleted |
---|---|---|
在表記錄新增時 | 存放新增的記錄 | 存放新增的記錄 |
修改時 | 存放用來更新的新記錄 | 存放更新前的記錄 |
刪除時 | 不儲存記錄 | 存放被刪除的記錄 |
PL SQL
PL: Procedural LanguagePL/SQL也是一種程式語言,叫做過程化SQL語言(Procedural Language/SQL)。
PL/SQL是Oracle資料庫對SQL語句的擴充套件。在普通SQL語句的使用上增加了程式語言的特點,所以PL/SQL就是把資料操作和查詢語句組織在PL/SQL程式碼的過程性單元中,通過邏輯判斷、迴圈等操作實現複雜的功能或者計算的程式語言。
參見 這兒
plsql 常用函式
事務日誌
事務日誌檔案Transaction Log File,副檔名為ldf。它是用來記錄資料庫更新情況的檔案,它可以記錄針對資料庫的任何操作,並將記錄的結果儲存到獨立的檔案中。對於每一次資料庫更新的過程,事務日誌檔案都有非常全面的記錄。根據這些記錄可以恢復資料庫更新前的狀態。
在 SQL Server 2000中,資料庫至少包括一個數據檔案和事務日誌檔案,資料和事務日誌從不混在一個檔案裡。
在事務日誌已滿的情況下,使用者不能更新資料。backup log語句有雙重的目的,不僅可以備份事務日誌,並且在事務日誌滿的時候,使用者還可以利用他清理事務日誌,移去事務日誌中不活動的部分。
截斷並不減少物理日誌檔案大小,而是減少邏輯日誌檔案的大小並釋放磁碟空間以供重新使用。
通常情況下,事務日誌備份經常與完整備份和差異備份結合使用,比如,每週進行一次完整備份,每天進行一次差異備份,每小時進行一次日誌備份。這樣,最多隻會丟失一個小時的資料。
如何檢視最早開始的活動事務的開始時間及伺服器程序 ID
連線到某個資料庫,執行 DBCC OPENTRAN
命令,檢視 SPID 和 Start time 行。