国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > SQL Server > 正文

把Oracle數據庫移植到Microsoft SQL Server 7.0

2024-08-31 00:52:08
字體:
來源:轉載
供稿:網友
 把Oracle數據庫移植到Microsoft SQL Server 7.0

摘要:本文是為那些想把自己的Oracle應用程序轉換為Microsoft SQL Server應用程序的開發人員編寫的。本文描述了一個成功的轉換所需要的工具、過程和技術。同時強調了建立高性能、高度并行的SQL Server應用程序的基本的設計要素。

本文的讀者應該具有: Oracle關系型數據治理系統(RDBMS)的堅實基礎。 普通數據庫治理知識。 熟悉Oracle SQL和PL/SQL語言。 C/C++編程語言的工作經驗。 在sysadmin組中設定服務器規則的成員資格
本文假定你熟悉Oracle RDBMS的術語、概念和工具。假如想要了解關于Oracle RDBMS以及它的結構的更多信息,請參考Oracle 7 Server Concepts Manual。對于使用Oracle腳本和示例,仍然假定你熟悉Oracle Server Manager和Oracle SQL*Plus工具。要得到更具體的信息,請參看Oracle文檔。


目錄 開發和應用程序平臺 概述 本文的組織形式 結構和術語 安裝和配置Microsoft SQL Server 定義數據庫對象 加強數據完整性和商業規則 事務、鎖定和并行 死鎖 SQL語言支持 實現游標 調整SQL語句 使用ODBC 開發和治理數據庫復制 移植你的數據和應用程序 數據庫示例


開發和應用程序平臺
為了便于清楚的表述,本文參照的開發和應用程序平臺假定為Microsoft Visual Studio version 6.0、Microsoft Windows NT version 4 (Service Pack 4)、SQL Server 7.0、Oracle 7.3。Oracle 7.3使用Visigenic Software ODBC(版本2.00.0300)驅動,SQL Server 7.0使用Microsoft Corporation ODBC(版本3.70)驅動。Microsoft SQL Server 7.0包括針對Oracle的OLE DB驅動,但是該驅動程序在本章中并沒有廣泛的討論。

概述
應用程序的移植似乎非常復雜。在不同的關系數據治理系統之間有太多的結構差異。用來描述Oracle結構的用詞和術語通常與該詞在Microsoft SQL Server中的意思完全不同。另外,Oracle和SQL Server都對SQL-92標準做了許多自有的擴展。

從一個應用程序開發人員的觀點來看,Oracle和SQL Server是以相似的方法來治理數據的。在Oracle和SQL Server之間有著重大的內部區別,但是假如治理得當,可以把這些區別對移植的影響減到最小。

SQL語言擴展
開發人員面臨的最重要的移植問題是執行SQL-92語言標準和每一個關系數據治理系統提供的語言擴展。有一些開發人員只使用標準的SQL語法,喜歡盡可能的保持他們的程序代碼的普遍性。通常,這種方法把程序代碼限制在SQL-92標準的登錄級別(entry-level)上,而這個級別是被許多的數據庫產品實現了的,包括Oracle和SQL Server。

這種方法將會產生一些不必要的程序代碼復雜性而且還會對程序的性能造成很大的影響。例如,Oracle的DECODE函數是一個非標準的SQL擴展。Microsoft SQL Server的CASE表達式是一個超越了登錄級別的SQL-92擴展,而且在所有其他的數據庫產品中都沒有實現。

Oracle的DECODE和SQL Server的CASE都是可選的,你可以不用這兩個函數而實現它們的功能,而這需要從關系數據治理系統中提取更多的數據。

還有,對SQL語言的程序擴展也會造成困難。Oracle的PL/SQL和SQL Server的Transact-SQL語言在函數上是相似的,但是在語法上不同。在兩種數據庫和程序擴展中間沒有明確的對稱性。因此,你可能會決定不使用想程序和觸發器這樣的存儲的程序。這是很不幸的,因為它們提供了別的任何方式都無法實現的性能和安全性上的優點。

私有開發接口的使用帶來了新的問題。用Oracle OCI(Oracle Call Interface)進行程序轉換通常需要很多資源。開發一個可能用到多個關系數據治理系統的應用程序,最好是考慮使用開放數據庫連接(Open Database Connectivity,ODBC)接口。

ODBC
ODBC是為同多個數據庫治理系統協同工作而設計的。ODBC提供了一個一致的應用程序編程接口(application PRogramming interface,API),該接口使用一個針對數據庫的驅動程序同不同的數據庫協同工作。

一致的應用程序編程接口意味著程序用來建立連接、執行命令以及獲取結果的函數是一樣的,無論該程序是和Oracle還是SQL Server對話。

ODBC同時還定義了一個標準化的調用級別的接口并且針對那些不同數據庫里完成同樣任務但語法不同的SQL函數使用標準的出口次序。ODBC驅動器可以自動的把這個ODBC語法轉化為Oracle或者SQL Server的本地語法,這個過程不需要對程序代碼做任何的修訂。在某些情況下,最好的方法是編寫一個程序并且讓ODBC在運行時間執行轉換處理。


ODBC并不是一個萬能的可以針對任何數據庫實現完全獨立的、完整功能和高性能的解決方案。不同數據庫和第三方經銷商提供了對ODBC不同級別的支持。一些驅動器僅僅實現了核心的API函數,這些函數映射了頂層或者其他接口庫。其他一些驅動器,例如Microsoft SQL Server的驅動器,在一個本地的、高性能的驅動器中提供了完整的2級支持。

假如一個程序僅使用核心的ODBC API,它很可能會丟棄某些數據庫的特征和性能。此外,并不是所有的本地SQL擴展都可以在ODBC出口次序中描述的(例如Oracle的DECODE和SQL Server的CASE表達式)。

另外,書寫SQL語句來利用數據庫優化器是意見很自然的事情。但是在Oracle中用來擴展數據庫性能的技術和方法在Microsoft SQL Server 7.0中不一定是最好的。ODBC接口并不能把一個系統所用的技術翻譯為另一個系統的技術。

ODBC并不影響一個應用程序使用數據庫專有的特征和調整來提高性能,但是應用程序需要某些數據庫專有的代碼部分。ODBC使得在多個數據庫間保持程序結構和多數程序代碼一致變得輕易。

OLE DB
OLE DB是下一代數據訪問技術。Microsoft SQL Server 7.0利用包含在其自身的組件之中的OLE DB。這樣,應用程序開發人員可以考慮使用OLE DB來進行新的SQL Server 7.0開發。微軟在SQL Server 7.0中還提供了支持Oracle 7.3的OLE DB。

OLE DB是微軟用來治理跨組織的數據的戰略性的系統級編程接口。OLE DB是在ODBC特征上建立的具有開放性的設計。ODBC是設計來訪問相關的數據庫的,而OLE DB則是設計來訪問相關的或者不相關的信息源,例如主機上的ISAM/VSAM和分層數據庫,電子郵件和文件系統存儲,文本、圖像和地理數據以及定制的業務對象。

OLE DB了一組COM接口以壓縮不同的數據庫治理服務,同時還答應創建軟件組件來實現這些服務.OLE DB組件包含了數據提供者(保持和顯露數據)、數據消費者(使用數據)以及服務組件(處理和傳輸數據,例如查詢處理器和光標引擎)。

OLE DB接口的設計目的是幫助實現組件的平滑集成,這樣的話OLE DB組件提供商就可以迅速的向市場提供高質量的OLE DB組件了。此外、OLE DB還包含一座連接ODBC的橋梁,如此就可以為今天可以得到的大量的ODBC相關的數據庫驅動程序繼續提供支持了。

本文的組織方式
為了幫助你一步一步的實現從Oracle到SQL Server的轉換,本文的每一部分都有一個關于Oracle7.3和Microsoft SQL Server 7.0的不同之處的概述。同時還包括轉換的考慮,SQL Server 7.0的優勢以及多個實例。

結構和術語
作為成功移植的開始,你應該把握Microsoft SQL Server 7.0所用的基本的結構和術語。這一部分中的許多例子都是從本文包含的Oracle和SQL Server應用程序中截取下來的。
數據庫的定義

在Oracle中,數據庫是指整個Oracle RDBMS環境,并且包含以下組件。
Oracle數據庫處理過程和數據緩存(實例)。

包含一個集中的系統目錄的SYSTEM表空間。 DBA定義的其它表空間(可選的)。 兩個或者多個Redo日志。 存檔的Redo日志(可選) 各種其它文件(控制文件、Init.ora等等)。
一個Microsoft SQL Server數據庫提供了數據、應用程序以及安全機制的邏輯區分,更像一個表空間(tablespaces)。正如Oracle支持多個表空間,SQL Server也支持多個數據庫。表空間也用來提供數據的物理放置,SQL Server通過文件組(filegroups)來提供同樣的功能。

Microsoft SQL Server將缺省的安裝下列數據庫。 model數據庫是所有新建用戶數據庫的模板。 Tempdb數據庫跟Oracle中的臨時表空間很相象,都是用來進行臨時的工作儲存以及排序操作。不同的是,當用戶退出登錄時,Microsoft SQL Server自動刪除其創建的臨時表空間。 Msdb數據庫支持SQL Server代理以及其預定的工作、警報和復制信息。 Northwind和pubs數據庫是用于培訓的實例數據庫。
假如想獲得缺省數據庫的更多信息,請參看SQL Server聯機圖書。
數據庫系統目錄
每個Oracle數據庫都在一個集中系統目錄(或者是數據字典(data dictionary))上運行,該目錄存在于SYSTEM表空間中。而每個Microsoft SQL Server 7.0數據庫都維護一個自己的系統目錄,該目錄包含下列信息:
數據庫對象(表、索引、存儲程序、視圖、觸發器等等)。
約束(Constraints)。 用戶和許可。 用戶定義數據類型。 復制定義。 數據庫所用的文件。
SQL Server同時在master數據庫中保存一個集中系統目錄,該目錄包含系統目錄和每個數據庫的某些信息: 數據庫名和每個數據庫的初始文件位置。 SQL Server登錄賬號。 系統消息。 數據庫配置值。 遠程和/或已連接的服務器。 當前活動信息。 系統存儲過程。

像Oracle中的SYSTEM表空間一樣,SQL Server的master數據庫也必須能訪問任何其他數據庫。同樣,對數據庫做了任何重大的改變以后,通過備份master數據庫來防止失敗是很重要的。數據庫治理員也應該能夠為組成master數據庫的文件做鏡象。

物理和邏輯存儲結構(Physical and Logical Storage StrUCtures)

Oracle RDBMS是由表空間組成的,而表空間又是由數據文件組成的。表空間數據文件被格式化為內部的塊單位。塊的大小,是由DBA在Oracle第一次創建的時候設置的,可以在512到8192個字節的范圍內變動。當一個對象在Oracle表空間中創建的時候,用戶用叫做長度的單位(初始長度((initial extent)、下一個長度(next extent)、最小長度(min extents)、以及最大長度(max extents))來標明該對象的空間大小。一個Oracle長度的大小可以變化,但是要包含一個由至少五個連續的塊構成的鏈。

Microsoft SQL Server在數據庫級別使用文件組來控制表和索引的物理放置。文件組是一個或者多個文件的邏輯容器,一個文件組中的數據按比例填充屬于該文件組的全部文件。
假如沒有顯明的定義和使用文件組,數據庫對象將放置在一個缺省的文件組中,該文件組是在數據庫的創建過程中隱含定義的。文件組答應你進行下列操作:
把大的表分布在多個文件中以提高I/O吞吐量。
把索引存儲在不同的文件中,而不是放在各自的表中,再一次提高I/O吞吐量以及實現磁盤并行操作。
把text、ntext、和image columns(大對象)儲存在一個表的不同文件中。
把數據庫對象放置在特定的磁盤錠(disk spindles)上。
在一個文件組中備份和恢復個別表和表的設置。

SQL Server把文件格式化為叫做頁(pages)的單位。頁的大小固定為8192字節(即8K)。頁按固定為8個連續頁大小的格式組織為長度。當創建表或者索引時,SQL Server自動為其分配一頁,比起分配一個長度來說,儲存較小的表和索引,這種方法要更有效些。

標記數據(Striping Data)
(譯注:Strip--在海量存儲系統(MSS)中,可由給定磁頭位置訪問的數據盒式磁帶中的那部分)
Oracle類型的段對于大多數Microsoft SQL Server安裝來說都不需要。取而代之的是,SQL Server可以利用基于硬件的RAID或者Windows NT軟件RAID來較好的完成數據的分布或者標記。基于硬件的RAID或者Windows NT軟件RAID可以設置一個由多個硬盤組成的標記裝置,使它們看起來就像一個邏輯驅動器一樣。假如數據庫文件是在這個標記裝置上創建的,磁盤子系統就假定為負責通過多個磁盤來進行分布式的I/O裝載。建議治理員使用RAID來將數據分布在多個物理磁盤上。

針對SQL Server的RAID推薦配置是RAID 1(鏡象)或者RAID 5(擁有一個作為冗余的額外的驅動器的標記設備)。RAID 10(對有奇偶的標記設備的鏡象)也是推薦的,但它比起前兩個來要昂貴的多。標記設備在分散數據庫文件上通常的隨機I/O來說是很好的。

假如不能使用RAID,文件組就是一個很有吸引力的選擇了,它提供了RAID可以提供的某些同樣的好處。此外,對于那些可能跨越多個物理RAID陣列的非常大的數據庫來說,文件組可能是一個很好的選擇,它可以通過一種受控制的方式將I/O分布在多個RAID陣列上。

必須優化事務日志文件(Transaction log files),使之適應連續的I/O,并且必須保護該文件以防止單點失敗。因此,建議采用RAID1(鏡象)來做事務日志。該驅動器的大小至少應該和在線恢復日志(online redo logs)以及反轉段表空間兩者加起來的大小一樣才行。創建一個或者更多個日志文件,把邏輯驅動器上定義的空間占滿。和存儲在文件組中的數據不同,事務日志條目總是按順序寫入的,而不是按比例填充的。

欲獲得關于RAID的更多信息,請參看SQL Server聯機圖書,你的Windows NT服務器文檔,以及Microsoft Windows NT資源指南。

事務日志和自動恢復(Transaction Logs and Automatic Recovery)
Oracle RDBMS在每次啟動時執行自動修復。它檢查表空間文件的目錄與在線恢復日志文件中的目錄是否一樣。假如不一樣,Oracle就使用在線恢復日志文件覆蓋表空間文件(roll forward、前滾),然后去掉它在后滾段中發現的所有未完成的事務(roll back,后滾)。假如Oracle不能從在線恢復日志中得到需要的信息,則Oracle就求助于存檔的恢復日志文件。
Microsoft SQL Server 7.0同樣在每次啟動時通過檢查系統中的每個數據庫來執行自動恢復。它首先檢查master數據庫,然后啟動線程以覆蓋系統中的所有數據庫。對于每一個SQL Server數據庫,自動修復機制將檢查事務日志。假如事務日志中包含任何未完成的事務,則該事務后滾。然后自動修復機制再檢查事務日志以找出那些還沒有寫入數據庫的未完成事務。假如找到,則執行該事務,前滾。

SQL Server事務日志包含了Oracle后滾段和Oracle在線恢復日志兩者總的功能。每個數據庫都有自己的事務日志,該日志記錄了數據庫發生的任何改變,并且日志由數據庫的所有用戶共享。當一個事務開始并且發生一次數據修改,則一個BEGIN TRANSACTION事件(同modification事件一樣)被記錄在日志中。在自動恢復的過程中使用該事件來確定事務的起始點。每收到一個數據修改事件,改變都被記入事務日志中,優先寫入其數據庫中。欲了解更多信息,請參看本章后面的"事務、鎖定和并行"部分。

SQL Server有一個自動檢查點機制,該機制確保完成了的事務規則的從SQL Server磁盤緩存中寫入事務日志文件。從數據庫的上一個檢查點算起,任何修改過的緩存頁將被寫入一個檢查點。向數據庫上的這些緩存頁(dirty pages,污損頁)寫入檢查點,確保了所有已完成的事務被寫到磁盤上。該過程縮短了發生失敗(例如能量損耗,power outage)時修復系統的所花的時間。該設置可以用SQL Server Enterprise Manager修改,還可以用Transact-SQL修改(sp_configure系統存儲程序)。

備份和恢復數據
Microsoft SQL Server提供了幾種備份數據的選擇:
完全的數據庫備份
要進行完全的數據庫備份,使用BACKUP DATABASE語句或者"備份向導"(Backup Wizard)。
微分備份(Differential backup)
在經過完全的數據庫備份以后,定期使用BACKUP DATABASE WITH DIFFERENTIAL語句或者"備份向導"來備份改變過的數據和索引頁。

事務日志備份
Microsoft SQL Server中的事務日志有一個獨立的數據庫。該數據庫僅在備份或者被刪除以后才填充。SQL Server 7.0中的缺省設置是事務日志自動增長,直到它用完了所有的可用空間或者達到其設置的最大空間。當事務日志過滿時,它會生成一個錯誤并且阻止任何的數據修改,直到該日志被備份或者被刪除。其他的數據庫不會受到影響。可以用BACKUP LOG語句或者"備份向導"進行事務日志備份。


文件或者文件組備份
SQL Server可以備份文件或者文件組。欲知詳情,請參看SQL Server聯機圖書。
備份可以在數據庫正在使用的時候進行,這樣就可以使那些必須不斷運行的系統進行備份。SQL Server 7.0的備份過程和數據結構已經大大的改進,可以使備份在對事務吞吐量影響最小的情況下達到最大的數據傳輸率。

Oracle和SQL Server都需要一個非凡的日志文件格式。在SQL Server中,這些叫做備份設備的文件是用SQL Server Enterprise Manager、Transact-SQL的sp_addumpdevice存儲程序或者等價的SQL-DMO命令創建的。

雖然備份可以通過手工操作進行,但是建議你使用SQL Server Enterprise Manager和/或者"數據庫維護計劃向導"進行定期的備份,或者基于數據庫活動進行備份。
應用事務日志備份和/或者微分備份,一個數據庫可以按時儲存在一個完全備份數據庫(設備)的特定的點上。數據庫使用備份中包含的信息恢復數據。可以用SQL Server Enterprise Manager、Transact-SQL (RESTORE DATABASE)或者SQL-DMO進行恢復。

就像你可以關掉Oracle存檔器以跳過備份一樣,在Microsoft SQL Server中,db_owner組中的成員可以強制事務日志在檢查點發生的時候抹去目錄。可以用SQL Server Enterprise Manager(刪除檢查點上的日志),Transact-SQL(sp_dboption存儲過程)或者SQL-DMO來完成。
網絡

Oracle SQL*Net支持Oracle數據庫和其客戶端的網絡連接。它們通過透明網絡層數據流協議進行通信,并且答應用戶運行許多不同的網絡協議,而不需要編寫任何非凡的代碼。SQL*Net未包含在核心Oracle數據庫軟件產品中。

在Microsoft SQL Server中,Net庫(網絡庫)支持客戶端和服務器的連接,它們通過列表數據流協議進行通信。這使得可以同時和運行名字管道(Named Pipes)、TCP/IP套接字或者其他交互處理機制(Inter-Process Communication、IPC)的客戶端連接。SQL Server CD-ROM包含了所有的客戶端Net庫,不需要另外購買這些產品了。

SQL Server Net庫選項可以在安裝后修改。客戶端網絡工具為運行Windows NT、Windows 95、 或者Windows 98的客戶端配置缺省的Net庫和服務器連接信息。除非在ODBC數據源的安裝過程中改變或者在ODBC連接字串中顯式的標明,所有的ODBC客戶端也使用同樣的Net庫和服務器連接信息。欲了解關于Net庫的更多信息,請參看SQL Server聯機手冊。
數據庫安全性和角色(Database Security and Roles)
為了把你的Oracle應用程序完整的移植到Microsoft SQL Server 7.0上,你需要明白SQL Server是如何實現數據庫的安全性和角色的。

登錄賬號
登錄賬號答應一個用戶訪問SQL Server數據或者治理選項。登錄賬號答應用戶僅僅是登錄到SQL Server上并且顯示那些可以讓訪客(guest)訪問的數據庫。(guest賬號不是缺省設置的,必須創建)

SQL Server提供了兩種類型的登錄安全性。Windows NT驗證模式(也稱為集成的)和SQL Server驗證模式(也稱為標準的)。SQL Server 7.0還支持標準的和集成的安全性的聯合使用,稱為混合的。

Windows NT驗證模式在檢驗登錄連接時使用Windows NT內建的安全機制,并且依靠用戶的Windows NT安全信任。用戶不需要為SQL Server輸入登錄ID和口令--其登錄信息直接從網絡連接上截取。當發生連接時,一個條目就被寫入syslogins表,并且在Windows NT和SQL Server之間加以驗證。這種方式叫做可信連接,其工作原理同兩臺Windows NT服務器之間的可信關系是一樣的。此功能同Oracle中用于用戶賬號的IDENTIFIED EXTERNALLY選項是類似的。

SQL Server驗證模式在用戶請求訪問SQL Server時要求用戶輸入登錄ID和口令。這種方式又叫做不信任連接。此功能同Oracle中用于用戶賬號的IDENTIFIED BY PASSWord選項是類似的。使用標準安全模式,登錄僅僅提供用戶訪問SQL Server數據庫引擎的能力,不答應用戶訪問用戶數據庫。

欲了解關于安全機制的更多信息,請參看SQL Server聯機手冊。
組、角色和許可(Groups, roles, and permissions)

Microsoft SQL Server和Oracle都使用許可來加強數據庫安全性。SQL Server用語句級的許可來限制創建新的數據庫對象的能力。(同Oracle一樣)

SQL Server還提供了對象級的許可。像Oracle一樣,對象級所有權是分配給對象的創建者的,并且不能過戶。在其他用戶可以訪問對象之前必須給予他們對象級的許可。sysadmin 固定服務器角色、db_owner 固定數據庫角色、或者db_securityadmin 固定數據庫角色的成員同樣可以給予其他用戶對某個用戶對象的許可。

SQL Server語句級和對象級的許可可以直接賦予數據庫用戶賬號。但是,通常更簡單的方法是賦予數據庫角色治理員許可。SQL Server角色用來賦予或者撤消數據庫用戶組的特權(同Oracle角色非常相象)。角色(Roles)是一個帶有非凡數據庫的數據庫對象。每次安裝都有一些固定的服務器角色,這些角色在數據庫之上工作。一個固定服務器角色的例子是sysadmin。Windows NT組也可以作為SQL Server登錄,就像數據庫用戶一樣。許可可以賦予一個Windows NT組或者一個Windows NT用戶。


一個數據庫可以有任意數量的角色或者Windows NT組。缺省的public角色總是可以在任何一個數據庫上找到,這些角色不能被清除。public角色的功能很像Oracle中的PUBLIC賬號。每個數據庫用戶都是public角色的成員。在public角色之外,一個數據庫用戶還可以是任意數量角色的成員。Windows NT用戶或組也可以是任意數量角色的成員,同樣,他們也是public角色的成員。

數據庫用戶和Guest賬號(Database users and the guest account)
在Microsoft SQL Server中,一個用戶登錄賬號必須被授權使用一個數據庫和它的對象。登錄賬號可以用下面方法中的一種來訪問數據庫:
登錄賬號可以被設定為數據庫用戶。
登錄賬號可以在數據庫中使用訪客(Guest)賬號。
一個Windows NT組登錄可以被映射為一個數據庫角色。作為該組成員的單個Windows NT賬號就可以連接到數據庫上。

db_owner或者db_accessadmin角色或者sysadmin固定服務器角色的成員可以創建數據庫用戶賬號角色。一個賬號可以包含一些參數:SQL Server登錄ID,數據庫用戶名(可選)、以及一個角色名(可選)。數據庫用戶名不一定要和用戶登錄ID一樣。假如未提供一個數據庫用戶名,則用戶的登錄ID和數據庫用戶名就是一樣的。假如未提供一個角色名,則該數據庫用戶就僅是public角色的成員。在創建了數據庫用戶之后,用戶可以根據需要分配任意的角色。
db_owner或者db_accessadmin角色的成員也可以創建一個guest賬號。guest賬號答應任意有效的SQL Server登錄賬號訪問一個數據庫,甚至不需要有數據庫用戶賬號。缺省情況下,guest賬號繼續了分配給public角色的特權;但是,這些特權可以修改為多于或者少于public賬號的特權。

一個Windows NT用戶或者一個組的賬號可以被賦予訪問數據庫的權利,就像SQL Server登錄所能做的一樣。假如一個Windows NT組的一個成員連接數據庫,該用戶會收到分配給這個組的許可。假如該用戶是不止一個Windows NT組的成員,則他會收到所有這些組對數據庫的權限的集合。

Sysadmin角色(The sysadmin role)
Microsoft SQL Server sysadmin固定服務器角色中的成員擁有與Oracle DBA組中的成員相似的權限。在SQL Server 7.0中,假如SQL Server是安裝在一臺Windows NT計算機上,那么以sa SQL Server驗證模式登錄的賬號缺省為該角色的成員,也就是本地Administrator組中的成員。一個sysadmin角色中的成員可以增加或者刪除Windows NT用戶和組,以及SQL Server登錄賬號。典型的該角色中的成員有以下職責:
安裝SQL Server。

配置服務器和客戶端。
創建數據庫。*
設立登錄權限和用戶許可。*
將數據導入或者導出SQL Server數據庫。*
備份和恢復數據庫。*
執行和維護復制。
安排無人值守的操作。*
監視和調試SQL Server的性能。*
診斷系統問題。
*這些項目可以委派給其他安全性角色和用戶。

在SQL Server 7.0中,對于sysadmin固定服務器角色中的成員能干什么是沒有限制的。因此,該角色中的成員可以通過一個非凡的SQL Server實例訪問任何數據庫、所有的對象(包括數據)。像一個Oracle DBA一樣,有一些命令和系統程序是只有sysadmin角色中的成員才能使用的。

db_owner角色

雖然Microsoft SQL Server數據庫在使用上和Oracle表空間很相似,但是它們在治理上是不一樣的。每個SQL Server數據庫都是一個自持的治理域。每個數據庫都標明了數據庫所有者(dbo)。該用戶總是db_owner固定數據庫角色的成員。其他用戶也可以是db_owner角色的成員。該角色中的所有成員都可以治理與他的數據庫相關的治理任務。(不象在Oracle中,DBA治理所有數據庫的治理任務)。這些治理任務包括:
治理數據庫訪問。
修改數據庫設置(只讀,單用戶,等等)。
備份和恢復數據庫目錄。
授予和取消數據庫許可。
創建和刪除數據庫對象。
db_owner角色中的成員可以在他們的數據庫上做任何事情。分配給該角色的大多數權利被分給一些固定數據庫角色,或者也可以賦予數據庫用戶。在數據庫上行使db_owner特權并不需要賦予sysadmin服務器范圍特權。

安裝和配置Microsoft SQL Server

了解了Oracle和SQL Server之間基本結構上的差異以后,你就可以開始進行移植過程的第一步了。SQL Server Query Analyzer將用來運行下面的腳本:

  使用Windows NT基于軟件的RAID或者基于硬件的RAID第五級來創建一個足夠放下你的所有數據的邏輯驅動器。對空間的估算可以通過計算被Oracle系統、臨時文件以及應用程序表空間占用的文件空間大小來進行。
使用Windows NT基于軟件的RAID或者基于硬件的RAID第一級創建一個第二邏輯驅動器來放事務日志。該驅動器的大小起碼應該和在線恢復以及后滾表空間的總的大小一致。
使用SQL Server Enterprise Manager創建一個和Oracle應用程序表空間名字一樣的數據庫。(示例應用程序使用的數據庫名字叫做USER_DB)標明文件位置,使它們分別和你在第一步以及第二步中為數據和事務創建的磁盤位置一致。假如你使用多個Oracle表空間,不需要也建議你不要創建多個SQL Server數據庫,RAID會自動為你分配的。 創建SQL Server登錄賬號: USE MASTER
EXEC SP_ADDLOGIN STUDENT_ADMIN, STUDENT_ADMIN

EXEC SP_ADDLOGIN DEPT_ADMIN, DEPT_ADMIN

EXEC SP_ADDLOGIN ENDUSER1, ENDUSER1

GO
為數據庫添加角色: USE USER_DB
EXEC SP_ADDROLE DATA_ADMIN

EXEC SP_ADDROLE USER_LOGON

GO
為角色授予許可: GRANT CREATE TABLE, CREATE TRIGGER, CREATE VIEW,

CREATE PROCEDURE TO DATA_ADMIN

GO
增加作為數據庫用戶賬號的登錄賬號: EXEC SP_ADDUSER ENDUSER1, ENDUSER1, USER_LOGON
EXEC SP_ADDUSER DEPT_ADMIN, DEPT_ADMIN, DATA_ADMIN

EXEC SP_ADDUSER STUDENT_ADMIN, STUDENT_ADMIN, DATA_ADMIN

GO

 

定義數據庫對象

Oracle數據庫對象(表、視圖和索引)可以很輕易的移植到Microsoft SQL Server上,這是因為兩個數據庫都基本遵循SQL-92標準,該標準承認對象定義。把Oracle SQL的表、索引和視圖的定義轉換為SQL Server的表、索引和視圖的定義只需要做相對簡單的語法改變。下表指出了Oracle和Microsoft SQL Server之間的數據庫對象的某些不同之處。
類別Microsoft SQL ServerOracle 列數1024254 行尺寸8060 byte, 外加16 byte用來指向每一個text或者image列無限制 (每行只答應有一個long或者long raw) 最大行數無限制無限制 BLOB類型存儲行中存儲一個16-byte 指針。數據存儲在其他數據頁。每表一個long或者long raw。 必須在行的結尾。數據存儲在行的同一個塊里。分簇表索引每表一個每表一個(index-organized tables) 未分簇的表索引每表249無限制在單一索引中的最大索引列數1616 索引中列值的最大長度900 bytes? block 表名約定[[[server.]database.]owner.]
table_name[schema.]table_name 視圖名約定[[[server.]database.]owner.]
table_name[schema.]table_name 索引名約定[[[server.]database.]owner.]
table_name[schema.]table_name
 

假設你是從一個Oracle腳本或者程序開始的,該腳本或者程序用來創建你的數據庫對象。拷貝你的腳本或者程序并且進行如下修改。這些修改將在本部分的其他地方加以討論。該例子是從示例應用程序腳本Oratable.sql和Sstable.sql中截取的: 確保數據庫對象標識遵循Microsoft SQL Server命名法則。你可能只需要修改索引的名字。 修改數據存儲參數使之能在SQL Server下工作。假如你使用RAID,就不需要任何存儲參數了。 修改Oracle約束定義使之能在SQL Server中工作。假如需要的話,創建一個觸發器以支持外部鍵DELETE CASCADE語句。假如表跨數據庫的話,使用觸發器來增強外部鍵的關系。 修改CREATE INDEX語句以利用分簇的索引。 使用數據轉換服務來創建新的CREATE TABLE語句。回顧該語句,注重Oracle數據類型是如何映射到SQL Server數據類型上的。 清除所有的CREATE SEQUENCE語句。在CREATE TABLE或者ALTER TABLE語句中使用同等列來替換順序的使用。 假如需要的話,修改CREATE VIEW語句。 清除所有對同義字的引用。 評估對Microsoft SQL Server臨時表的使用和其在你的應用程序中的用處。 把所有的Oracle的CREATE TABLE…AS SELECT命令改為SQL Server的SELECT…INTO語句。 評估潛在的對用戶定義規則、數據類型和缺省的使用。
 

數據對象標識符

下表比較了Oracle和Microsoft SQL Server是如何處理對象標識符的。在許多情況下,當移植到SQL Server上時,你不需要改變對象的名字。
OracleMicrosoft SQL  1-30 字符長度。
數據庫名稱:最多8個字符長度。
數據庫連接名稱:最多128個字符長度。1-128 Unicode字符長度。
臨時表名稱:最多116個字符。標識符的名稱必須用:字母、包含文字數字的字符、或者字符_, $, 和 #開頭標識符名稱可以用:字母數字字符、或者_開頭,實際上可以用任何字符開頭。
假如標識符用空格開頭,或者包含了不是_、@、#、或者$的字符,你必須用[](定界符)包圍標識符名稱

假如一個對象用下面這些字符開頭:
@ 則表明該對象是一個本地變量。
# 則該對象是一個本地臨時對象。
## 則該對象是一個全局臨時對象
表空間名必須唯一.數據庫名必須唯一標識符名在用戶賬號(計劃,Schema)范圍內必須唯一。標識符名在數據庫用戶賬號范圍內必須唯一列名在表和視圖范圍內必須唯一。列名在表和視圖范圍內必須唯一。索引名在用戶賬號(Schema)范圍內必須唯一。索引名在數據庫表名范圍內必須唯一
 

修飾表名

當訪問存在于你的用戶賬號中的表時,該表可以簡單的通過未經限制的表名來選中。訪問其他Oracle計劃中的表就需要把該計劃的名字作為前綴加到表名上,兩者之間用點號(.)隔開。Oracle同義字可以提供更高的位置透明度。

涉及到表時,Microsoft SQL Server采用一種不同的方法。因為一個SQL Server登錄賬號可以在多個數據庫中用同一個名字創建一個表,所以采用下面的方法來訪問表和視圖:[[數據庫名字]所有者名字]表名]
用……訪問一個表OracleMicrosoft SQL Server 你的用戶賬號SELECT *
FROM STUDENTSELECT * FROM USER_DB.STUDENT_
ADMIN.STUDENT 其他模式(schema)SELECT * FROM STUDENT_ADMIN.STUDENTSELECT * FROM OTHER_DB.STUDENT_
ADMIN.STUDENT
 

這是一些為Microsoft SQL Server表和視圖命名的指導方針: 使用數據庫名字和用戶名字是可選的。假如一個表只通過名字加以引用(例如,STUDENT),SQL Server在當前數據庫中以當前用戶帳號搜索該表。假如沒有找到,就在數據庫中尋找由dbo的保留用戶名擁有的具有同樣名字的對象。表名在同一個數據庫中的同一個用戶帳號下必須是唯一的。 同一個SQL Server登錄賬號可以在多個數據庫中擁有同樣名字的表。例如,ENDUSER1賬號擁有下列數據庫對象:USER_DB.ENDUSER1.STUDENT和OTHER_DB.ENDUSER1.STUDENT。這里所加的限制是數據庫用戶名而不是SQL Server登錄名,因為兩者不一定要一樣。

同時,這些數據庫的其他用戶可以有同樣名字的對象: USER_DB.DBO.STUDENT USER_DB.DEPT_ADMIN.STUDENT USER_DB.STUDENT_ADMIN.STUDENT OTHER_DB.DBO.STUDENT
 

因此,建議你在引用數據庫對象時包含所有者的名字。假如應用程序有多個數據庫,建議你再把數據庫名字也包含在引用中。假如查詢跨越多個服務器,還要包括服務器名。

SQL Server的每個連接都有一個當前數據庫上下文,這是在登錄時用USE語句設置的。例如,假設有下面的場景: 一個用戶,使用ENDUSER1賬號,登錄到USER_DB數據庫上。用戶請求STUDENT表。SQL Server就查詢ENDUSER1.STUDENT表。假如找到,SQL Server就在USER_DB.ENDUSER1.STUDENT表上做要求的數據庫操作。假如在ENDUSER1數據庫賬號下沒有找到該表,SQL Server就為該數據庫以dbo賬號搜尋USER_DB.DBO.STUDENT。假如還是找不到該表,SQL Server就返回一個錯誤消息,指出該表不存在。 假如另一個用戶,例如DEPT_ADMIN擁有該表,則該表必須以數據庫用戶名作為前綴(DEPT_ADMIN.STUDENT)。另外,數據庫名字缺省為在當前上下文中的數據庫名字。 假如被引用的表在另一個數據庫中,則數據庫名必須作為引用的一部分。例如,要訪問在OTHERDB數據庫中由ENDUSER1擁有的表STUDENT,就需要用OTHER_DB.ENDUSER1.STUDENT來引用。
可以在數據庫和表名之間加兩個點號來省略對象的所有者名。例如,假如應用程序引用STUDENT_DB..STUDENT,SQL Server就做如下搜尋: STUDENT_DB.current_user.STUDENT STUDENT_DB.DBO.STUDENT
 

假如應用程序一次只使用一個數據庫,在做對象引用時省略數據庫名字,這樣的話,該應用程序可以方便的用于其他數據庫。所有的對象引用都隱含的訪問當前所用的數據庫。這對于你要想在同一臺服務器上維持一個測試數據庫和一個產品數據庫時很有用

 

創建表

因為Oracle和SQL Server都支持SQL-92條目級(entry-level)的關于標識RDBMS對象的協議,CREATE TABLE的語法是相似的。
OracleMicrosoft SQL  CREATE TABLE
[schema.]table_name
(
{col_name column_properties
[default_eXPression] [constraint [constraint
[...constraint]]] [[,] constraint]}
[[,] {next_col_name next_constraint}...]
)
[Oracle Specific Data Storage Parameters]CREATE TABLE [server.][database.][owner.] table_name
(
{col_name column_properties[constraint
[constraint [...constraint]]] [[,] constraint]}
[[,] {next_col_name next_constraint}...]
)
[ON filegroup_name]
 

Oracle數據庫對象名字是不分大小寫的。在Microsoft SQL Server中,數據庫對象的名字可以是大小寫敏感的,這要看安裝時的設置。

當SQL Server第一次設置的時候,缺省的排序順序是字典順序,區分大小寫。(可以用SQL ServerSetup來做不同的設置)因為Oracle對象的名字總是唯一的,你在把數據庫對象移植到SQL Server上時不會碰到任何的麻煩。建議你把Oracle和SQL Server中的所有的表和列的名字都寫成大寫的以避免萬一有用戶安裝了區分大小寫的SQL Server時出問題。

 

表和索引存儲參數

對于Microsoft SQL Server,使用RAID通常可以簡化數據庫對象的放置。在表的結構中集成了一個SQL Server的分簇的索引,就像一個Oracle索引組織表一樣。
OracleMicrosoft SQL  CREATE TABLE DEPT_ADMIN.DEPT (
DEPTVARCHAR2(4) NOT NULL,
DNAMEVARCHAR2(30) NOT NULL,
CONSTRAINT DEPT_DEPT_PK
PRIMARY KEY (DEPT)
USING INDEX TABLESPACE USER_DATA
PCTFREE 0 STORAGE (INITIAL 10K NEXT 10K
MINEXTENTS 1 MAXEXTENTS UNLIMITED),
CONSTRAINT DEPT_DNAME_UNIQUE
UNIQUE (DNAME)
USING INDEX TABLESPACE USER_DATA
PCTFREE 0 STORAGE (INITIAL 10K NEXT 10K
MINEXTENTS 1 MAXEXTENTS UNLIMITED)
)
PCTFREE 10PCTUSED 40
TABLESPACE USER_DATA
STORAGE (INITIAL 10K NEXT 10K
MINEXTENTS 1 MAXEXTENTS UNLIMITED
FREELISTS 1)CREATE TABLE USER_DB.DEPT_ADMIN.DEPT (
DEPTVARCHAR(4) NOT NULL,
DNAMEVARCHAR(30) NOT NULL,
CONSTRAINT DEPT_DEPT_PK
PRIMARY KEY CLUSTERED (DEPT),
CONSTRAINT DEPT_DNAME_UNIQUE
UNIQUE NONCLUSTERED (DNAME)
)
 

用SELECT語句創建表

使用Oracle,一個表可以用任何有效的SELECT命令創建。Microsoft SQL Server提供了同樣的功能,但是語法不一樣。
OracleMicrosoft SQL  CREATE TABLE STUDENTBACKUP AS SELECT * FROM STUDENTSELECT * INTO STUDENTBACKUP

FROM STUDENT
 

要SELECT…INTO能夠起作用,必須將使用該程序的數據庫的選項select into/bulkcopy設定為true。(數據庫所有者可以用SQL Server Enterprise Manager或者Transact-SQL的sp_dboption系統存儲程序來設置該選項)。用sp_helpdb系統存儲過程來檢查數據庫的狀態。假如select into/bulkcopy未設定為true,你仍然可以用SELECT語句拷貝到臨時表中,就像下面這樣:

SELECT * INTO #student_backup FROM user_db.student_admin.student

當用SELECT.. INTO語句來創建新的表時,其參考的完整性定義不會轉換到新的表中。

將select into/bulkcopy設定為true的要求可能會使移植的過程變得復雜。假如你必須用SELECT語句拷貝數據到表中,請首先創建表,然后再用INSERT INTO…SELECT語句來載入該表。對于Oracle和SQL Server來說,語法是一樣的,也不需要設置任何數據庫選項。

 

視圖

在Microsoft SQL Server中創建視圖的語法同Oracle一樣。
OracleMicrosoft SQL  CREATE [OR REPLACE] [FORCE
NOFORCE] VIEW [schema.]view_name
[(column_name [, column_name]...)]
AS select_statement
[WITH CHECK OPTION [CONSTRAINT
   name]]
[WITH READ ONLY]CREATE VIEW [owner.]view_name
[(column_name [, column_name]...)]
[WITH ENCRYPTION]
AS select_statement [WITH CHECK OPTION]
 

SQL Server視圖要求表必須存在,并且視圖的所有者必須有訪問在SELECT語句中標明的數據庫的權限(同Oracle中的FORCE選項相似)。

缺省情況下,不會檢查視圖上的數據修改語句來判定受影響的行是否在視圖的范圍內。要檢查所有的修改,請使用WITH CHECK OPTION。對于WITH CHECK OPTION主要的不同之處在于,Oracle將其作為約束來定義,而SQL Server不是。此外,兩者的功能是一樣的。

在定義視圖的時候,Oracle提供了一個WITH READ ONLY選項。SQL Server應用程序可以用僅向視圖用戶提供SELECT權限的方法來達到同樣的結果。

SQL Server和Oracle視圖都支持派生列、使用數學表達式、函數以及常量表達式。SQL Server的某些非凡的不同之處是: 假如數據修改只影響一個基本表,則數據修改語句(INSERT或者UPDATE)可以存在于多個視圖上。單個語句中的數據修改語句不能用在超過一個表上。 READTEXT或者WRITETEXT不能用于視圖中的列。 不能使用ORDER BY、COMPUTE、FOR BROWSE、或者COMPUTE BY子句。 在視圖中不能使用INTO要害字。
當一個視圖是和一個外部連接一起定義的,并且查詢限定在外部接合點的內部表上時,SQL Server和Oracle的結果會有所不同。在大多數情況下,Oracle視圖很輕易轉化為SQL Server視圖。
OracleMicrosoft SQL  CREATE VIEW STUDENT_ADMIN.STUDENT_GPA
   (SSN, GPA)
AS SELECT SSN,    ROUND(AVG(DECODE(grade
,'A', 4
,'A+', 4.3
,'A-', 3.7
,'B', 3
,'B+', 3.3
,'B-', 2.7
,'C', 2
,'C+', 2.3
,'C-', 1.7
,'D', 1
,'D+', 1.3
,'D-', 0.7
,0)),2)
FROM STUDENT_ADMIN.GRADE
GROUP BY SSNCREATE VIEW STUDENT_ADMIN.STUDENT_GPA
   (SSN, GPA)
AS SELECT SSN, ROUND(AVG(CASE grade
WHEN 'A' THEN 4
WHEN 'A+' THEN 4.3
WHEN 'A-' THEN 3.7
WHEN 'B' THEN 3
WHEN 'B+' THEN 3.3
WHEN 'B-' THEN 2.7
WHEN 'C' THEN 2
WHEN 'C+' THEN 2.3
WHEN 'C-' THEN 1.7
WHEN 'D' THEN 1
WHEN 'D+' THEN 1.3
WHEN 'D-' THEN 0.7
ELSE 0
END),2)
FROM STUDENT_ADMIN.GRADE
GROUP BY SSN
 

索引

Microsoft SQL Server提供了分簇和未分簇的索引結構。這些索引是由來自于一個叫做B-tree的樹型結構中的頁構成的(同Oracle中的B-tree索引結構相似)。起始頁(“根”級)說明了表中值的范圍。“根”級頁中的每一個范圍指向其他頁(判定節點),該節點包含了表中值的更小的范圍。以此類推,該節點又可以指向其他的判定節點,這樣就縮小了搜索的范圍。樹型結構的最后一級叫做“葉”級。



分簇的索引

分簇的索引在Oracle中是以索引組織表的形式實現的。一個分簇的索引是一個物理的包含在一個表中的索引。表和索引分享同一塊存儲空間。分簇的索引按索引順序物理的重排數據行,建立起中間判定節點。索引的“葉”頁包含了真實的表數據。這個結構答應每個表只有一個分簇的索引。Microsoft SQL Server為表自動的創建一個分簇的索引,無論該表設置了PRIMARY KEY還是UNIQUE約束。分簇的索引對下面這些是有用的: 主鍵(Primary keys) 不能被更新的列。 返回一個值的范圍的查詢,使用諸如BETWEEN、>、>=、<、以及<=這樣的操作符,例如:
SELECT * FROM STUDENT WHERE GRAD_DATE

BETWEEN '1/1/97' AND '12/31/97'
返回一個大的結果集合的查詢:

SELECT * FROM STUDENT WHERE LNAME = 'SMITH'
被用做排序操作的列(ORDER BY、GROUP BY)
例如,在STUDENT表上,在ssn的主鍵上包含一個未分簇的索引是很有用的,而分簇的索引可以在lname、fname(last name、first name)上創建,因為這是一種常用的區分學生的方法。
分布表上的更新行為可以防止出現“熱點”。熱點通常是由于多個用戶向一個有上升鍵的表中填充而引起的。這樣的情景經常導致行級別的鎖定。
刪除和重建一個分簇的索引在SQL Server中是一種很普通的重新組織表的技術。這是一種確保數據頁在磁盤上是連續的以及重建表中的一些可用空間的簡單的方法。這同Oracle中導出、刪除以及導入一個表是很相似的。

一個SQL Server分簇的索引與Oracle的簇在根本上是不一樣的。一個Oracle的簇。一個Oracle的簇是兩個或者更多的表的物理集合,它們分享同一個數據塊,使用一個公共的列來作為簇鍵。SQL Server沒有與Oracle簇相似的結構。

作為一個普遍的原則,在表上定義一個分簇的索引將提高SQL Server的性能并且加強空間治理。假如你不知道對于給定表的查詢和更新模式,你可以在主鍵上創建一個分簇的索引。

下表摘錄自示例應用程序的源代碼。請注重SQL Server“簇”化索引的使用。
OracleMicrosoft SQL  CREATE TABLE STUDENT_ADMIN.GRADE (
SSNCHAR(9) NOT NULL,
CCODEVARCHAR2(4) NOT NULL,
GRADEVARCHAR2(2) NULL,
CONSTRAINT     GRADE_SSN_CCODE_PK
    PRIMARY KEY (SSN, CCODE)
CONSTRAINT GRADE_SSN_FK
FOREIGN KEY (SSN) REFERENCES
STUDENT_ADMIN.STUDENT (SSN),
CONSTRAINT GRADE_CCODE_FK
FOREIGN KEY (CCODE) REFERENCES
DEPT_ADMIN.CLASS (CCODE)
)CREATE TABLE STUDENT_ADMIN.GRADE (
SSNCHAR(9) NOT NULL,
CCODEVARCHAR(4) NOT NULL,
GRADEVARCHAR(2) NULL,
CONSTRAINT
    GRADE_SSN_CCODE_PK
    PRIMARY KEY CLUSTERED (SSN,     CCODE),
CONSTRAINT GRADE_SSN_FK
    FOREIGN KEY (SSN) REFERENCES
    STUDENT_ADMIN.STUDENT (SSN),
CONSTRAINT GRADE_CCODE_FK
    FOREIGN KEY (CCODE) REFERENCES
    DEPT_ADMIN.CLASS (CCODE)
)
 

未分簇的索引

在未分簇的索引中,索引數據和表數據在物理上是分開的,并且表中的行并不是按順序存儲在索引中的。你可以把Oracle索引定義移植到Microsoft SQL Server未分簇的索引定義上(就像在下表中顯示的一樣)。可是,考慮到性能的緣故,你可能希望選擇表的其中一個索引把它創建為分簇的索引。
OracleMicrosoft SQL  CREATE INDEX
STUDENT_ADMIN.STUDENT_
   MAJOR_IDX
ON STUDENT_ADMIN.STUDENT    (MAJOR)
TABLESPACE USER_DATA
PCTFREE 0
STORAGE (INITIAL 10K NEXT 10K
    MINEXTENTS 1 MAXEXTENTS
    UNLIMITED)CREATE NONCLUSTERED INDEX
STUDENT_MAJOR_IDX
ON USER_DB.STUDENT_
   ADMIN.STUDENT (MAJOR)
 

索引語法和命名

在Oracle中,一個索引的名字在一個用戶賬號中是唯一的。在In Microsoft SQL Server,一個索引的名字在一個表名中必須是唯一的,但是不必在用戶名和數據庫名中唯一。因此,在SQL Server中創建或者刪除索引時,你必須說明表名和索引名。另外,SQL Server的DROP INDEX語句可以一次刪除多個索引。
OracleMicrosoft SQL CREATE [UNIQUE] INDEX [schema].index_name
    ON [schema.]table_name (column_name
    [, column_name]...)
[INITRANS n]
[MAXTRANS n]
[TABLESPACE tablespace_name]
[STORAGE storage_parameters]
[PCTFREE n]
[NOSORT]
DROP INDEX ABC;
CREATE [UNIQUE] [CLUSTERED NONCLUSTERED]
    INDEX index_name ON table (column     [,…n])
[WITH
        [PAD_INDEX]
        [[,] FILLFACTOR = fillfactor]
        [[,] IGNORE_DUP_KEY]
        [[,] DROP_EXISTING]
        [[,] STATISTICS_NORECOMPUTE]
]
[ON filegroup]
   DROP INDEX    USER_DB.STUDENT.DEMO_IDX,    USER_DB.GRADE.DEMO_IDX

 

索引數據存儲參數

Microsoft SQL Server功能選項中的FILLFACTOR選項在很多方面與Oracle中的PCTFREE變量相似。當表的尺寸增加的時候,索引頁也相應改變以容納新的數據。索引必須自己進行重新組合以容納新的數據。只有在創建索引的時候,才使用填充參數百分比,而且在這之后也不加以維護。

FILLFACTOR選項(0~100)控制著在創建索引時應該留下多少空間。假如沒有表明參數,就使用缺省參數,該參數是0,表示將完全填充索引的“葉”頁,并且在每個判定節點為至少一個條目留下空間(假如有兩個條目,則表示是一個不唯一的“簇”化索引)。




一個較低的填充因數將會減少索引頁的分裂,但是會增加B-tree結構的層數。較高的填充因數能更有效的使用索引頁空間,只需要較少的磁盤I/O來訪問索引數據,并且將會減少B-tree結構的層數。

PAD_INDEX選項表示,填充因數也將應用到判定節點頁上,就象要用在索引的數據頁上一樣。

雖然在 Oracle中可能需要調整PCTFREE參數以優化性能。但是在CREATE INDEX語句中很少使用FILLFACTOR參數。填充因數是為性能優化而提供的。但是它僅僅在一個表上為已有數據創建索引時才有用,并且只有在你能精確的猜測數據在未來的變化時才有用。

假如你將Oracle中的PCTFREE參數設為0,可以考慮將它設為100。這在表中不會發生數據輸入和修改(只讀表)時是很有用的。假如填充因數設為100,服務器將創建這樣一個索引,它的每一頁都是完全填滿的。

 

忽略重復的要害字

無論在Oracle還是在Microsoft SQL Server中,用戶都不能在一個或者一些唯一索引的列中輸入重復的值。這樣做將會產生一個錯誤消息。然而,SQL Server答應開發人員選擇INSERT或者UPDATE語句將如何處理這個錯誤。

假如在CREATE INDEX語句中使用了IGNORE_DUP_KEY,并且執行了一個創建重復的要害字的INSERT或者UPDATE語句,SQL Server將給出一個警告信息,并且忽略重復行。假如沒有使用IGNORE_DUP_KEY,SQL Server將給出一個錯誤信息,并且后滾整個INSERT語句。假如需要了解關于這個選項的更多信息,請參看SQL Server聯機手冊。

 

使用臨時表

一個Oracle應用程序也許必須創建一個暫時存在的表。應用程序必須確保在某個時候刪除所有為此目的創建的表。假如應用程序不這樣做,那么表空間將很快變得混亂,難以治理。

Microsoft SQL Server提供了臨時表數據庫對象,這個表就是為上面提到的目的創建的。這樣的表總是在tempdb數據庫中創建的。表的名字決定了該表在tempdb數據庫中要存在多長時間。
表名描述#table_name這個本地臨時表只在用戶會話或者創建它的過程的生命期內存在。在用戶退出登錄或者創建它的過程完成以后,該表自動刪除。該表不能在多個用戶之間共享。其它數據庫用戶不能訪問該表。在該表上不能賦予或者撤消許可。##table_name該表也典型的存在于用戶會話或者創建它的過程的生命期內。但該表可以被多個用戶共享。在最后一個引用它的用戶會話斷開以后,該表自動刪除。所有其它數據庫的用戶都可以訪問該表。在該表上不能賦予或者撤消許可。
 

可以為臨時表定義索引。但是只能在那些在tempdb中顯明的創建的表上創建視圖,這些表的名字前不加#或者##前綴。下面的例子顯示了一個臨時表和相應的索引的創建。當用戶退出的時候,表和索引就自動刪除了。
SELECT SUM(ISNULL(TUITION_PAID,0)) SUM_PAID, MAJOR INTO #SUM_STUDENT
FROM USER_DB.STUDENT_ADMIN.STUDENT GROUP BY MAJOR

CREATE UNIQUE INDEX SUM STUDENT IDX ON #SUM STUDENT (MAJOR)

 

在你的程序代碼中使用臨時表,你可以發現它的好處。

數據類型

同Oracle比起來,Microsoft SQL Server在數據庫類型的選擇上更強大。在Oracle和SQL Server數據類型之間有很多可能的轉換方式。我們建議你使用DTS向導來自動創建新的CREATE TABLE語句。需要的時候,你還可以修改它。
OracleMicrosoft SQL  CHAR推薦使用char。 char 類型的列比varchar列的訪問速度要稍微快一點,因為char列使用一個固定的存儲長度。VARCHAR2
和 LONGvarchar 或者 text. (假如在你的Oracle列中數據值的長度小于或等于8000 bytes ,使用varchar;否則,你必須使用text。) RAW 和
LONG RAWvarbinary 或者 image. (假如在你的Oracle列中數據值的長度小于或等于8000 bytes,使用varbinary;否則,你必須使用image。) NUMBER假如整數在1到255之間, 使用tinyint.
假如整數在-32768到32767之間,使用smallint.
假如整數在-2,147,483,648到2,147,483,647之間,使用int.
假如你需要浮點型的數,使用numeric (精確且可以定標).
注重: 不要使用float或者real, 因為可能會發生截斷(Oracle NUMBER和 SQL Server numeric 不會截斷).
假如你不確定,使用numeric; 它同Oracle NUMBER數據類型非常相似。 DATEdatetime. ROWID使用identity列類型 CURRVAL, NEXTVAL使用identity列類型, 以及@@IDENTITY, IDENT_SEED(), 和IDENT_INCR() 函數。SYSDATEGETDATE(). USERUSER.
 

使用Unicode數據

Unicode規范定義了一個編碼方案,該方案使用單一編碼方式為全世界范圍內業務上使用的所有字符編碼。所有的計算機都能使用單一的Unicode編碼把Unicode數據中的位模式轉換成為字符。這個方案確保了在所有的計算機上,同樣的位模式轉換為同樣的字符。數據可以自由的從一個數據庫或者一臺計算機傳送到另一個上面,而不用考慮接受系統能否把位模式正確的轉換成字符。

使用一個字節來表示字符的方法有一個問題,就是這種數據類型只能表示256個字符。這樣就為不同的語言產生了多個編碼規范(或者叫做代碼頁)。這樣做也不可能處理日文或者韓文這樣有上千個字符的語言。

Microsoft SQL Server把在SQL Server中安裝了代碼頁的字符的位模式轉換成char,varchar,或者text類型的列。客戶端則使用操作系統安裝的代碼頁來解釋字符的位模式。現在有很多不同的代碼頁。有些字符只在某些代碼頁上才有,在別的代碼頁上就沒有。某些字符在某些代碼頁上定義為一種位模式,在另外一些代碼頁上又定義為另一種位模式。假如你要建立一個必須處理各種語言的國際系統時,為那些滿足語言要求或者多個國家的計算機挑選代碼頁就變得非常困難。同樣,在和一個使用不同代碼頁的系統連接時,確保每一臺計算機都能正確的實現字符轉換也非常困難。


Unicode規范使用雙字節編碼方案解決了這個問題。使用雙字節編碼,就有足夠的空間來覆蓋最廣泛使用的商業語言了。因為所有的Unicode系統都采用同樣的位模式來代表所有的字符,在從一個系統轉移到另一個系統的時候,就不會發生字符轉換不正確的問題了。

在SQL Server中,nchat,nvarchar和ntext數據類型支持Unicode數據。假如需要了解關于SQL Server數據類型的更多信息,請參看SQL Server聯機手冊。

 

用戶定義數據類型

可以為model數據庫或者單用戶數據庫創建用戶定義數據類型。假如是為model定義用戶定義數據類型,則該數據類型可以被定義之后所有新創建的用戶數據庫使用。用戶定義數據類型是通過sp_addtype系統存儲程序來定義的。假如需要了解更多信息,請參看SQL Server聯機手冊。

你可以在CREATE TABLE和ALTER TABLE語句中使用用戶定義數據類型,并且為它綁定缺省方式和規則。假如在表的創建過程使用用戶定義數據類型時顯明的定義了nullability,則它比在數據定義時定義的nullability優先級高。

下例顯示了如何創建用戶定義數據類型。參數是用戶類型名字,數據類型和nullability。
sp_addtype gender_type, 'varchar(1)', 'not null'
go

 

這個能力對于解決與Oracle表創建腳本移植到SQL Server上相關的問題是很有用的。例如,要增加一個Oracle的DATE數據類型是非常簡單的。
sp_addtype date, datetime
 

這個功能不能用在那些需要變長度的數據類型上,例如Oracle數據類型NUMBER。假如這樣做,系統將會返回一個錯誤信息,告訴你需要標明數據長度。
sp_addtype varchar2, varchar
Go

Msg 15091, Level 16, State 1

You must specify a length with this physical type.

 

Microsoft timestamp列

timestamp列使得BROWSE模式修改和游標修改操作更有效。timestamp是這樣一個數據類型,含有timestamp列的行有輸入或者修改操作時,該數據類型自動修改。

timestamp列中的值不是按照實際的日期和時間存儲的,而是作為binary(8)或者varbinary(8)存儲的,這個值表示表中一行發生的事件的頻率。一個表只能有一個timestamp列。

假如要了解更多信息,請參看SQL Server聯機手冊。

 

對象級許可

Microsoft SQL Server對象特權可以向任何其他數據庫用戶、數據庫組以及public角色授予、拒絕授予、和撤消。SQL Server不答應對象的所有者授予其他用戶、組或者public角色ALTER TABLE和CREATE INDEX特權,這一點與Oracle不同。這些特權必須被對象所有者保留。

GRANT語句創建一個安全系統的入口許可,該許可答應當前數據庫中的一個用戶可以操作當前數據庫中的數據,或者執行特定的Transact-SQL語句。GRANT語句的語法在Oracle和SQL Server中是一樣的。

DENY語句在安全系統中創建一個條目,拒絕當前數據庫中的一個安全賬號的許可,并且禁止該安全賬號繼續自該賬號所屬的組或者角色成員的許可。Oracle中沒有DENY語句。REVOKE語句清除以前授予給當前數據庫中一個用戶的許可或者拒絕其許可。
OracleMicrosoft SQL  GRANT {ALL [PRIVILEGES][column_list] permission_list [column_list]}
ON {table_name [(column_list)]
view_name [(column_list)]
stored_procedure_name}
TO {PUBLIC name_list }
[WITH GRANT OPTION] GRANT
    {ALL [PRIVILEGES] permission[,…n]}
    {
        [(column[,…n])] ON {table view}
         ON {table view}[(column[,…n])]
         ON {stored_procedure         extended_procedure}
    }
TO security_account[,…n]
[WITH GRANT OPTION]
[AS {group role}]
REVOKE [GRANT OPTION FOR]
    {ALL [PRIVILEGES] permission[,…n]}
    {
        [(column[,…n])] ON {table view}
         ON {table view}[(column[,…n])]
         {stored_procedure         extended_procedure}
    }
{TO FROM}
    security_account[,…n]
[CASCADE]
[AS {group role}]

DENY
    {ALL [PRIVILEGES] permission[,…n]}
    {
        [(column[,…n])] ON {table view}
         ON {table view}[(column[,…n])]
         ON {stored_procedure         extended_procedure}
    }
TO security_account[,…n]
[CASCADE]

 

假如需要了解關于對象級許可的更多信息,請參看 SQL Server聯機手冊。

在Oracle中,REFERENCES特權只能授予用戶。SQL Server則答應把該特權授予數據庫用戶和數據庫組。INSERT、UPDATE、DELETE和SELECT特權的授予在Oracle和SQL Server中以同樣的方式處理。

加強數據完整性和商業規則

加強數據完整性確保數據庫中數據的質量。規劃表時重要的兩個步驟是鑒定列中值的有效性和如何加強列中數據的完整性。數據完整性可以分為四類,它們是以不同的方式進行加強的。

完整性類型如何強制 Entity integrityPRIMARY KEY constraint
UNIQUE constraint
IDENTITY property Domain integrityDomain DEFAULT definition
FOREIGN KEY constraint
CHECK constraint
Nullability Referential integrityDomain DEFAULT definition
FOREIGN KEY constraint
CHECK constraint
Nullability User-defined integrityAll column- and table-level constraints in CREATE TABLE
Stored procedures
Triggers
 

實體完整性(Entity Integrity)

實體完整性把特定表中的一行作為一個唯一的實體加以定義。實體完整性通過索引、UNIQUE約束、PRIMARY KEY約束或者IDENTITY特性加強表中標識列或者主要害字的完整性,

 

為約束命名

你總是可以顯式的命名你的約束。假如你不這樣做,Oracle和Microsoft SQL Server將使用不同的命名慣例來隱式的為約束命名。在命名上的不同會為你的移植帶來不必要的麻煩。在刪除約束或者使約束失效時將會出現問題,因為約束必須通過名字來刪除。顯式命名約束的語法在Oracle和SQL Server中是一樣的。
CONSTRAINT constraint_name
 

主鍵和唯一列

SQL-92標準要求主要害字中的所有值都是唯一的并且該列不答應空值。Oracle和Microsoft SQL Server都是通過自動創建唯一的索引這種方式來強制實現唯一性的,無論是否定義了PRIMARY KEY或者UNIQUE約束。

雖然可以創建一個未分簇的索引,但是SQL Server缺省的為主要害字創建一個分簇的索引。Oracle在主要害字上的索引可以通過刪除約束或者使約束失效的方法來清除,而SQL Server的索引只能通過刪除約束來實現。

無論在哪種RDBMS中,其他要害字都可以定義一個UNIQUE約束。可以在任何表中定義多個UNIQUE約束。UNIQUE約束列可以為空。在SQL Server中,除非另外說明,否則將缺省的創建一個未分簇的索引

在移植你的應用程序時,重要的是注重到SQL Server只答應完全唯一的要害字(單個或者多個列索引)中有一行是NULL值的,而Oracle則答應完全唯一的要害字中任意行是NULL值。
OracleMicrosoft SQL  CREATE TABLE DEPT_ADMIN.DEPT
(DEPT VARCHAR2(4) NOT NULL,
DNAME VARCHAR2(30) NOT NULL,
CONSTRAINT DEPT_DEPT_PK
    PRIMARY KEY (DEPT)
    USING INDEX TABLESPACE
    USER_DATA
    PCTFREE 0 STORAGE (
    INITIAL 10K NEXT 10K
    MINEXTENTS 1 MAXEXTENTS     UNLIMITED),
CONSTRAINT DEPT_DNAME_UNIQUE
    UNIQUE (DNAME)
    USING INDEX TABLESPACE USER_DATA
    PCTFREE 0 STORAGE (
    INITIAL 10K NEXT 10K
    MINEXTENTS 1 MAXEXTENTS
    UNLIMITED)
)CREATE TABLE USER_DB.DEPT_ADMIN.DEPT
(DEPTVARCHAR(4) NOT NULL,
DNAMEVARCHAR(30) NOT NULL,
CONSTRAINT DEPT_DEPT_PK
   PRIMARY KEY CLUSTERED (DEPT),
CONSTRAINT DEPT_DNAME_UNIQUE
   UNIQUE NONCLUSTERED (DNAME)
)
 

增加和清除約束

使約束失效可以改善數據庫性能,并且使數據復制過程更加流暢。例如,當你在一個遠程站點上重建或者復制表中的數據時,你不用重復約束檢查,因為數據的完整性是在它原來輸入數據庫時就檢查過的。你可以編制Oracle應用程序來使能或者失效約束(除了PRIMARY KEY和UNIQUE)。你可以在Microsoft SQL Server的ALTER TABLE語句中使用CHECK和WITH NOCHECK來達到同樣的目的。

下面的插圖顯示了該過程的比較。



在SQL Server中,你在NOCHECK子句上使用ALL要害字來推遲所有的表的約束。

假如你的Oracle應用程序使用CASCADE選項來失效或者刪除PRIMARY KEY或者UNIQUE約束,你也許需要重寫某些代碼,因為CASCADE選項同時失效或者刪除父類和子類的完整性約束。

這是關于語法的示例:
DROP CONSTRAINT DEPT_DEPT_PK CASCADE
 

SQL Server應用程序必須修改成首先刪除子類的約束,然后刪除父類的約束。例如,為了刪除DEPT表上的PRIMARY KEY約束,STUDENT.MAJOR和CLASS.DEPT相關列的外部要害字必須被刪除。這是語法的示例:
ALTER TABLE STUDENT
DROP CONSTRAINT STUDENT_MAJOR_FK

ALTER TABLE CLASS

DROP CONSTRAINT CLASS_DEPT_FK

ALTER TABLE DEPT

DROP CONSTRAINT DEPT_DEPT_PK

 

ALTER TABLE增加和刪除約束的語法在Oracle和SQL Server中的語法是一樣的。

 

生成連續的數字值

假如你的Oracle應用程序使用SEQUENCEs,該選項可以很輕易的改變以利用Microsoft SQL Server的IDENTITY特性。
類別Microsoft SQL Server 語法CREATE TABLE new_employees
( Empid int IDENTITY (1,1), Employee_Name varchar(60),

CONSTRAINT Emp_PK PRIMARY KEY (Empid)
)
If increment interval is 5:
CREATE TABLE new_employees
( Empid int IDENTITY (1,5), Employee_Name varchar(60),
CONSTRAINT Emp_PK PRIMARY KEY (Empid)
) 每個表擁有的標識列一個 答應空值否 使用缺省約束、值不能使用. 強制唯一是 在INSERT, SELECT INTO 或者bulk copy 語句完成以后,查詢最大的當前標識數@@IDENTITY (function) 返回創建標識列時指定的種子值IDENT_SEED('table_name') 返回創建標識列時指定的增加值IDENT_INCR('table_name') SELECT語法當在SELECT, INSERT, UPDATE, 和DELETE語句中引用帶有IDENTITY屬性的列時,可以在列名上使用IDENTOTY要害字
 

雖然IDENTITY特性使一個表中的行記數自動化,但是不同的表,假如每一個都有自己的標識列,可以產生同樣的值。這是因為IDENTITY特性只能在使用它的表上被擔保為唯一的。假如一個應用程序必須生成一個在整個數據庫,或者全世界每一臺聯網計算機上的每一個數據庫中唯一的標識列,可以使用ROWGUIDCOL特性,uniqueidentifier數據類型,以及NEWID函數。SQL Server使用全局獨立的標識列來并入復制,確保該行在所有該表的拷貝中是唯一的標識。

假如需要了解關于創建和修改標識列的更多信息,請參看SQL Server聯機手冊。

 

域完整性

域完整性約束對給定列的有效入口。域完整性是通過限制類型(通過數據類型),格式(通過CHECK約束),或者可能值的范圍(通過REFERENCE和CHECK約束)來實現的。

DEFAULT和CHECK約束

Oracle把缺省(default)當作一個列屬性來對待,而Microsoft SQL Server把缺省當作一個約束來對待。SQL Server的DEFAULT約束可以包含整型值,內建的不帶參數的函數(niladic函數),或者NULL。

要很方便的移植Oracle的DEFAULT列屬性,你應該在SQL Server中定義列級別的不使用約束名字的DEFAULT約束。SQL Server為每一個DEFAULT約束生成一個唯一的名字。

用來定義CHECK約束的語法在Oracle和SQL Server中是一樣的。搜索條件應該用布爾表達式來表示而且不能包含子查詢。列級別的約束只能用在被約束列上,表級別的約束只能用在被約束的表中的列上。可以為一個表定義多個CHECK約束。SQL Server語法答應在一個CREATE TABLE語句中只創建一個列級別的CHECK約束,并且該約束可以有多個條件。

測試你修改過的CREATE TABLE語句的最好方式是使用SQL Server中的SQL Server Query Analyzer,并且只分析語法。輸出結果將會指出任何錯誤。假如需要了解關于約束語法的更多信息,請參看SQL Server聯機手冊。
OracleMicrosoft SQL  CREATE TABLE STUDENT_ADMIN.STUDENT (
SSN CHAR(9) NOT NULL,
FNAME VARCHAR2(12) NULL,
LNAME VARCHAR2(20) NOT NULL,
GENDER CHAR(1) NOT NULL
    CONSTRAINT
    STUDENT_GENDER_CK
    CHECK (GENDER IN ('M','F')),
MAJOR VARCHAR2(4)
DEFAULT 'Undc' NOT NULL,
BIRTH_DATE DATE NULL,
TUITION_PAID NUMBER(12,2) NULL,
TUITION_TOTAL NUMBER(12,2) NULL,
START_DATE DATE NULL,
GRAD_DATE DATE NULL,
LOAN_AMOUNT NUMBER(12,2) NULL,
DEGREE_PROGRAM CHAR(1)
    DEFAULT 'U' NOT NULL
    CONSTRAINT
    STUDENT_DEGREE_CK     CHECK
    (DEGREE_PROGRAM IN ('U', 'M', 'P',     'D')),
...CREATE TABLE USER_DB.STUDENT
   _ADMIN.STUDENT (
SSN CHAR(9) NOT NULL,
FNAME VARCHAR(12) NULL,
LNAME VARCHAR(20) NOT NULL,
GENDER CHAR(1) NOT NULL
   CONSTRAINT STUDENT_GENDER_CK
   CHECK (GENDER IN ('M','F')),
MAJOR VARCHAR(4)
   DEFAULT 'Undc' NOT NULL,
BIRTH_DATE DATETIME NULL,
TUITION_PAID NUMERIC(12,2) NULL,
TUITION_TOTAL NUMERIC(12,2) NULL,
START_DATE DATETIME NULL,
GRAD_DATE DATETIME NULL,
LOAN_AMOUNT NUMERIC(12,2) NULL,
DEGREE_PROGRAM CHAR(1)
   DEFAULT 'U' NOT NULL
   CONSTRAINT STUDENT_DEGREE_CK
     CHECK
     (DEGREE_PROGRAM IN ('U', 'M',
     'P','D')),
...
 

關于用戶定義規則和缺省(default)要注重:關于Microsoft SQL Server規則和缺省的語法是考慮了向后兼容的,但是建議把CHECK約束和DEFAULT約束用在新的開發中。假如需要了解更多的信息,請參看SQL Server聯機手冊。

Nullability

Microsoft SQL Server和Oracle創建列約束來強制nullability。在Oracle的CREATE TABLE和ALTER TABLE語句中,列缺省是NULL,而不是NOT NULL。在Microsoft SQL Server,數據庫和會話的設置可以越過在列定義中使用的數據類型的nullability。


你的所有的SQL腳本(無論是Oracle還是SQL Server),都必須顯明的給出每一列的NULL和NOT NULL定義。要了解這個策略是如何實現的,請參看Oracle.sql和Sstable.sql這兩個示例的表創建腳本。假如沒有顯明的定義,則列的nullability遵循如下的規則。
Null settingsDescription 列是用一個用戶定義數據類型定義的SQL Server 使用在創建數據類型時指定的空值性。使用sp_help 系統存儲過程來獲取數據類型的缺省的空值性 列是用一個系統提供的數據類型定義的假如系統提供的數據類型只有一個選項,則優先使用該選項。當前, bit數據類型只能被定義為NOT NULL。
假如任何會話設置為ON (用SET打開), 則:
假如ANSI_NULL_DFLT_ON是ON, 則指定為NULL.
假如ANSI_NULL_DFLT_OFF是ON, 則指定為NOT NULL.
假如任何數據庫設置被修改過(用sp_dboption 系統存儲過程修改), 則:
假如ANSI null default是true, 則指定為NULL.
假如ANSI null default是false, 則指定為NOT NULLNULL/NOT NULL
沒有定義當沒有顯明的定義時(ANSI_NULL_DFLT選項一個都沒有設定),會話將被修改,并且數據庫被設定為缺省(ANSI null default是false),然后SQL Server指定它為NOT NULL。
 

引用完整性

下表提供了一個用來定義referential完整性約束的語法比較。
約束OracleMicrosoft SQL Server PRIMARY KEY[CONSTRAINT constraint_name]
PRIMARY KEY (col_name [, col_name2 [..., col_name16]])
[USING INDEX storage_parameters][CONSTRAINT constraint_name]
PRIMARY KEY [CLUSTERED NONCLUSTERED] (col_name [, col_name2 [..., col_name16]])
[ON segment_name]
[NOT FOR REPLICATION] UNIQUE[CONSTRAINT constraint_name]
UNIQUE (col_name [, col_name2 [..., col_name16]])
[USING INDEX storage_parameters][CONSTRAINT constraint_name]
UNIQUE [CLUSTERED NONCLUSTERED](col_name [, col_name2 [..., col_name16]])
[ON segment_name]
[NOT FOR REPLICATION] FOREIGN KEY[CONSTRAINT constraint_name]
[FOREIGN KEY (col_name [, col_name2 [..., col_name16]])]
REFERENCES [owner.]ref_table [(ref_col [, ref_col2 [..., ref_col16]])]
[ON DELETE CASCADE][CONSTRAINT constraint_name]
[FOREIGN KEY (col_name [, col_name2 [..., col_name16]])]
REFERENCES [owner.]ref_table [(ref_col [, ref_col2 [..., ref_col16]])]
[NOT FOR REPLICATION] DEFAULTColumn property, not a constraint
DEFAULT (constant_expression)[CONSTRAINT constraint_name]
DEFAULT {constant_expression niladic-function NULL}
[FOR col_name]
[NOT FOR REPLICATION] CHECK[CONSTRAINT constraint_name]
CHECK (expression)[CONSTRAINT constraint_name]
CHECK [NOT FOR REPLICATION] (expression)
 

NOT FOR REPLICATION子句用來在復制過程中掛起列級別,FOREIGN KEY,以及CHECK約束。

 

外部鍵

定義外部要害字的語法在各種RDBMS中都是相似的。在外部要害字中標明的列數和每一列的數據類型必須和REFERENCES子句相匹配。一個輸入到列中的非空的值必須在REFERENCES子句中定義表和列中存在,并且被提及的表的列必須有一個PRIMARY KEY或者UNIQUE約束。

Microsoft SQL Server約束提供了在同一個數據庫中引用表的能力。要實現在數據庫范圍的應用完整性,可以使用基于表的觸發器。

Oracle和SQL Server都支持自引用表,這種表中有對同一個表的一列或幾列的引用。例如,CLASS表中的prereq列可以引用CLASS表中的ccode列以確保一個有效的課程編號是作為一個子句的先決條件輸入的。

在Oracle中實現層疊式的刪除和修改是使用CASCADE DELETE子句,而SQL Server用表觸發器來實現同樣的功能。假如需要了解更多的信息,請參看本章后面的“SQL語言支持”部分 。

 

用戶定義的完整性

用戶定義的完整性答應你定義特定的商業規則,該規則不屬于其他完整性的范疇。

 

存儲過程

Microsoft SQL Server存儲程序用CREATE PROCEDURE語句來接受或者返回用戶提供的參數。除臨時存儲程序以外,存儲程序是在當前數據庫中創建的。下表顯示了Oracle和SQL Server的語法。
OracleMicrosoft SQL  CREATE OR REPLACE PROCEDURE [user.]procedure
    [(argument [IN OUT] datatype
    [, argument [IN OUT] datatype]
{IS AS} blockCREATE PROC[EDURE] procedure_name        [;number]

    [
       {@parameter data_type} [VARYING]        [= default] [OUTPUT]
    ]
    [,…n]
[WITH
    { RECOMPILE    ENCRYPTION
      RECOMPILE, ENCRYPTION} ]
[FOR REPLICATION]
AS
    sql_statement […n]
 

在SQL Server中,臨時存儲程序是在tempdb數據庫中通過在procedure_name前加上數字標記來創建的。加一個數字標記(#procedure_name)表示是一個本地臨時存儲程序,加兩個數字標記(##procedure_name)表示是一個全局臨時程序。

一個本地臨時程序只能被創建它的用戶使用。執行本地臨時程序的許可不能授予其他用戶。本地臨時程序在用戶會話結束時自動刪除。

一個全局的臨時程序可以被所有的SQL Server用戶使用。假如一個全局臨時程序被創建了,所有的用戶都可以訪問它,并且不能顯式的撤回許可。全局臨時程序在最后一個用戶會話結束的時候自動刪除。

SQL Server存儲程序可以有最多32級嵌套。嵌套層數在被調用的程序開始執行時增加,在被調用的程序結束運行時減少。

下面的例子說明了怎樣用一個Transact-SQL存儲程序來代替一個Oracle的PL/SQL封裝函數。Transact-SQL的版本更簡單一些,因為SQL Server的返回結果的能力是在一個存儲程序中直接用SELECT語句設置的,不需要使用游標。
OracleMicrosoft SQL  CREATE OR REPLACE PACKAGE    STUDENT_ADMIN.P1 AS ROWCOUNT    NUMBER :=0;
   CURSOR C1 RETURN    STUDENT%ROWTYPE;
   FUNCTION    SHOW_RELUCTANT_STUDENTS
(WORKVAR OUT VARCHAR2)       RETURN NUMBER;
END P1;
/

CREATE OR REPLACE PACKAGE BODY    STUDENT_ADMIN.P1 AS CURSOR C1    RETURN STUDENT%ROWTYPE IS
      SELECT * FROM       STUDENT_ADMIN.STUDENT
        WHERE NOT EXISTS
      (SELECT 'X' FROM       STUDENT_ADMIN.GRADE
      WHERE       GRADE.SSN=STUDENT.SSN) ORDER       BY SSN;

FUNCTION SHOW_RELUCTANT_STUDENTS
   (WORKVAR OUT VARCHAR2) RETURN    NUMBER IS
   WORKREC STUDENT%ROWTYPE;
   BEGIN
      IF NOT C1%ISOPEN THEN OPEN C1;
      ROWCOUNT :=0;
      ENDIF;
      FETCH C1 INTO WORKREC;
      IF (C1%NOTFOUND) THEN
        CLOSE C1;
        ROWCOUNT :=0;
      ELSE
        WORKVAR := WORKREC.FNAME'         'WORKREC.LNAME
        ', social security number         'WORKREC.SSN' is not enrolled
           in any classes!';
        ROWCOUNT := ROWCOUNT + 1;
      ENDIF;
RETURN(ROWCOUNT);CREATE PROCEDURE
STUDENT_ADMIN.SHOW_
RELUCTANT_STUDENTS
AS SELECT FNAME+'' +LNAME+', social   security number'+ SSN+' is not enrolled in any   classes!'
FROM STUDENT_ADMIN.STUDENT S
WHERE NOT EXISTS
   (SELECT 'X' FROM    STUDENT_ADMIN.GRADE G
   WHERE G.SSN=S.SSN)
ORDER BY SSN
RETURN@@ROWCOUNT
GO       EXCEPTION
WHEN OTHERS THEN
IF C1%ISOPEN THEN CLOSE C1;
ROWCOUNT :=0;
ENDIF;
RAISE_APPLICATION_ERROR(-20001,SQLERRM);
END SHOW_RELUCTANT_STUDENTS;
END P1;
/ 
 

SQL Server不支持與Oracle包或者函數相似的構造,也不支持在創建存儲程序時的CREATE OR REPLACE選項。

 

延遲存儲過程的執行

Microsoft SQL Server提供了WAITFOR,答應開發人員給定一個時間,時間段,或者事件來觸發一個語句塊、存儲程序或者事務的執行。這是Transact-SQL對于Oracle中dbms_lock_sleep的等價。

WAITFOR {DELAY 'time' TIME 'time'}

指示Microsoft SQL Server等待直到給定的時間過去以后再執行,最多可以到24小時。

在這里 DELAY
指示Microsoft SQL Server等待,直到給定數量的時間過去以后才執行,最多可以設置到24小時。
'time'
需要等待的時間,時間可以是任何可接受的datetime數據類型的格式,或者可以作為一個本地變量給出。但是,不能指定datetime值的日期部分。
TIME
指示SQL Server等到指定的時間

例如:
BEGIN
WAITFOR TIME '22:20'

EXECUTE update_all_stats

END

 


指定存儲程序中的參數

要在一個存儲程序中指定一個參數,可以使用下面給出的語法。
OracleMicrosoft SQL  Varname datatype
DEFAULT <value>;{@parameter data_type} [VARYING]
   [= default] [OUTPUT]
 

觸發器(Triggers)

Oracle和Microsoft SQL Server都有觸發器,但它們在執行上有些不同。
描述OracleMicrosoft SQL Server 每表可以有的觸發器數無限制無限制 在INSERT, UPDATE, DELETE之前執行觸發器是否 在INSERT, UPDATE, DELETE之后執行觸發器是是 語句級觸發器有有 行級觸發器有無 在執行之前檢查約束是,除非觸發器被取消是。另外,這是DTS(Data Transformation Services)中的一個選項 在一個UPDATE或者DELETE觸發器中提交舊的或者以前的值:oldDELETED.column 在INSERT觸發器中提交新值:newINSERTED.column 取消觸發器ALTER TRIGGERDTS中的選項
 

DELETED和INSERTED是SQL Server為觸發器創建的概念上的表。該表在結構上同觸發器定義于其上的表相似,并且保存了可能被用戶的行動改變的舊的或者新的行中的值。該表將跟蹤在Transact-SQL中的行一級的變化。這些表提供了與Oracle中的行級別的觸發器同樣的功能。當一個INSERT、UPDATE、或者DELETE語句在SQL Server中執行的時候,行被加入到觸發器表中,而且是同時加入到INSERTED和DELETED表中。

INSERTED和DELETED表同觸發器表是一樣的。它們有同樣的列名和數據類型。例如,假如在GRADE表中放置一個觸發器,那么INSERTED和DELETED就有這樣的結構。
GRADEINSERTEDDELETED SSN CHAR(9)
CCODE VARCHAR(4)
GRADE VARCHAR(2)SSN CHAR(9)
CCODE VARCHAR(4)
GRADE VARCHAR(2)SSN CHAR(9)
CCODE VARCHAR(4)
GRADE VARCHAR(2)
 

INSERTED和DELETED表可以被觸發器檢查以確定要執行什么樣的觸發器行動。INSERTED表同INSERT和UPDATE語句一起使用。DELETED表則和DELETE以及UPDATE語句一起使用。

UPDATE語句使用INSERTED和DELETED表,這是因為進行UPDATE操作時,SQL Server總是要刪除舊的行,填入新的行。因此,執行UPDATE時,INSERTED表中的行總是DELETED表中的行的副本。

下面的例子使用INSERTED和DELETED表來代替PL/SQL中的行級別的觸發器。一個完全的外部接合點被用來查詢任意表中的所有行。
OracleMicrosoft SQL Server CREATE TRIGGER STUDENT_ADMIN.TRACK_GRADES
AFTER
INSERT OR UPDATE OR DELETE
ON STUDENT_ADMIN.GRADE
FOR EACH ROW
BEGIN
INSERT INTO GRADE_HISTORY(
    TABLE_USER, ACTION_DATE,
    OLD_SSN, OLD_CCODE,
    OLD_GRADE, NEW_SSN,
    NEW_CCODE, NEW_GRADE)
VALUES (USER, SYSDATE,
    :OLD.SSN, :OLD.CCODE,    
 :OLD.GRADE, :NEW.SSN,    

 :NEW.CCODE, :NEW.GRADE),
END;
CREATE TRIGGER STUDENT_ADMIN.TRACK_GRADES
ON STUDENT_ADMIN.GRADE
FOR INSERT, UPDATE, DELETE
AS
INSERT INTO GRADE_HISTORY(
   TABLE_USER, ACTION_DATE,
   OLD_SSN, OLD_CCODE, OLD_GRADE
   NEW_SSN, NEW_CCODE,    NEW_GRADE)
SELECT USER, GETDATE(),
   OLD.SSN, OLD.CCODE, OLD.GRADE,
   NEW.SSN, NEW.CCODE, NEW.GRADE
FROM INSERTED NEW FULL OUTER    JOIN
  DELETED OLD ON NEW.SSN = OLD.SSN
 

你可以只在當前數據庫中創建一個觸發器,你也可以引用當前數據庫之外的對象。假如你使用所有者名稱來修飾觸發器,那么就用同樣的方法來修飾表名。

觸發器可以最多嵌套32級。假如一個觸發器改變了某個表,而該表有另外一個觸發器,則第二個觸發器是活動的,可以調用第三個觸發器,如此類推。假如鏈上的任何觸發器引起了死循環,則嵌套級別溢出,該觸發器被取消。此外,假如某表結果上的一行上的一個更新觸發器同時是另一行的更新,那么更新觸發器將只執行一次。

Microsoft SQL Server的公布引用完整性(declarative referential integrity,DRI)沒有提供跨數據庫的引用完整性定義。假如需要跨數據庫的完整性,可以使用觸發器。

下面的語句在Transact-SQL觸發器中是不被答應的。 CREATE 語句(DATABASE, TABLE, INDEX, PROCEDURE, DEFAULT, RULE, TRIGGER, SCHEMA, 和VIEW) DROP 語句(TRIGGER, INDEX, TABLE, PROCEDURE, DATABASE, VIEW, DEFAULT, RULE) ALTER 語句(DATABASE, TABLE, VIEW, PROCEDURE, TRIGGER) TRUNCATE TABLE GRANT, REVOKE, DENY UPDATE STATISTICS RECONFIGURE UPDATE STATISTICS RESTORE DATABASE, RESTORE LOG LOAD LOG, DATABASE DISK語句 SELECT INTO (因為它創建一個表)

 

假如需要了解關于觸發器的更多信息,請參看SQL Server聯機手冊。

事務、鎖定和并行

本部分解釋了在Oracle和Microsoft SQL Server事務是如何執行的,并且提供了所有數據庫類型中鎖定過程和并行問題之間的區別。

 

事務

在Oracle中,執行插入、更新或者刪除操作時自動開始事務。一個應用程序必須給出一個COMMIT命令來保存數據庫的所有修改。假如沒有執行COMMIT,所有的修改都將后滾或者自動變成未完成的。

缺省情況下,Microsoft SQL Server在每次插入、更新或者刪除操作之后自動執行一個COMMIT語句。因為數據是自動保存的,你不能后滾任何改變。你可以使用隱式的或者顯式的事務模式來改變這個缺省行為。

隱式的事務模式答應SQL Server像Oracle一樣運轉,這種模式是用SET IMPLICIT_TRANSACTIONS ON語句激活的。假如該選項是ON并且當前沒有突出的事務,則每一個SQL語句自動開始一個事務。假如有一個打開的事務,則不會有任何新的事務開始。打開的事務必須由用戶用COMMIT TRANSACTION語句來顯明的承諾,以使所有的改變生效并且釋放所有的鎖定。

一個顯明的事務是一組由下述事務分隔符包圍的SQL語句: BEGIN TRANSACTION [transaction_name] COMMIT TRANSACTION [transaction_name] ROLLBACK TRANSACTION [transaction_name savepoint_name]
 

在下面這個例子中,英語系被改變為文學系。請注重BEGIN TRANSACTION和COMMIT TRANSACTION語句的用法。
OracleMicrosoft SQL  INSERT INTO DEPT_ADMIN.DEPT (DEPT, DNAME)
VALUES ('LIT', 'Literature')
/
UPDATE DEPT_ADMIN.CLASS
SET MAJOR = 'LIT'
WHERE MAJOR = 'ENG'
/
UPDATE STUDENT_ADMIN.STUDENT
SET MAJOR = 'LIT'
WHERE MAJOR = 'ENG'
/
DELETE FROM DEPT_ADMIN.DEPT
WHERE DEPT = 'ENG'
/
COMMIT
/BEGIN TRANSACTION

INSERT INTO DEPT_ADMIN.DEPT (DEPT, DNAME)
VALUES ('LIT', 'Literature')

UPDATE DEPT_ADMIN.CLASS
SET DEPT = 'LIT'
WHERE DEPT = 'ENG'

UPDATE STUDENT_ADMIN.STUDENT
SET MAJOR = 'LIT'
WHERE MAJOR = 'ENG'

DELETE FROM DEPT_ADMIN.DEPT
WHERE DEPT = 'ENG'

COMMIT TRANSACTION
GO
 

所有顯明的事務必須用BEGIN TRANSACTION...COMMIT TRANSACTION語句封閉。SAVE TRANSACTION語句的功能同Oracle中的SAVEPOINT命令是一樣的,在事務中設置一個保存點,這樣就可以進行部分后滾(roll back)了。

事務可以嵌套。假如出現了這種情況,最外層的一對創建并提交事務,內部的對跟蹤嵌套層。當碰到一個嵌套的事務時,@@TRANCOUNT函數就增加。通常,這種顯然的事務嵌套發生在存儲程序或者有BEGIN…COMMIT對互相調用的觸發器中。盡管事務可以嵌套,但是對ROLLBACK TRANSACTION語句的行為的影響是很小的。

在存儲過程和觸發器中,BEGIN TRANSACTION語句的個數必須和COMMIT TRANSACTION語句的個數相匹配。包含不匹配的BEGIN TRANSACTION和COMMIT TRANSACTION語句的存儲過程和觸發器在運行的時候會產生一個錯誤消息。語法答應在一個事務中調用包含BEGIN TRANSACTION和COMMIT TRANSACTION語句對的存儲過程和觸發器。

只要情況許可,就應該把一個大的事務分成幾個較小的事務。確保每個事務都在一個單獨的batch中有完整的定義。為了把可能的并行沖突減到最小,事務既不應該跨越多個batch,也不應該等待用戶輸入。把多個事務組合到一個運行時間較長的事務中會給恢復時間帶來消極的影響,并且還會造成并行問題。

在使用ODBC編程的時候,你可以通過使用SQLSetConnectOption函數來選擇顯式或者隱式的事務模式。究竟該選擇哪種模式要視AUTOCOMMIT連接選項的情況而定。假如AUTOCOMMIT是ON(缺省的),你就是在顯式模式中。假如AUTOCOMMIT是OFF,則在隱式模式下。

假如你通過SQL Server Query Analyzer或者其他查詢工具使用腳本,你可以顯式的包括一個上面提到的BEGIN TRANSACTION語句,也可以利用SET IMPLICIT_TRANSACTIONS ON語句來開始腳本。BEGIN TRANSACTION的方法更靈活一些,而隱式的方法更適合Oracle。

 

鎖定和事務孤立

Oracle和Microsoft SQL Server有著很不一樣的鎖定和孤立策略。當你把Oracle應用程序轉化為SQL Server應用程序的時候,你必須考慮到這些不同以確保應用程序的可伸縮性。

Oracle對所有讀數據的SQL語句隱式或者顯式的使用一種多版本一致模型(multiversion consistency model)。在這種模型中,數據讀者在讀數據行以前,缺省的既不獲得一個鎖定也不等待其他的鎖定解開。當讀者需要一個已經改變但別的寫入者還沒有提交的數據時,Oracle通過使用后滾段來重建一個數據行的快照的方法來重新創建舊的數據。

Oracle中的數據寫入者在更新、刪除或者插入數據時要請求鎖定。鎖定將一直維持到事務結束,并且禁止別的用戶覆蓋尚未提交的修改。

Microsoft SQL Server使用多粒度鎖定,該鎖定答應用事務來鎖定不同類型的資源。為了把鎖定的開銷降到最低,SQL Server自動在與任務相配的層次上鎖定資源。以較小的間隔尺寸鎖定,例如行,增強了并行,但是治理開銷較大,因為假如有許多行鎖定,就必須維持多個鎖定。以較大的間隔尺寸鎖定,例如表,在并行方面是昂貴的,因為對整個表的鎖定限制了其他事務對表中任何一部分的訪問,但是治理開銷卻比較小,因為只要維持少數幾個鎖定。SQL Server可以鎖定這些資源(按照間隔尺寸遞增的順序排列)。

資源描述RID行標識符。用于一個單行表的獨立鎖定。Key鍵;索引中的一個行鎖定。用于在一個可串行化的事務中保護鍵范圍。Page8-KB數據頁或者索引頁。Extent相鄰的八個數據頁或者索引頁的組。Table整個表,包括所有數據和索引。DB數據庫。
 

SQL Server使用不同的鎖定模式鎖定資源,使用哪種模式決定了當前事務訪問如何訪問資源。
鎖定模式描述Shared (S)用于那些不修改或者更新數據的操作(只讀操作),例如一個SELECT語句。Update (U)用于那些可以被更新的資源。防止當多個會話被讀入、鎖定,然后潛在的更新資源時發生一個公共形式的死鎖。Exclusive (X)用于數據修改操作,例如UPDATE、INSERT、或者DELETE。確保不會同時發生對同一個資源的多個修改操作。Intent用于建立一個鎖定層次。Schema在一個依靠表的模式的操作執行時使用。有兩種類型的模式鎖定:schema stability (Sch-S)和schema modification (Sch-M)。
 

對于任何RDBMS都很重要的一點是,快速釋放鎖定以提供最大的并行性。你可以通過盡可能短的保持一個事務來確保快速釋放鎖定。假如可能的話,事務不應該跨越多個往返行程到服務器,也不應該包括用戶“思考”的時間。假如你使用游標,你也應該使你的應用程序很快提取數據,因為未提取數據的掃描將在服務器上占據共享鎖定,因此將阻礙更新。欲了解更多信息,請參看本章后面的“使用ODBC”部分。

 

改變缺省的鎖定行為

Microsoft SQL Server和Oracle都答應開發人員使用非缺省的鎖定和孤立行為。在Oracle中,最普通的機制是SELECT 命令的FOR UPDATE子句,SET TRANSACTION READ ONLY命令,以及顯式的LOCK TABLE命令。

因為兩者的鎖定和孤立策略如此不同,所以很難在Oracle和SQL Server之間直接映射鎖定選擇。要更好的理解這一過程,重要的一點是理解SQL Server提供的修改缺省鎖定行為的選擇。

在SQL Server中,修改缺省鎖定行為最常用的機制是SET TRANSACTION ISOLATION LEVEL語句和在SELECT和UPDATE語句中支持的鎖定暗示。SET TRANSACTION ISOLATION LEVEL語句為一個用戶會話的持續時間設定事務孤立級別。除非在一個SQL語句的FROM子句中標明了表級別的鎖定暗示,否則這將變成該會話的缺省行為。事務孤立是這樣設定的:
SET TRANSACTION ISOLATION LEVEL
{

READ COMMITTED

READ UNCOMMITTED

REPEATABLE READ

SERIALIZABLE

}
READ COMMITTED
缺省的SQL Server孤立級別。假如你使用這種選擇,你的應用程序將不能讀取其他事務還沒有提交的數據。在這種模式下,一旦數據從頁上讀出,仍然要釋放共享鎖定。假如應用程序在同一個事務中重新讀取同一個的數據區,將會看到別的用戶做的修改。
SERIALIZABLE
假如設定了這種選擇,事務將同其他事務孤立起來。假如你不希望在查詢中看到其他用戶做的修改,你可以設置事務的孤立級別為SERIALIZABLE。SQL Server將占據所有的共享鎖定,直到事務結束。你可以通過在SELECT語句中表名的后面使用HOLDLOCK暗示來在一個更小的級別上取得同樣的效果。
READ UNCOMMITTED
假如設定為這種選擇,SQL Server讀者將不會受到阻塞,就像在Oracle中一樣。該選擇實現了污損讀取或者說是孤立級別為0的鎖定,這意味著不使用任何共享鎖定并且也不使用任何獨占的鎖定。當這個選項選定后,有可能會讀到未提交的或者污損的數據;在事務結束以前,數據可能會改變,數據集中的行可能出現也可能消失。這個選項同一個事務中在所有SELECT語句中設定所有的表為NOLOCK的效果是一樣的。這是四種孤立級別中限制性最小的一種。只有在你已經徹底的搞清楚了它將對你的應用程序結果的精確度有什么樣的影響的前提下才能使用這種選擇。

 

SQL Server有兩種方法實現Oracle中的READ ONLY功能: 假如一個應用程序中的事務需要可重復讀取的行為,你也許需要使用SQL Server提供的SERIALIZABLE孤立級別。 假如所有的數據庫訪問都是只讀的,你可以設置SQL Server數據庫選項為READ ONLY來提高性能。
 

SELECT…FOR UPDATE

當一個應用程序利用WHERE CURRENT OF 語法來在一個游標上實現定位更新或者刪除時,首先使用Oracle中的SELECT…FOR UPDATE語句。在這種情況下,可以隨意去掉FOR UPDATE子句,因為Microsoft SQL Server游標的缺省行為是“可更新的”。

缺省情況下,SQL Server游標在提取行下不占據鎖定。SQL Server使用一種樂觀的并行策略(optimistic concurrency strategy)來防止更新時相互之間的覆蓋。假如一個用戶試圖更新或者刪除一個讀入游標后已經被修改過的行,SQL Server將給出一個錯誤消息。應用程序可以捕捉該消息,并且重新進行適當的更新或者刪除。要改變這個行為,開發人員可以在游標聲明中使用SCROLL_LOCKS。

通常情況下,樂觀的并行策略支持較高的并行性,所謂通常情況是指更新器之間沖突很少的情況。假如你的應用程序確實需要保證一行在被提取以后不會被修改,你可以在SELECT語句中使用UPDLOCK暗示。這個暗示不會阻礙別的讀者,但是它禁止其他潛在的寫入者也獲得該數據的更新鎖定。使用ODBC時,你可以通過使用SQLSETSTMTOPTION (…,SQL_CONCURRENCY)= SQL_CONCUR_LOCK來達到同樣的目的。但是,其他的任何選擇都將減少并行性。

 

表級別的鎖定

Microsoft SQL Server可以用SELECT…table_name (TABLOCK)語句來鎖定整個表。這和Oracle的 LOCK TABLE…IN SHARE MODE語句是一樣的。該鎖定答應其他人讀取一個表,但是禁止他們修改該表。缺省情況下,鎖定將維持到語句的結束。假如你同時加上了HOLDLOCK要害字(SELECT…table_name (TABLOCK HOLDLOCK)),表的鎖定將一直維持到事務的結束。

可以用SELECT…table_name (TABLOCKX)語句在一個SQL Server表上設置一個獨占的鎖定。該語句請求一個表上的獨占鎖定。該鎖定禁止其他人讀取和修改該表,并且將一直維持到命令或者事務結束。這同Oracle中TABLE…IN EXCLUSIVE MODE語句的功能是一樣的。


SQL Server沒有為顯式的鎖定請求提供NOWAIT選項。

 

鎖定升級

當一個查詢向表請求行時,Microsoft SQL Server自動生成一個頁級別的鎖定。但是,假如查詢請求表中的大部分行時,SQL Server將把鎖定從頁級別升級到表級別。這個過程叫做鎖定升級。

鎖定增加使那些產生較大結果集的表的掃描和操作更加有效,因為它減少了鎖定的治理開銷。缺少WHERE子句的SQL語句一般都要造成鎖定增加。

在讀取操作中,假如一個共享頁級別的鎖定增加為一個表鎖定時,將應用一個共享表鎖定(TABLOCK)。在下列情況下應用共享的表級別的鎖定: 使用了HOLDLOCK或者SET TRANSACTION ISOLATION LEVEL SERIALIZABLE語句。 優化器選擇了一個表的掃描。 表中積累的共享鎖定的數目超過鎖定升級的極限。
表中缺省的鎖定升級的極限是200頁,但是該極限可以用最小和最大范圍定制為依靠于表尺寸的一個百分比。欲了解關于鎖定升級極限的更多信息,請參看SQL Server聯機手冊。

在一個寫操作中,當一個UPDATE鎖定被升級為一個表鎖定時,應用一個獨占表鎖定(TABLOCKX)。獨占表鎖定在下列情況下使用: 更新或者刪除操作無索引可用。 表中有獨占鎖定的頁的數目超過鎖定升級上限。 創建了一個分簇的索引。
 

Oracle不能升級行級別的鎖定,這將導致一些包含了FOR UPDATE子句的查詢出問題。例如,假設STUDENT表有100,000行數據,并且一個Oracle用戶給出下列語句:
SELECT * FROM STUDENT FOR UPDATE
 

這個語句強制Oracle RDBMS依次鎖定STUDENT表的一行;這將花去一段時間。它永遠也不會要求升級鎖定到整個表。

在SQL Server同樣的查詢是:
SELECT * FROM STUDENT (UPDLOCK)
 

當這個查詢運行的時候,頁級別的鎖定升級為表級別的鎖定,后者更加有效并且明顯要快一些。

死鎖

當一個進程鎖定了另一個進程需要的頁或者表的時候,而第二個進程又鎖定了第一個進程需要的一頁,這個時候就會發生死鎖。死鎖也叫抱死。SQL Server自動探測和解決死鎖。假如找到一個死鎖,服務器將終止完成了抱死的用戶進程。

 

在每次數據修改之后,你的程序代碼需要檢查1205號消息,這個消息指出一個死鎖。假如返回這個消息,就說明發生了一個死鎖并且事務已經后滾。在這種情況下,你的應用程序必須重新開始這個事務。

死鎖一般可以通過一些簡單的技術加以避免: 在你的應用程序的各部分以同樣的順序訪問表。 在每個表上使用分簇的索引以強制一個顯式的行順序。 使事務簡短。
欲了解具體信息,請參閱Microsoft Knowledge Base文章“Detecting and Avoiding Deadlocks in Microsoft SQL Server”

 

遠程事務

在Oracle中執行遠程事務,你必須通過一個數據庫連接訪問遠程數據庫節點。在SQL Server中,你必須訪問一個遠程服務器。遠程服務器是一臺運行SQL Server的服務器,用戶可以用他們的本地服務器訪問該服務器。當某個服務器被設置為遠程服務器,用戶就可以在其上使用系統過程和存儲過程而不需要顯式的登錄到上面。

遠程服務器是成對設置的。你必須配置兩臺服務器,使它們互相把對方當作遠程服務器。每臺服務器的名字都必須用sp_addlinkedserver系統存儲過程或者SQL Server Enterprise Manager加到伙伴服務器上。

設置完遠程服務器以后,你可以用sp_addremotelogin系統存儲過程或者SQL Server Enterprise Manager來為那些必須訪問遠程服務器的用戶設置遠程登錄賬號。在這一步完成以后,你還必須賦予他們執行存儲過程的權限。

然后用EXECUTE語句來在遠程服務器上執行過程。這個例子在遠程服務器STUDSVR1上執行了validate_student存儲過程,并且將指明成功或者失敗的返回情況存儲在@retvalue1中:
DECLARE @retvalue1 int
EXECUTE @retvalue = STUDSVR1.student_db.student_admin.validate_student '111111111'

 

欲了解具體信息,請參看SQL Server聯機手冊。

 

分布事務

假如修改兩個或者更多的數據庫節點上的表,Oracle就自動初始化一個分布式事務。SQL Server分布式事務使用包含在SQL Server中的微軟分布事務協調器(Microsoft Distributed Transaction Coordinator,MS DTC)中的兩步提交服務(two-phase commit services)。

缺省情況下,SQL Server必須被通知參與分布事務。SQL Server參與一個MS DTC事務可以用下面方式中的任一種來存儲: BEGIN DISTRIBUTED TRANSACTION語句。該語句開始一個新的MS DTC事務。 一個客戶端應用程序直接調用DTC事務接口。
在下例中,注重對本地表GRADE和遠程表CLASS的分布式更新(使用一個class_name過程):
BEGIN DISTRIBUTED TRANSACTION
UPDATE STUDENT_ADMIN.GRADE

SET GRADE = 'B+' WHERE SSN = '111111111' AND CCODE = '1234'

DECLARE @retvalue1 int

EXECUTE @retvalue1 = CLASS_SVR1.dept_db.dept_admin.class_name '1234', 'Basketweaving'

COMMIT TRANSACTION

GO

 

假如程序不能完成事務,則通過ROLLBACK TRANSACTION語句終止該事務。假如程序失敗或者參與的資源治理器失敗,MS DTC終止該事務。MS DTC不支持分布式的存儲點或者是SAVE TRANSACTION語句。假如一個MS DTC事務失敗或者后滾,則整個事務退回到分布式事務的起點,而不理會任何存儲點。

 

兩步提交處理

Oracle和MS DTC兩步提交機制在操作上是相似的。在SQL Server兩步提交的第一步,事務治理器請求每一個參與的資源治理器預備提交。假如有任何資源治理器沒有預備好,事務治理器就向與事務相關的所有成員廣播一個異常中斷決定。


假如所有的資源治理器都能成功的預備,事務治理器就廣播一個提交決定。這是提交處理的第二步。當一個資源治理器預備好后,事務究竟是提交了還是失敗了,這一點還是拿不準。MS DTC維持了一個連續的日志,因此它的提交或者中斷決定都是持久的。假如某個資源治理器或者事務治理器失敗了,則當它們重新連接上的時候,就能在那個拿不準的事務上協調了。

SQL語言支持

本部分簡要介紹了Transact-SQL和PL/SQL語言語法上的相似和不同之處,并且給出了轉換策略。

SELECT和數據操作聲明

當你把Oracle DML語句和PL/SQL程序移植到SQL Server上時,請按下列步驟進行: 檢查所有SELECT、INSERT、UPDATE、和DELETE語句是否有效。做任何需要的修改。 把所有的外部節點改為SQL-92外部節點語法 用適當的SQL Server函數代替Oracle函數 檢查所有的比較操作符 用“+”代替“”做字符串串聯操作符。 用Transact-SQL程序代替PL/SQL程序 把所有的PL/SQL游標改為無游標SELECT語句或者Transact-SQL游標。 用Transact-SQL過程代替PL/SQL過程、函數和封裝。 把PL/SQL觸發器轉換為Transact-SQL觸發器。 使用SET SHOWPLAN語句來調試你的查詢以獲得高的性能。
 

SELECT statements語句

Oracle和Microsoft SQL Server用的SELECT語句的語法是類似的。
OracleMicrosoft SQL  SELECT [/*+ optimizer_hints*/]
[ALL DISTINCT] select_list
[FROM
{table_name view_name    select_statement}]
[WHERE clause]
[GROUP BY group_by_expression]
[HAVING search_condition]
[START WITH … CONNECT BY]
[{UNION UNION ALL INTERSECT
MINUS} SELECT …]
[ORDER BY clause]
[FOR UPDATE]SELECT select_list
[INTO new_table_]
FROM table_source
[WHERE search_condition]
[ GROUP BY [ALL] group_by_expression [,…n]
        [ WITH { CUBE ROLLUP } ]
[HAVING search_condition]
[ORDER BY order_expression [ASC DESC] ]
In addition:

UNION Operator
COMPUTE Clause
FOR BROWSE Clause
OPTION Clause

 

SQL Server不支持面向Oracle的基于開銷的優化器暗示,必須把這些暗示清除掉。建議使用SQL Server的基于開銷的優化器。欲了解具體信息,請參閱本章后面的“調試SQL語句”部分。

SQL Server不支持Oracle的START WITH…CONNECT BY子句。在SQL Server中,你可以用創建一個執行同樣任務的存儲過程來代替。

SQL Server不支持Oracle的INTERSECT和MINUS集合。SQL Server的EXISTS和NOT EXISTS子句可以完成同樣的任務。

下面的例子使用INTERSECT操作符來為所有有學生的班級找到課程代碼和課程名稱。注重EXISTS操作符是怎樣代替INTERSECT操作符的。兩者返回的數據是一樣的。
OracleMicrosoft SQL  SELECT CCODE, CNAME
FROM DEPT_ADMIN.CLASS
INTERSECT
SELECT C.CCODE, C.CNAME
FROM STUDENT_ADMIN.GRADE G,
DEPT_ADMIN.CLASS C
WHERE C.CCODE = G.CCODESELECT CCODE, CNAME
FROM DEPT_ADMIN.CLASS C
WHERE EXISTS
(SELECT 'X' FROM    STUDENT_ADMIN.GRADE G
WHERE C.CCODE = G.CCODE)
 

下例使用MINUS操作符來找出那些沒有學生的班級。
OracleMicrosoft SQL  SELECT CCODE, CNAME
FROM DEPT_ADMIN.CLASS
MINUS
SELECT C.CCODE, C.CNAME
FROM STUDENT_ADMIN.GRADE G,
DEPT_ADMIN.CLASS C
WHERE C.CCODE = G.CCODESELECT CCODE, CNAME
FROM DEPT_ADMIN.CLASSC
WHERE NOT EXISTS
(SELECT 'X' FROM    STUDENT_ADMIN.GRADE G
WHERE C.CCODE = G.CCODE)
 

INSERT語句

Oracle和Microsoft SQL Server用的INSERT語句的語法是類似的。
OracleMicrosoft SQL  INSERT INTO
{table_name view_name select_statement} [(column_list)]
{values_list select_statement}INSERT [INTO]
    {
     table_name [ [AS] table_alias] WITH ( <table_hint_limited> […n])
     view_name [ [AS] table_alias]
     rowset_function_limited
    }

    {    [(column_list)]
        { VALUES ( {    DEFAULT
                            NULL
                            expression
                        }[,…n]

            )
         derived_table
         execute_statement    
        }
    }
     DEFAULT VALUES
 

Transact-SQL語言支持插入表和視圖,但是不支持SELECT語句中的INSERT操作。假如你的Oracle程序這么做了,則必須修改。
OracleMicrosoft SQL  INSERT INTO (SELECT SSN, CCODE,    GRADE FROM GRADE)
VALUES ('111111111', '1111',NULL)INSERT INTO GRADE (SSN, CCODE,    GRADE)
VALUES ('111111111', '1111',NULL)
 

Transact-SQL的values_list參數提供了SQL-92標準的要害字DEFAULT,但這個在Oracle中是不支持的。當執行插入操作的時候,這個要害字給出了要用到的列的缺省值。假如給定的列沒有缺省值,則插入一個NULL。假如該列不答應NULL,則返回一個錯誤消息。假如該列是作為一個時間片數據類型定義的,則插入下一個連續值。

要害字DEFAULT不能用于標識列。要產生下一個連續值,則有IDENTITY屬性的列一定不能列入column_list或者values_clause。你不一定非要用DEFAUL要害字來獲得一列的缺省值。在Oracle中,假如該列沒有被column_list引用并且它有一個缺省值,則缺省值將放入列中。這是執行移植時最兼容的方法。

一個有用的Transact-SQL選項(EXECute procedure_name)是執行一個過程并且用管道把它的輸出值輸出到一個目標表或者視圖。Oracle不答應你這樣做。

UPDATE語句

因為Transact-SQL支持Oracle的UPDATE絕大多數語法,所以只需要很小的修改。
OracleMicrosoft SQL  UPDATE
{table_name view_name    select_statement}
SET [column_name(s) = {constant_value    expression select_statement column_list
   variable_list}
{where_statement}UPDATE
{
table_name [ [AS] table_alias] WITH ( <table_hint_limited> […n])
view_name [ [AS] table_alias]
rowset_function_limited
}
SET
{column_name = {expression DEFAULT NULL}
@variable = expression
@variable = column = expression } [,…n]

{{[FROM {<table_source>} [,…n] ]

[WHERE
<search_condition>] }

[WHERE CURRENT OF
{ { [GLOBAL] cursor_name } cursor_variable_name}
] }
[OPTION (<query_hint> [,…n] )]
 

Transact-SQL的UPDATE語句不支持依靠SELECT語句的更新操作。假如你的Oracle程序這樣做了,你可以把SELECT語句變成一個視圖,然后在SQL Server的UPDATE語句中使用這個視圖名字。請參看前面“INSERT”語句中的例子。

Oracle的UPDATE命令只能使用一個PL/SQL塊中的程序變量。Transact-SQL語言不要求在使用變量時使用塊。
OracleMicrosoft SQL  DECLARE
VAR1 NUMBER(10,2);
BEGIN
    VAR1 := 2500;
    UPDATE     STUDENT_ADMIN.STUDENT
    SET TUITION_TOTAL = VAR1;
END;DECLARE
@VAR1 NUMERIC(10,2)
SELECT @VAR1 = 2500
UPDATE STUDENT_ADMIN.STUDENT
SET TUITION_TOTAL=@VAR1
 

在SQL Server中,要害字DEFAULT可以用來把一列設置為它的缺省值。你不能用Oracle的UPDATE命令來設置一列為它的缺省值。

Transact-SQL和Oracle SQL都支持在一個UPDATE語句中使用子查詢。但是Transact-SQL的FROM子句可以用來創建一個基于節點的UPDATE。這個能力是你的UPDATE語法更加可讀并且在某種意義上提高了性能。
OracleMicrosoft SQL  UPDATE
   STUDENT_ADMIN.STUDENT S
SET TUITION_TOTAL = 1500
WHERE SSN IN (SELECT SSN
FROM GRADE G
WHERE G.SSN = S.SSN
AND G.CCODE = '1234')Subquery:
UPDATE
   STUDENT_ADMIN.STUDENT S
SET TUITION_TOTAL = 1500
WHERE SSN IN (SELECT SSN
FROM GRADE G
WHERE G.SSN = S.SSN
AND G.CCODE = '1234')

FROM clause:

UPDATE
   STUDENT_ADMIN.STUDENT S
SET TUITION_TOTAL = 1500
   FROM GRADE G
      WHERE S.SSN = G.SSN
      AND G.CCODE = '1234'

 

DELETE語句

在大多數情況下,你不需要修改DELETE語句。但是假如你在Oracle中執行依靠SELECT語句的刪除操作,你就必須進行修改,因為在Transact-SQL不支持這種功能。

Transact-SQL支持在WHERE子句中使用子查詢,FROM子句也一樣。后者可以產生更有效的語句。請參看前面在“UPDATE語句”中的例子。

OracleMicrosoft SQL  DELETE [FROM]
{table_name view_name    select_statement}
[WHERE clause] DELETE
[FROM ]
{
table_name [ [AS] table_alias] WITH ( <table_hint_limited> […n])
view_name [ [AS] table_alias]
rowset_function_limited
}

[ FROM {<table_source>} [,…n] ]
[WHERE
{ <search_condition>
    { [ CURRENT OF
{
{ [ GLOBAL ] cursor_name }
cursor_variable_name
}
]
}
]
[OPTION (<query_hint> [,…n])]

 

TRUNCATE TABLE語句

在Oracle和Microsoft SQL Server中TRUNCATE TABLE語句的語法是相似的。TRUNCATE TABLE語句用來把一個表中的所有行清除掉,并且這個操作是不能后滾的。該表的結構和索引仍然存在。DELETE觸發器不會被執行。假如該表被一個FOREIGN KEY引用,則該表不能被砍掉。
OracleMicrosoft SQL  TRUNCATE TABLE table_name
[{DROP REUSE} STORAGE]TRUNCATE TABLE table_name
 

在SQL Server中,這個語句只能由表的所有者給出。在Oracle中,只有當你是表的所有者或者有DELETE TABLE系統特權時才能使用該語句。

Oracle的TRUNCATE TABLE命令可以隨意的釋放被表中的行占據的存儲空間。SQL Server的 TRUNCATE TABLE則總是回收被表中的數據和與之關聯的索引占據的空間。

 

在identity和timestamp列中操作數據

Oracle序列是一種和任何給定的表或者列都不直接相關的數據庫對象。一列和一個序列的關系是在應用程序中實現的,方法是把一個序列的值分配給一個列。因此在同序列一起工作的時候,Oracle并沒有強化任何規則。但是在Microsoft SQL Server的標識列中,值是不能被更新的并且也不能使用DEFAULT要害字。

缺省情況下,數據不能直接插入到一個標識列中。標識列為新插入表的每一行自動產生一個唯一的、順序的數字。這個缺省設置可以用下面的SET語句覆蓋。
SET IDENTITY_INSERT table_name ON
 

當IDENTITY_INSERT設置為ON時,用戶就可以在新行的標識列中插入任何值。為了防止輸入重復的值,必須在該列上創建一個唯一的索引。這個語句的目的是答應用戶為一行重新創建一個偶然被刪除的值。@@IDENTITY可以用來獲取最后一個標識值。

TRUNCATE TABLE語句把一個標識列重新設置為它原來的SEED值。假如你不想為一列重新設置標識值,可以用不帶WHERE子句的DELETE子句來代替TRUNCATE TABLE語句。你必須估計這會給你的Oracle移植帶來什么樣的影響,因為ORACLE SEQUENCES不會跟著TRUNCATE TABLE命令重新設置。

對時間信息(timestamp)列,你只能執行插入或者刪除操作。假如你試圖更新一個時間信息列,你將收到這樣的錯誤消息。
Msg 272, Level 16, State 1 Can't update a TIMESTAMP column.
 

鎖定被請求的行

Oracle用FOR UPDATE子句來鎖定在SELECT命令中指定的行。在Microsoft SQL Server中,你不需要使用它的等價子句,因為這是一個缺省行為。

 

行合計和計算子句

SQL Server的COMPUTE子句用來生成行合計函數(SUM、AVG、MIN、MAX、以及COUNT),這些函數看起來好象是查詢結果的附加行。這答應你看到一組結果的詳情和匯總。你可以為一個子群(subgroups)計算匯總值,還可以為同一組計算更多的合計函數。

Oracle的SELECT命令語法不支持COMPUTE子句。但是,SQL Server的COMPUTE子句就像在Oracle的SQL*Plus查詢工具中能找到的COMPUTE命令一樣的工作。

 

連接子句(Join clauses)

Microsoft SQL Server 7.0答應在一個連接子句中連接多達256個表,包括臨時的和永久的表。在Oracle中,沒有連接限制。

在Oracle中使用外部連接時,外部連接操作符(+)典型的放置在子列(foreign key)的后面。(+)依靠少數幾個唯一值來識別該列。除非子列答應空值,否則總是這樣的。假如子列答應空值,則(+)被放置在父列(PRIMARY KEY或者UNIQUE約束)上。你不能把(+)同時放在等號(=)的兩邊。

用SQL Server,你可以使用(*=)和(=*)外部連接操作符。(*)用來標識一個有很多唯一值的列。假如子列不答應空值,則(*)被放在等號的父列一邊。在Oracle中,(*)的放置正好相反。不能把(*)同時放在等號的兩邊。

(*=)和(=*)被認為是傳統的連接操作符。SQL Server也支持下面列出的SQL-92標準的連接操作符。建議你使用這種語法。SQL-92標準語法比(*)操作符更強大,限制更小。
Join操作描述CROSS JOIN這是兩個表的交叉產物。假如在一個舊式的連接中沒有指定WHERE子句,則返回同一行。在Oracle中,這種類型的連接叫做笛卡兒連接。INNER該連接指定返回所有的內部行。任何不匹配的行將被丟棄。該連接同一個標準的Oracle表連接是一樣的。LEFT[OUTER] 這種類型的連接指定返回右邊表的所有外部行,即使沒有發現任何匹配行。該操作符同Oracle外部連接(+)是一樣的。RIGHT[OUTER] 這種類型的連接指定返回左邊表的所有外部行,即使沒有發現任何匹配行。該操作符同Oracle外部連接(+)是一樣的。FULL [OUTER]假如來自任一表的一行不匹配選擇標準,指定該行被包括到結果集中,并且它的符合其它表的輸出列被設定為NULL。這和把Oracle外部連接操作符放在“=”的兩端是一樣的(col1(+) = col2(+)),而在Oracle中,這是不答應的。

 

下面的例子返回所有學生都要上的課程的一個清單。在學生表和年級表之間定義的外部連接答應顯示所有的學生,甚至那些沒有參加任何課程的學生。在課程表上也有一個外部連接,該連接返回課程名字。假如課程表上沒有加上外部連接,則不會返回那些沒有參加任何課程的學生,因為他們的課程代碼(CCDOE)是空值。
OracleMicrosoft SQL Server SELECT S.SSN AS SSN,
FNAME, LNAME
FROM STUDENT_ADMIN.STUDENT S,
DEPT_ADMIN.CLASS C,
STUDENT_ADMIN.GRADE G
WHERE S.SSN = G.SSN(+)
AND G.CCODE = C.CCODE(+)SELECT S.SSN AS SSN,
FNAME, LNAME
FROM STUDENT_ADMIN.GRADE G
RIGHT OUTER JOIN
STUDENT_ADMIN.STUDENT S
ON G.SSN = S.SSN
LEFT OUTER JOIN
DEPT_ADMIN.CLASS C
ON G.CCODE = C.CCODE
 

用SELECT語句做表名

Microsoft SQL Server和Oracle都支持在執行查詢時用SELECT語句作為表源。SQL Server需要一個別名(alias);而在Oracle中是否使用別名是可選的。
OracleMicrosoft SQL  SELECT SSN, LNAME, FNAME,
TUITION_PAID, SUM_PAID
FROM STUDENT_ADMIN.STUDENT,
(SELECT SUM(TUITION_PAID) SUM_PAID FROM    STUDENT_ADMIN.STUDENT)SELECT SSN, LNAME, FNAME,
TUITION_PAID, SUM_PAID
FROM STUDENT_ADMIN.STUDENT,
(SELECT SUM(TUITION_PAID) SUM_PAID FROM    STUDENT_ADMIN.STUDENT) SUM_STUDENT
 

讀取和修改BLOBs

Microsoft SQL Server用text和image列來實現二進制大對象(binary large objects,BLOBs)。Oracle則用LONG和LONG RAW列來實現BLOBs。在Oracle中,SELECT命令可以查詢LONG和LONG RAW列的值。

在SQL Server中,你可以使用標準的Transact-SQL語句或者專門的READTEXT語句來讀取text和image列中的數據。READTEXT語句答應你讀取text和image列的一部分。Oracle沒有為LONG 和LONG RAW提供等價的語句。

READTEXT語句利用了一個text_pointer,該指針可以用TEXTPTR函數獲取。TEXTPTR函數返回一個指向特定行中的text或者image的指針,假如查詢有多于一行返回的話,則返回指向最后一行中的text或者image的指針。由于TEXTPTR返回的是一個16字節的二進制字符串,所以最好是聲明一個內部變量來保持該文本指針,然后在READTEXT中使用這個變量。

READTEXT語句說明了有幾個字節要返回。位于@@TEXTSIZE函數中的值,限制了返回的字符或者字節的數量,假如該值小于READTEXT聲明的值,就用后者來代替。

SET語句可以用TEXTSIZE參數來說明以字節為單位的由一個SELECT語句返回的文本數據的尺寸。假如你設置一個大小為0的TEXTSIZE,則該尺寸就重設為缺省值(4 KB)。設置TEXTSIZE對@@TEXTSIZE函數有影響。當SQL_MAX_LENGTH 語句選項改變的時候,SQL Server ODBC自動設置TEXTSIZE參數。

在Oracle中,用UPDATE和INSERT命令來改變LONG和LONG RAW列中的值。在SQL Server,你可以用標準的UPDATE和INSERT語句,或者也可以用UPDATETEXT和WRITETEXT語句。UPDATETEXT和WRITETEXT都答應一個nonlogged選項,而且UPDATETEXT還答應對文本或者圖形列的部分更新。

UPDATETEXT可以用來代替已有的數據,刪除已有的數據,或者插入新數據。新插入的數據可以是一個常數值,表名,列名或者文本指針。

WRITETEXT語句完全覆蓋它所影響的列中的任何已有的數據。用WRITETEXT來替換文本數據,用UPDATETEXT來修改文本數據。因為UPDATETEXT語句只修改一個文本或者圖形值的一部分而不是全部的值,所以UPDATETEXT語句更靈活一些。

欲了解具體信息,請參閱SQL Server聯機手冊。

 

函數

本節中的表顯示了Oracle和SQL Server 的scalar-valued和合計函數之間的關系。盡管名字是一樣的,很重要的一點是注重到函數參數的個數和類型之間的區別。那些只有Microsoft SQL Server提供的函數在這個清單中沒有提及,因為本章限制在使現存的Oracle應用程序的移植工作更輕易。例如,這些函數不被Oracle支持:角度(DEGREES),PI(PI),和隨機數(RAND)

 

數字/數學函數

下面是Oracle支持的數字/數學函數以及它們的Microsoft SQL Server等價函數。
函數OracleMicrosoft SQL Server 絕對值ABSABS Arc cosineACOSACOS Arc sineASINASIN Arc tangent of nATANATAN Arc tangent of n and mATAN2ATN2 Smallest integer >= valueCEILCEILING CosineCOSCOS Hyperbolic cosineCOSHCOT Exponential valueEXPEXP Largest integer <= value FLOORFLOOR Natural logarithmLNLOG Logarithm, any baseLOG(N)N/A Logarithm, base 10LOG(10)LOG10 Modulus (remainder)MODUSE MODULO (%) OPERATOR PowerPOWERPOWER Random numberN/ARAND RoundROUNDROUND Sign of numberSIGNSIGN SineSINSIN Hyperbolic sineSINHN/A Square rootSQRTSQRT TangentTANTAN Hyperbolic tangentTANHN/A TruncateTRUNCN/A Largest number in listGREATESTN/A Smallest number in listLEASTN/A Convert number if NULLNVLISNULL

 

字符函數

下面是Oracle支持的字符函數和它們的Microsoft SQL Server等價函數。
函數OracleMicrosoft SQL Server 把字符轉換為ASCIIASCIIASCII 字串連接CONCAT(expression + expression) 把ASCII轉換為字符CHRCHAR 返回字符串中的開始字符(左起)INSTRCHARINDEX 把字符轉換為小寫LOWERLOWER 把字符轉換為大寫UPPERUPPER 填充字符串的左邊LPADN/A 清除開始的空白LTRIMLTRIM 清除尾部的空白RTRIMRTRIM 字符串中的起始模式(pattern)INSTRPATINDEX 多次重復字符串RPADREPLICATE 字符串的語音表示SOUNDEXSOUNDEX 重復空格的字串RPADSPACE 從數字數據轉換為字符數據TO_CHARSTR 子串SUBSTRSUBSTRING 替換字符REPLACESTUFF 將字串中的每個詞首字母大寫INITCAPN/A 翻譯字符串TRANSLATEN/A 字符串長度LENGTHDATELENGTH or LEN 列表中最大的字符串GREATESTN/A 列表中最小的字符串LEASTN/A 假如為NULL則轉換字串NVLISNULL
 

日期函數

下面是Oracle支持的日期函數和它們的Microsoft SQL Server等價函數。
函數OracleMicrosoft SQL Server 日期相加(date column +/- value) or
ADD_MONTHSDATEADD 兩個日期的差(date column +/- value) or
MONTHS_BETWEENDATEDIFF 當前日期和時間SYSDATEGETDATE() 一個月的最后一天LAST_DAYN/A 時區轉換NEW_TIMEN/A 日期后的第一個周日NEXT_DAYN/A 代表日期的字符串TO_CHARDATENAME 代表日期的整數TO_NUMBER
(TO_CHAR))DATEPART 日期舍入ROUNDCONVERT 日期截斷TRUNCCONVERT 字符串轉換為日期TO_DATECONVERT 假如為NULL則轉換日期NVLISNULL
 

轉換函數

下面是Oracle支持的轉換函數和它們的Microsoft SQL Server等價函數。
函數OracleMicrosoft SQL Server 數字轉換為字符TO_CHARCONVERT 字符轉換為數字TO_NUMBERCONVERT 日期轉換為字符TO_CHARCONVERT 字符轉換為日期TO_DATECONVERT 16進制轉換為2進制HEX_TO_RAWCONVERT 2進制轉換為16進制RAW_TO_HEXCONVERT
 

其它行級別的函數

下面是Oracle支持的其它行級別的函數以及它們的Microsoft SQL Server等價函數。
函數OracleMicrosoft SQL Server 返回第一個非空表達式DECODECOALESCE 當前序列值CURRVALN/A 下一個序列值NEXTVALN/A 假如exp1 = exp2, 返回nullDECODENULLIF 用戶登錄賬號ID數字UIDSUSER_ID 用戶登錄名USERSUSER_NAME 用戶數據庫ID數字UIDUSER_ID 用戶數據庫名USERUSER_NAME 當前用戶CURRENT_USERCURRENT_USER 用戶環境(audit trail)USERENVN/A 在CONNECT BY子句中的級別LEVELN/A
 

合計函數

下面是Oracle支持的合計函數和它們的Microsoft SQL Server等價函數。
函數OracleMicrosoft SQL Server AverageAVGAVG CountCOUNTCOUNT MaximumMAXMAX MinimumMINMIN Standard deviationSTDDEVSTDEV or STDEVP SummationSUMSUM VarianceVARIANCEVAR or VARP
 

條件測試

Oracle的DECODE語句和Microsoft SQL Server的CASE表達式都執行條件測試。當test_value中的值和后面的任何表達式匹配的時候,相關的值就返回。假如沒有找到任何匹配的值,就返回default_value。假如沒有指定default_value,在沒有匹配的時候,DECODE和CASE都返回一個NULL。下表顯示了該語句的語法,同時給出了轉換DECODE命令的示例。
OracleMicrosoft SQL  DECODE (test_value,
expression1, value1
[[,expression2, value2] […]]
[,default_value]
)
CREATE VIEW STUDENT_ADMIN.STUDENT_GPA
(SSN, GPA)
AS SELECT SSN, ROUND(AVG(DECODE(grade
,'A', 4
,'A+', 4.3
,'A-', 3.7
,'B', 3
,'B+', 3.3
,'B-', 2.7
,'C', 2
,'C+', 2.3
,'C-', 1.7
,'D', 1
,'D+', 1.3
,'D-', 0.7
,0)),2)
FROM STUDENT_ADMIN.GRADE
GROUP BY SSN
CASE input_expression
WHEN when_expression THEN    result_expression
[[WHEN when_expression THEN    result_expression] [...]]
[ELSE else_result_expression]
END
CREATE VIEW STUDENT_ADMIN.STUDENT_GPA
(SSN, GPA)
AS SELECT SSN, ROUND(AVG(CASE grade
WHEN 'A' THEN 4
WHEN 'A+' THEN 4.3
WHEN 'A-' THEN 3.7
WHEN 'B' THEN 3
WHEN 'B+' THEN 3.3
WHEN 'B-' THEN 2.7
WHEN 'C' THEN 2
WHEN 'C+' THEN 2.3
WHEN 'C-' THEN 1.7
WHEN 'D' THEN 1

WHEN 'D+' THEN 1.3
WHEN 'D-' THEN 0.7
ELSE 0
END),2)
FROM STUDENT_ADMIN.GRADE
GROUP BY SSN

 

CASE表達式可以支持用SELECT語句執行布爾測試,這是DECODE命令所不答應的。欲了解關于CASE表達式的具體信息,請參閱SQL Server聯機手冊。

 

把值轉換為不同的數據類型

Microsoft SQL Server的CONVERT和CAST函數都是多目標轉換函數。它們提供了相似的功能,把一種數據類型的表達式轉換為另一種數據類型的表達式,并且支持多種專門數據的格式。 CAST(expression AS data_type) CONVERT (data type[(length)], expression [, style])
CAST是一個SQL-92標準的函數。這些函數執行同Oracle的TO_CHAR、TO_NUMBER、TO_DATE、HEXTORAW以及RAWTOTEXT函數相同的功能。

這里所指的數據類型是任何表達式將被轉換成為的系統數據類型。不能使用用戶定義的數據類型。長度參數是可選的,該參數用于char、varchar、binary以及varbinary數據類型。答應的最大長度是8000。
轉換OracleMicrosoft SQL Server 字符到數字TO_NUMBER('10')CONVERT(numeric, '10') 數字到字符TO_CHAR(10)CONVERT(char, 10) 字符到日期TO_DATE('04-JUL-97')
TO_DATE('04-JUL-1997',
'dd-mon-yyyy')
TO_DATE('July 4, 1997',
'Month dd, yyyy')CONVERT(datetime, '04-JUL-97')
CONVERT(datetime, '04-JUL-1997')
CONVERT(datetime, 'July 4, 1997') 日期到字符TO_CHAR(sysdate)
TO_CHAR(sysdate, 'dd mon yyyy')
TO_CHAR(sysdate, 'mm/dd/yyyy')CONVERT(char, GETDATE())
CONVERT(char, GETDATE(), 106)
CONVERT(char, GETDATE(), 101) 16進制到2進制HEXTORAW('1F')CONVERT(binary, '1F') 2進制到16進制RAWTOHEX
(binary_column)CONVERT(char, binary_column)
 

請注重字符串是怎樣轉換為日期的。在Oracle中,缺省的日期格式模型是“DD-MON-YY”假如你使用任何其它格式,你必須提供一個合適的日期格式模型。CONVERT函數自動轉換標準日期格式,不需要任何格式模型。

從日期轉換到字符串時,CONVERT函數的缺省輸出是“dd mon yyyy hh:mm:ss:mmm(24h)”。用一個數字風格代碼來格式化輸出,使它能輸出為其它類型的日期格式模型。欲了解CONVERT函數的具體信息,請參閱SQL Server聯機手冊。

下表顯示了Microsoft SQL Server日期的缺省輸出。
Without CenturyWith CenturyStandardOutput -0 or 100 (*) Defaultmon dd yyyy hh:miAM (or PM) 1101USAmm/dd/yy 2102ANSIyy.mm.dd 3103British/Frenchdd/mm/yy 4104Germandd.mm.yy 5105Italiandd-mm-yy 6106-dd mon yy 7107-mon dd, yy 8108-hh:mm:ss -9 or 109 (*) Default millisecondsmon dd yyyy hh:mi:ss:mmm (AM or PM) 10110USAmm-dd-yy 11111Japanyy/mm/dd 12112ISOyymmdd -13 or 113 (*) Europe default dd mon yyyy hh:mm:ss:mmm(24h) 14114-hh:mi:ss:mmm(24h)
 

用戶定義函數

Oracle PL/SQL函數可以在Oracle SQL語句中使用。在Microsoft SQL Server中一般可以通過其它方式來實現同樣的功能。

在SQL Server中可以用表中給出的查詢來代替。
OracleMicrosoft SQL Server SELECT SSN, FNAME, LNAME, )    TUITION_PAID,
   TUITION_PAID/GET_SUM_
   MAJOR(MAJOR)
   AS PERCENT_MAJOR
FROM STUDENT_ADMIN.STUDENTSELECT SSN, FNAME, LNAME, TUITION_PAID, TUITION_PAID/SUM_MAJOR AS PERCENT_MAJOR
FROM STUDENT_ADMIN.STUDENT,
  (SELECT MAJOR,      SUM(TUITION_PAID) SUM_MAJOR
  FROM STUDENT_ADMIN.STUDENT
  GROUP BY MAJOR) SUM_STUDENT
WHERE STUDENT.MAJOR =      SUM_STUDENT.MAJOR CREATE OR REPLACE FUNCTION GET_SUM_MAJOR
(INMAJOR VARCHAR2) RETURN NUMBER
AS SUM_PAID NUMBER;
BEGIN
SELECT SUM(TUITION_PAID) INTO    SUM_PAID
FROM STUDENT_ADMIN.STUDENT
WHERE MAJOR = INMAJOR;
RETURN(SUM_PAID);
END GET_SUM_MAJOR;No CREATE FUNCTION syntax is required; use CREATE PROCEDURE syntax.
 

比較操作符

Oracle和Microsoft SQL Server的比較操作符幾乎是一樣的。
算符OracleMicrosoft SQL Server 等于(=)(=) 大于(>)(>) 小于(<)(<) 大于或等于(>=)(>=) 小于或等于(<=)(<=) 不等于(!=, <>, ^=)(!=, <>, ^=) 不大于,不小于N/A!> , !< 在集合中任意成員中ININ 不在集合中的任何成員中NOT INNOT IN 集合中的任意值ANY, SOMEANY, SOME 提交集合中的所有值!= ALL, <> ALL, < ALL,

> ALL, <= ALL, >= ALL, != SOME, <> SOME,
< SOME, > SOME,
<= SOME, >= SOME!= ALL, <> ALL, < ALL,
> ALL, <= ALL, >= ALL, != SOME, <> SOME,
< SOME, > SOME,
<= SOME, >= SOME 像模式(Like pattern)LIKELIKE 不像模式(Not like pattern)NOT LIKENOT LIKE X和y之間的值BETWEEN x AND yBETWEEN x AND y 不在x和y之間的值NOT BETWEENNOT BETWEEN 值存在EXISTSEXISTS 值不存在NOT EXISTSNOT EXISTS 值{為不為}空IS NULL, IS NOT NULLSame. Also = NULL,
!= NULL for backward compatibility (not recommended).
 

模式匹配

SQL Server的LIKE要害字提供了有用的通配符搜索功能,這個功能在Oracle中不支持。除了所有的RDBMS都支持的(%)和(_)通配符以外,SQL Server還支持([ ])和([^])通配符。

([ ])字符用來查詢在一個范圍內的所有單個字符。例如,假如你需要查詢包含一個從a到f的字符的數據,你可以這樣寫:“LIKE '[a-f]'”或者“LIKE '[abcdef]'”。這些附加的通配符的有效性在下表中給出。
OracleMicrosoft SQL  SELECT * FROM STUDENT_ADMIN.STUDENT
WHERE LNAME LIKE 'A%'
OR LNAME LIKE 'B%'
OR LNAME LIKE 'C%'SELECT * FROM STUDENT_ADMIN.STUDENT
WHERE LNAME LIKE '[ABC]%'
 

[^]通配符用來標記那些不在特定范圍內的字符。例如,假如除了a到f以外的所有字符都是可以接受的,你可以這樣書寫:LIKE '[^a - f]'或者LIKE '[^abcdef]'。

欲了解關于LIKE要害字的具體信息,請參閱SQL Server聯機手冊。

 

在比較中使用NULL

盡管Microsoft SQL Server傳統上支持SQL-92標準的和一些非標準的NULL行為,但是它還是支持Oracle中的NULL的用法。

為了支持分布式查詢,SET ANSI_NULLS必須設定為ON。

在進行連接的時候,SQL Server的SQL Server ODBC驅動程序和OLE DB提供者自動把SET ANSI_NULLS設定為ON。這個設置可以在ODBC數據源、ODBC連接屬性、或者是在連接到SQL Server之前在應用程序中設置的OLE DB連接屬性中進行配置。在從DB-Library應用程序中連接時,SET ANSI_NULLS缺省為OFF。

當SET ANSI_DEFAULTS為ON時,SET ANSI_NULLS被答應。

欲了解關于NULL用法的具體信息,請參閱SQL Server聯機手冊。

 

字串連接

Oracle使用兩個管道符號()來作為字串連接操作符,SQL Server則使用加號(+)。這個差別要求你在應用程序中做小小的修改。
OracleMicrosoft SQL  SELECT FNAME' 'LNAME AS NAME
FROM STUDENT_ADMIN.STUDENTSELECT FNAME +' '+ LNAME AS    NAME
FROM STUDENT_ADMIN.STUDENT
 

流控制(Control-of-Flow)語言

流控制語言控制SQL語句執行流,語句塊以及存儲過程。PL/SQL和Transact-SQL提供了多數相同的結構,但是還是有一些語法差別。

 

要害字

這是兩個RDBMS支持的要害字。
語句Oracle PL/SQLMicrosoft SQL Server
Transact-SQL 聲明變量DECLAREDECLARE 語句塊BEGIN...END;BEGIN...END 條件處理IF…THEN,
ELSIF…THEN,
ELSE
ENDIF;IF…[BEGIN…END]
ELSE <condition>
[BEGIN…END]
ELSE IF <condition>
CASE expression 無條件結束RETURNRETURN 無條件結束當前程序塊后面的語句EXITBREAK 重新開始一個WHILE循環 N/ACONTINUE 等待指定間隔N/A (dbms_lock.sleep)WAITFOR 循環控制WHILE LOOP…END LOOP;

LABEL…GOTO LABEL;
FOR…END LOOP;
LOOP…END LOOP;
WHILE <condition>
BEGIN… END
LABEL…GOTO LABEL
程序注釋/* … */, --/* … */, -- 打印輸出RDBMS_OUTPUT.PUT_
LINEPRINT 引發程序錯誤(Raise program error)RAISE_APPLICATION_
ERRORRAISERROR 執行程序EXECUTEEXECUTE 語句終止符Semicolon (;)N/A
 

聲明變量

Transact-SQL和PL/SQL的變量是用DECLARE要害字創建的。Transact-SQL變量用@標記,并且就像PL/SQL一樣,在第一次創建時,用空值初始化。
OracleMicrosoft SQL  DECLARE
VSSN CHAR(9);
VFNAME VARCHAR2(12);
VLNAME VARCHAR2(20);
VBIRTH_DATE DATE;
VLOAN_AMOUNT NUMBER(12,2);DECLARE
@VSSN CHAR(9),
@VFNAME VARCHAR2(12),
@VLNAME VARCHAR2(20),
@VBIRTH_DATE DATETIME,
@VLOAN_AMOUNT NUMERIC(12,2)

 

Transact-SQL不支持%TYPE和%ROWTYPE變量數據類型定義。一個Transact-SQL變量不能在DECLARE命令中初始化。在Microsoft SQL Server數據類型定義中也不能使用Oracle的NOT NULL和CONSTANT要害字。

像Oracle的LONG和LONG RAW數據類型一樣。文本和圖形數據類型不能被用做變量定義。此外,Transact-SQL不支持PL/SQL風格的記錄和表的定義。

 

給變量賦值

Oracle和Microsoft SQL Server提供了下列方法來為本地變量賦值。
OracleMicrosoft SQL  Assignment operator (:=)SET @local_variable = value SELECT...INTO syntax for selecting column values from a single rowSELECT @local_variable = expression [FROM…] for assigning a literal value, an expression involving other local variables, or a column value from a single row FETCH…INTO syntaxFETCH…INTO syntax
 

這里有一些語法示例
OracleMicrosoft SQL  DECLARE VSSN CHAR(9);
VFNAME VARCHAR2(12);
VLNAME VARCHAR2(20);
BEGIN
VSSN := '123448887';
SELECT FNAME, LNAME INTO VFNAME, VLNAME FROM STUDENTS WHERE SSN=VSSN;
END; DECLARE @VSSN CHAR(9),
@VFNAME VARCHAR(12),
@VLNAME VARCHAR(20)
SET @VSSN = '12355887'
SELECT @VFNAME=FNAME, @VLNAME=LNAME FROM STUDENTS WHERE SSN = @VSSN
 

語句塊

Oracle PL/SQL和Microsoft SQL Server Transact-SQL都支持用BEGIN…END術語來標記語句塊。Transact-SQL不需要在DECLARE語句后使用一個語句塊。假如在Microsoft SQL Server 中的IF語句和WHILE循環中有多于一個語句被執行,則需要使用BEGIN…END語句塊。
OracleMicrosoft SQL  DECLARE
DECLARE VARIABLES ...
BEGIN -- THIS IS REQUIRED SYNTAX
PROGRAM_STATEMENTS ...
IF ...THEN
STATEMENT1;
STATEMENT2;
STATEMENTN;
END IF;
WHILE ... LOOP
STATEMENT1;
STATEMENT2;
STATEMENTN;
END LOOP;
END; -- THIS IS REQUIRED SYNTAXDECLARE
DECLARE VARIABLES ...
BEGIN -- THIS IS OPTIONAL SYNTAX
PROGRAM_STATEMENTS ...
IF ...
BEGIN
STATEMENT1
STATEMENT2
STATEMENTN
END
WHILE ...
BEGIN
STATEMENT1
STATEMENT2
STATEMENTN
END
END -- THIS IS REQUIRED SYNTAX
 

條件處理

Microsoft SQL Server Transact-SQL的條件語句包括IF和ELSE,但不包括Oracle PL/SQL中的ELSEIF語句。可以用嵌套多重IF語句來到達同樣的效果。對于廣泛的條件測試,用CASE表達式也許更輕易和可讀一些。
OracleMicrosoft SQL  DECLARE
VDEGREE_PROGRAM CHAR(1);
VDEGREE_PROGRAM_NAME VARCHAR2(20);
BEGIN
VDEGREE_PROGRAM := 'U';
IF VDEGREE_PROGRAM = 'U' THEN
VDEGREE_PROGRAM_NAME :=
'Undergraduate';
ELSIF VDEGREE_PROGRAM = 'M'         THEN VDEGREE_PROGRAM_
           NAME := 'Masters';
ELSIF VDEGREE_PROGRAM = 'P'            THEN VDEGREE_PROGRAM_
              NAME := 'PhD';
ELSE VDEGREE_PROGRAM_
              NAME := 'Unknown';
END IF;
END;DECLARE
@VDEGREE_PROGRAM CHAR(1),
@VDEGREE_PROGRAM_NAME VARCHAR(20)
SELECT @VDEGREE_PROGRAM = 'U'
SELECT @VDEGREE_PROGRAM_
   NAME = CASE @VDEGREE_PROGRAM
   WHEN 'U' THEN 'Undergraduate'
   WHEN 'M' THEN 'Masters'
   WHEN 'P' THEN 'PhD'.
   ELSE 'Unknown'
END
 

重復執行語句(循環)

Oracle PL/SQL提供了無條件的LOOP和FOR LOOP。Transact-SQL則提供了WHILE循環和GOTO語句。
WHILE Boolean_expression
{sql_statement statement_block}

[BREAK] [CONTINUE]

 

WHILE循環需要測試一個布爾表達式來決定一個或者多個語句的重復執行。只要給定的表達式結果為真,這個(些)語句就一直重復執行下去。假如有多個語句需要執行,則這些語句必須放在一個BEGIN…END塊中。

OracleMicrosoft SQL  DECLARE
COUNTER NUMBER;
BEGIN
COUNTER := 0
WHILE (COUNTER <5) LOOP
COUNTER := COUNTER + 1;
END LOOP;
END;DECLARE
@COUNTER NUMERIC
SELECT@COUNTER = 1
WHILE (@COUNTER <5)
BEGIN
   SELECT @COUNTER =
   @COUNTER +1
END
 

語句的執行可以在循環的內部用BREAK和CONTINUE要害字控制。BREAK要害字使WHILE循環無條件的結束,而CONTINUE要害字使WHILE循環跳過后面的語句重新開始。BREAK要害字同Oracle PL/SQL中的EXIT要害字是等價的。而在Oracle中沒有和CONTINUE等價的要害字

GOTO語句

Oracle和Microsoft SQL Server都有GOTO語句,但是語法不同。GOTO語句使Transact-SQL跳到指定的標號處運行,在GOTO語句后指定標號之間的任何語句都不會被執行。
OracleMicrosoft SQL  GOTO label;
<<label name here>>GOTO label
 

PRINT語句

Transact-SQL的PRINT語句執行同PL/SQL的RDBMS_OUTPUT.put_line過程同樣的操作。該語句用來打印用戶給定的消息。

用PRINT語句打印的消息上限是8,000個字符。定義為char或者varchar數據類型的變量可以嵌入打印語句。假如使用其它數據類型的變量,則必須使用CONVERT或者CAST函數。本地變量、全局變量可以被打印。可以用單引號或者雙引號來封閉文本。

 

從存儲過程返回

Microsoft SQL Server和Oracle都有RETURN語句。RETURN使你的程序從查詢或者過程中無條件的跳出。RETURN是立即的、完全的、并且可以用于從過程、批處理或者語句塊的任意部分跳出。在REUTRN后面的語句將不會被執行。
OracleMicrosoft SQL  RETURN expression:RETURN [integer_expression]
 

引發程序錯誤(Raising program errors)

Transact-SQL的RAISERROR返回一個用戶定義的錯誤消息,并且設置一個系統標志來記錄發生了一個錯誤。這個功能同PL/SQL的raise_application_error異常處理器的功能是相似的。

RAISERROR語句答應客戶重新取得sysmessages表的一個入口,或者用用戶指定的嚴重性和狀態信息動態的建立一條消息。在被定義后,消息被送回客戶端作為系統錯誤消息。
RAISERROR ({msg_id msg_str}, severity, state
[, argument1 [, argument2]])

[WITH options]

 

在轉換你的PL/SQL程序時,也許用不著使用RAISERROR語句。在下面的示例代碼中。PL/SQL程序使用raise_application_error異常處理器,但是Transact-SQL程序則什么也沒用。包括raise_application_error異常處理器是為了防止PL/SQL返回不明確的未經處理的異常錯誤消息。作為代替,當一個不可預見的問題發生的時候,異常處理器總是返回Oracle錯誤消息。

當一個Transact-SQL失敗時,它總是返回一個具體的錯誤消息給客戶程序。因此,除非需要某些特定的錯誤處理,一般是不需要RAISERROR語句的。
OracleMicrosoft SQL  CREATE OR REPLACE FUNCTION
DEPT_ADMIN.DELETE_DEPT
(VDEPT IN VARCHAR2) RETURN NUMBER AS
BEGIN
DELETE FROM DEPT_ADMIN.DEPT
WHERE DEPT = VDEPT;
RETURN(SQL%ROWCOUNT);
EXCEPTION
WHEN OTHER THEN
RAISE_APPLICATION_ERROR
(-20001,SQLERRM);
END DELETE_DEPT;
/CREATE PROCEDURE
DEPT_ADMIN.DELETE_DEPT
@VDEPT VARCHAR(4) AS
DELETE FROM DEPT_DB.DBO.DEPT
WHERE DEPT = @VDEPT
RETURN @@ROWCOUNT
GO
 

實現游標

Oracle在使用SELECT語句時總是需要游標,不管從數據庫中請求多少行。在Microsoft SQL Server,SELECT語句并不把在返回客戶的行上附加游標作為缺省的結果集合。這是一種返回數據給客戶應用程序的有效的方法。

SQL Server為游標函數提供了兩種接口。當在Transact-SQL批處理或者存儲過程中使用游標的時候,SQL語句可用來聲明、打開、和從游標中抽取,就像定位更新和刪除一樣。當使用來自DB-Library、ODBC、或者OLEDB程序的游標時,SQL Server顯式的調用內建的服務器函數來更有效的處理游標。

當從Oracle輸入一個PL/SQL過程時,首先判定是否需要在Transact-SQL中采用游標來實現同樣的功能。假如游標僅僅返回一組行給客戶程序,就使用非游標的SELECT語句來返回缺省的結果集合。假如游標用來從行中一次取得一個數據給本地過程變量,你就必須在Transact-SQL中使用游標。

 

語法

下表顯示了使用游標的語法。
操作OracleMicrosoft SQL Server 聲明一個游標CURSOR cursor_name [(cursor_parameter(s))]
IS select_statement;DECLARE cursor_name CURSOR
[LOCAL GLOBAL]
[FORWARD_ONLY SCROLL]
[STATIC KEYSET DYNAMIC FAST_FORWARD]
[READ_ONLY SCROLL_LOCKS OPTIMISTIC]
[TYPE_WARNING]

FOR select_statement
[FOR UPDATE [OF column_name [,…n]]] 打開一個游標OPEN cursor_name [(cursor_parameter(s))];OPEN cursor_name 從游標中提取(Fetching)FETCH cursor_name INTO variable(s)FETCH [[NEXT PRIOR FIRST LAST ABSOLUTE {n @nvar} RELATIVE {n @nvar}]
FROM] cursor_name
[INTO @variable(s)] 更新提取行UPDATE table_name
SET statement(s)…
WHERE CURRENT OF cursor_name;UPDATE table_name
SET statement(s)…
WHERE CURRENT OF cursor_name 刪除提取行DELETE FROM table_name
WHERE CURRENT OF cursor_name;DELETE FROM table_name
WHERE CURRENT OF cursor_name 關閉游標CLOSE cursor_name;CLOSE cursor_name 清除游標數據結構N/ADEALLOCATE cursor_name
 

聲明一個游標

盡管Transact-SQL DECLARE CURSOR語句不支持游標參數的使用,但它確實支持本地變量。當游標打開的時候,它就使用這些本地變量的值。Microsoft SQL Server在其DECLARE CURSOR中提供了許多附加的功能。

INSENSITIVE選項用來定義一個創建數據的臨時拷貝以被游標使用的游標。游標的所有請求都由這個臨時表來應答。因此,對原表的修改不會反映到那些由fetch返回的用于該游標的數據上。這種類型的游標訪問的數據是不能被修改的。

應用程序可以請求一個游標類型然后執行一個不被所請求的服務器游標類型支持的Transact-SQL語句。SQL Server返回一個錯誤,指出該游標類型被改變了,或者給出一組參數,隱式的轉換游標。欲取得一個觸發SQL Server 7.0隱式的把游標從一種類型轉換為另一種類型的參數的完整列表,請參閱SQL Server聯機手冊。

SCROLL選項答應除了前向的抽取以外,向后的、絕對的和相對的數據抽取。一個滾動游標使用一種鍵集合的游標模型,在該模型中,任何用戶提交的對表的刪除和更新都將影響后來的數據抽取。只有在游標沒有用INSENSITIVE選項聲明時,上面的特性才起作用。

假如選擇了READ ONLY選項,對游標中的行的更新就被禁止。該選項將覆蓋游標的缺省選項棗答應更新。

UPDATE [OF column_list]語句用來在游標中定義一個可更新的列。假如提供了[OF column_list],那么僅僅是那些列出的列可以被修改。假如沒有指定任何列。則所有的列都是可以更新的,除非游標被定義為READ ONLY。

重要的是,注重到一個SQL Server游標的名字范圍就是連接自己。這和本地變量的名字范圍是不同的。不能聲明一個與同一個用戶連接上的已有的游標相同名字的游標,除非第一個游標被釋放。

 

打開一個游標

Transact-SQL不支持向一個打開的游標傳遞參數,這一點和PL/SQL是不一樣的。當一個Transact-SQL游標被打開以后,結果集的成員和順序就固定下來了。其它用戶提交的對原表的游標的更新和刪除將反映到對所有未加INSENSITIVE選項定義的游標的數據抽取上。對一個INSENSITIVE游標,將生成一個臨時表。

 

抽取數據

Oracle游標只能向前移動棗沒有向后或者相對滾動的能力。SQL Server游標可以向前或者向后滾動,具體怎么滾動,要由下表給出的數據抽取選項來決定。只有在游標是用SCROLL選項聲明的前提下,這些選項才能使用。
卷動選項描述NEXT假如這是對游標的第一次提取,則返回結果集合的第一行;否則,在結果結合內移動游標到下一行。NEXT是在結果集合中移動的基本方法 。NEXT是缺省的游標提取(fetch)。 PRIOR返回結果集合的前一行。FIRST把游標移動到結果集合的第一行,同時返回第一行。LAST把游標移動到結果集合的最后一行,同時返回最后一行。ABSOLUTE n返回結果集合的第n行。假如n為負數,則返回倒數第n行RELATIVE n返回當前提取行后的第n行,假如n是負數,則返回從游標相對位置起的倒數第n行。
 

Transact-SQL的FETCH語句不需要INTO子句。假如沒有指定返回變量,行就自動作為一個單行結果集合返回給客戶。但是,假如你的過程必須把行給客戶,一個不帶游標的SELECT語句更有效一些。

在每一個FETCH后面,@@FETCH_STATUS函數被更新。這和在PL/SQL中使用CURSOR_NAME%FOUND和CURSOR_NAME%NOTFOUND變量是相似的。@@FETCH_STATUS函數在每一次成功的數據抽取以后被設定為0。假如數據抽取試圖讀取一個超過游標末尾的數據,則返回一個為-1的值。假如請求的行在游標打開以后從表上被刪除了,@@FETCH_STATUS函數就返回一個為-2的值。只有游標是用SCROLL選項定義的情況下,才會返回-2值。在每一次數據抽取之后都必須檢查該變量,以確保數據的有效性。

SQL Server不支持Oracle的游標FOR循環語法。

CURRENT OF子句

更新和刪除的CURRENT OF子句語法和函數在PL/SQL和Transact-SQL中是一樣的。在給定游標中,在當前行上執行定位的UPDATE和DELETE。

 

關閉一個游標

Transact-SQL的CLOSE CURSOR語句關閉游標,但是保留數據結構以備重新打開。PL/SQL 的CLOSE CURSOR語句關閉并且釋放所有的數據結構。

Transact-SQL需要用DEALLOCATE CURSOR語句來清除游標數據結構。DEALLOCATE CURSOR語句同CLOSE CURSOR是不一樣的,后者保留數據結構以備重新打開。DEALLOCATE CURSOR釋放所有與游標相關的數據結構并且清除游標的定義。

 

游標示例

下面的例子顯示了在PL/SQL和Transact-SQL等價的游標語句。
OracleMicrosoft SQL  DECLARE
VSSN CHAR(9);
VFNAME VARCHAR(12);
VLNAME VARCHAR(20);DECLARE

@VSSN CHAR(9),
@VFNAME VARCHAR(12),
@VLNAME VARCHAR(20)CURSOR CUR1 IS
SELECT SSN, FNAME, LNAME
FROM STUDENT ORDER BY LNAME;
BEGIN
    OPEN CUR1;
    FETCH CUR1 INTO VSSN,     VFNAME, VLNAME;
    WHILE (CUR1%FOUND) LOOP
    FETCH CUR1 INTO VSSN,     VFNAME, VLNAME;
END LOOP;
CLOSE CUR1;
END;DECLARE curl CURSOR FOR
   SELECT SSN, FNAME, LNAME
   FROM STUDENT ORDER BY SSN
OPEN CUR1
FETCH NEXT FROM CUR1
   INTO @VSSN, @VFNAME, @VLNAME
WHILE (@@FETCH_STATUS <> -1)
   BEGIN
  FETCH NEXT FROM CUR1 INTO       @VSSN, @VFNAME, @VLNAME
   END
CLOSE CUR1
DEALLOCATE CUR1
 

調試SQL語句

本節提供了一些SQL Server工具的信息,你可以用這些工具來調試Transact-SQL語句。欲了解關于調試SQL Server數據庫的具體信息,請參閱本卷前面的“性能調節部分”

SQL Server Query Analyzer(SQL Server查詢分析器)

你可以利用SQL Server查詢分析器的圖形化特性來更多的了解優化器是如何處理你的語句的。

SQL Server Profiler

該圖形化工具實時捕捉服務器活動的連續記錄。SQL Server Profier監視許多不同的服務器事件和事件類別,用用戶指定的標準來過濾這些事件,并且輸出到一個顯示在屏幕上的軌跡,一個文件,或者另一個SQL Server上。

SQL Server Profiler 可以用來: 監視SQL Server的性能。 調試Transact-SQL語句和存儲過程。 識別執行很慢的查詢。 通過捕捉導致一個非凡問題的所有事件查找SQL Server中的問題,然后在一個測試系統上重放這一系列事件來重現并且孤立問題。 通過單步執行語句,在項目的開發階段測試SQL語句和存儲過程,確保代碼像預期的那樣工作。 在產品系統上捕捉事件,并且在測試系統上重放捕捉的事件,以此為測試或者調試的目的重現產品環境中發生的事情。在獨立的系統上重放捕捉的事件可以讓用戶繼續使用產品系統,不會造成沖突。
 

SQL Server Profiler為一系列擴展存儲過程提供了一個圖形用戶界面。你也可以直接使用這些擴展存儲界面。因此,你可以創建自己的利用SQL Server Profiler擴展存儲過程的應用程序來監視SQL Server。

SET語句

SET語句可以在你的工作會話、運行中的觸發器或者存儲過程的生命期內設定SQL Server查詢處理選項。

SET FORCEPLAN ON語句強制優化器按照表在FROM子句出現的順序處理連接,同Oracle優化器所用的ORDERED提示是類似的。

SET SHOWPLAN_ALL和SET SHOWPLAN_TEXT語句只返回查詢或者語句執行方案的信息,而不會執行查詢或者語句本身。要執行查詢或者語句。需要把適當的顯示方案的語句設定為OFF。然后就可以執行查詢或者語句了。SHOWPLAN語句的結果跟Oracle的EXPLAIN PLAN工具是類似的。

假如SET STATISTICS PROFILE是ON,則每一個執行的查詢除了返回正常的結果集合,還加上一個額外的結果集合,該集合顯示了一個查詢執行的快照。其它選項包括SET STATISTICS IO和SET STATISTICS TIME。

Transact-SQL語句處理包括兩個階段,編譯和執行。NOEXEC選項編譯每一個查詢但不執行該查詢。在NOEXEC設定為ON以后,后來的語句將不再執行,一直到NOEXEC設定為OFF。
SET SHOWPLAN ON
SET NOEXEC ON

go

SELECT * FROM DEPT_ADMIN.DEPT,

STUDENT_ADMIN.STUDENT

WHERE MAJOR = DEPT

go

STEP 1

The type of query is SETON

STEP 1

The type of query is SETON

STEP 1

The type of query is SELECT

FROM TABLE

DEPT_ADMIN.DEPT

Nested iteration

Table Scan

FROM TABLE

STUDENT_ADMIN.STUDENT

Nested iteration

Table Scan

 

查詢優化

Oracle需要使用提示來影響它的基于開銷的優化器的操作和性能。Microsoft SQL Server的基于開銷的優化器不需要使用提示來幫助其查詢評估過程。但是,它們仍然可以在某些情況下使用。

INDEX = {index_name index_id}為那個表指定要用的索引名稱或者ID。假如index_id為0,則強制該表進行掃描,而為1的index_id則強制使用一個分簇的索引,假如有的話。這跟Oracle中使用的索引提示是類似的。

SQL Server的FASTFIRSTROW指示優化器使用一個未分簇的索引,假如它的列順序同ORDER BY子句相匹配的話。該提示同Oralce中的FIRST_ROWS提示是類似的

使用ODBC

本部分提供Oracle和SQL Server使用ODBC的方法的信息和關于開發和移植使用ODBC的應用程序的信息。

 

推薦的轉換策略

假如要把你的應用程序從Oracle轉換到SQL Server上,推薦采用下面的過程: 假如你的應用程序使用Oracle Pro*C或者Oracle調用接口(Oracle Call Interface,OCI)的話,考慮把它轉換到ODBC。 理解SQL Server缺省的結果集合和游標選項,然后選擇針對你的應用程序的最有效的提取策略。(fetching strategy)。 重新映射Oracle ODBC SQL數據類型到合適的SQL Server ODBC SQL數據類型。 使用ODBC Extended SQL擴展來創建類屬的SQL語句。 決定SQL Server應用程序是否需要手工提交模式。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 茂名市| 准格尔旗| 竹北市| 崇信县| 荥经县| 泌阳县| 泰和县| 石柱| 玉山县| 富顺县| 壶关县| 哈尔滨市| 黄大仙区| 彰化市| 新兴县| 德阳市| 上饶县| 池州市| 海城市| 鄂温| 临武县| 罗源县| 玉龙| 广昌县| 揭阳市| 永定县| 安国市| 鹤壁市| 天气| 万全县| 库车县| 井陉县| 遵化市| 文昌市| 江山市| 万荣县| 清苑县| 司法| 东乌珠穆沁旗| 吉木萨尔县| 敦化市|