【轉】SQL Server 2008 新數據類型

概覽:
  • 新日期和時間數據類型
  • 表明在層次結構中的位置
  • 用於處理空間數據的兩種模型

 

在全球經濟環境下開展業務這一趨勢愈來愈要求各公司使用新型的數據、應用程序以及複雜的計算。SQL Server 2008 內置的七種新數據類型
提供了處理和簡化更復雜數據管理的方法。

 

日期和時間
使用舊的 datetime 數據類型時,SQL Server ® 用戶沒法分別處理日期和時間信息。四種新數據類型(date、time、datetime2 和 datetimeoffset)則改變了這一情況,從而簡化了日期和時間數據的處理,而且提供了更大的日期範圍、小數秒精度以及時區支持。新數據庫應用程序應使用這些新數據類型,而非原來的 datetime。讓咱們進一步瞭解一下這些新類型。
Date 數據類型僅存儲日期,不存儲時間。範圍是從 1000 年 1 月 1 日到 9999 年 12 月 31 日(0001-01-01 到 9999-12-31)。每一個日期變量都須要 3 個存儲字節,且精度爲 10 位。Date 類型的準確性僅限於單天。
看一看 圖 1,它顯示瞭如何在 T-SQL 腳本中建立和初始化 Date 變量。變量 @myDate1 初始化爲 'MM/DD/YYYY' 格式的字符串。變量 @myDate2 則未初始化,它的值將爲 NULL。變量 @myDate3 初始化爲本地計算機系統的日期。可隨時使用 SELECT 或 SET 語句來更改變量的值,示例中更改了 @myDate2 的值。也可在表格中建立日期列。 圖 2 展現瞭如何建立包含三個日期列的表格。
 
USE TempDB
GO

CREATE TABLE myTable
(
    myDate1 date,myDate2 date,myDate3 date
)
GO

INSERT INTO myTable
VALUES('01/22/2005',
       '2007-05-08 12:35:29.1234567 +12:15',
       GetDate())

SELECT * FROM myTable

--Results
--myDate1    myDate2    myDate3
------------ ---------- ----------
--2005-01-22 2007-05-08 2007-11-20

 

Figure 1 Create and initialize date variables in T-SQL scripts
 
 
 
DECLARE @myDate1 date = '01/22/2005'
DECLARE @myDate2 date
DECLARE @myDate3 date = GetDate()

SELECT @myDate2 = '2007-05-08 12:35:29.1234567 +12:15'

SELECT @myDate1 AS '@myDate1',
       @myDate2 AS '@myDate2',
       @myDate3 AS '@myDate3'

--Results
--@myDate1   @myDate2   @myDate3
------------ ---------- ----------
--2005-01-22 2007-05-08 2007-11-20
 
Time 數據類型僅存儲一天中的時間,不存儲日期。它使用的是 24 小時時鐘,所以支持的範圍是 00:00:00.0000000 到 23:59:59.9999999(小時、分鐘、秒和小數秒)。可在建立數據類型時指定小數秒的精度。默認精度是 7 位,準確度是 100 毫微秒。精度影響着所需的存儲空間大小,範圍包括最多 2 位的 3 個字節、3 或 4 位的 4 個字節以及 5 到 7 位的 5 個字節。
圖 3 中的 T-SQL 腳本展現了字符串初始化值的隱式轉換將如何影響變量的精度。T-SQL 代碼首先建立八個單獨的時間變量,並將其初始化爲相同值。每一個變量的小數精度等於其名稱。例如,@myTime3 的小數精度爲 3 位。結果顯示每一個時間數據類型的精度均等於聲明的小數精度。超出的位數將被截斷。
 
 
DECLARE @myTime  time = '01:01:01.1234567 +01:01'
DECLARE @myTime1 time(1) = '01:01:01.1234567 +01:01'
DECLARE @myTime2 time(2) = '01:01:01.1234567 +01:01'
DECLARE @myTime3 time(3) = '01:01:01.1234567 +01:01'
DECLARE @myTime4 time(4) = '01:01:01.1234567 +01:01'
DECLARE @myTime5 time(5) = '01:01:01.1234567 +01:01'
DECLARE @myTime6 time(6) = '01:01:01.1234567 +01:01'
DECLARE @myTime7 time(7) = '01:01:01.1234567 +01:01'

SELECT @myTime  AS '@myTime',
       @myTime1 AS '@myTime1',
       @myTime2 AS '@myTime2',
       @myTime3 AS '@myTime3',
       @myTime4 AS '@myTime4',
       @myTime5 AS '@myTime5',
       @myTime6 AS '@myTime6',
       @myTime7 AS '@myTime7'

--Results
--@myTime          @myTime1   @myTime2    @myTime3     @myTime4      
------------------ ---------- ----------- ------------ -------------
--01:01:01.1234567 01:01:01.1 01:01:01.12 01:01:01.123 01:01:01.1235
--
--@myTime5       @myTime6        @myTime7
---------------- --------------- ----------------
--01:01:01.12346 01:01:01.123457 01:01:01.1234567

DROP TABLE myTable

 

 
可將 time 數據類型建立爲表格中的一列。 圖 4 中的 DROP TABLE myTable T-SQL 腳本建立了一個名爲 myTable1 的表格並向表格添加了三個時間列。而後,使用 SELECT 語句來將記錄插入到表格中而且顯示錶格的內容。
 
 
USE TempDB
GO

CREATE TABLE myTable1
(
    myTime1 time(1),
    myTime2 time(2),
    myTime3 time(3)
)
GO

INSERT INTO myTable1
VALUES('01:30:01.1234567',
       '02:34:01.1234567',
       '03:01:59.1234567')

SELECT * from myTable1

--Results
--myTime1    myTime2     myTime3
------------ ----------- ------------
--01:30:01.1000000 02:34:15.1200000 03:01:59.1230000

DROP TABLE myTable1

 

 
Datetimeoffset 和 Datetime2
Datetimeoffset 數據類型提供了時區信息。time 數據類型不包含時區,所以僅適用於當地時間。然而,在全球經濟形勢下,經常須要知道某個地區的時間與另外一地區的時間之間的關係。時區偏移值表示爲 + 或 - hh:mm。
如下代碼建立了一個 datetimeoffset 變量並將其初始化爲時間值 8:52 A.M.太平洋時間:
 
 
DECLARE @date DATETIMEOFFSET = '2007-11-26T08:52:00.1234567-08:00'
PRINT @date
--Results
--2007-11-26 08:52:00.1234567 -08:00

 

 
初始化 datetimeoffset 變量(腳本中的 @date)的字符串爲特殊格式,從最重要的元素到最不重要的元素。單個大寫字母 T 分隔了日期和時間元素。減號將時間元素與時區分隔開來。減號與時間或時區元素之間並沒有空格。該格式是 datetimeoffset 數據類型所支持的兩種 ISO 8601 格式中的一種(ISO 8601 是日期和時間值表示的國際標準)。
時間組件的精度指定爲與 time 數據類型同樣,而且若是未指定則默認爲一樣的七位。支持的範圍也相同。
Datetime2 數據類型是原始 datetime 類型的擴展。它支持更大的日期範圍以及更細的小數秒精度,同時可以使用它來指定精度。datetime2 類型的日期範圍是 0001 年 1 月 1 日到 9999 年 12 月 31 日(原始 datetime 的範圍則是 1753 年 1 月 1 日到 9999 年 12 月 31 日)。與 time 類型同樣,提供了七位小數秒精度。原始 datetime 類型提供了三位精度,且時間範圍爲 00:00:00 到 23:59:59.999。如下代碼顯示瞭如何建立一個 datetime2 變量並將其初始化爲本地服務器日期和時間:
 
 
DECLARE @datetime2 DATETIME2 = GetDate();
PRINT @datetime2

--Results
--2007-11-26 09:39:04.1370000
 
接下來看看新的 hierarchyid 數據類型。該數據類型用於處理表中數據元素之間的關係,而非具體的日期或時間數據。

 

Hierarchyid 數據類型
Hierarchyid 數據類型可用於構建表中數據元素之間的關係,專門表明在層次結構中的位置。爲研究該數據類型,首先經過使用 圖 5 中的腳原本建立 MyCompany 數據庫並在其中填寫員工數據。
 
 
USE MASTER
GO

CREATE DATABASE MyCompany
GO
USE MyCompany
GO

--Create a table called employee that will store
--the data for the employees for MyCompany.
    
CREATE TABLE employee
(
    EmployeeID int NOT NULL,
    EmpName    varchar(20) NOT NULL,
    Title      varchar(20) NULL,
    Salary     decimal(18, 2) NOT NULL,
    hireDate   datetimeoffset(0) NOT NULL,
)
GO

--These statements will insert the data for the employees of MyCompany.

INSERT INTO employee
VALUES(6,   'David',  'CEO', 35900.00, '2000-05-23T08:30:00-08:00')

INSERT INTO employee
VALUES(46,  'Sariya', 'Specialist', 14000.00, '2002-05-23T09:00:00-08:00')

INSERT INTO employee
VALUES(271, 'John',   'Specialist', 14000.00, '2002-05-23T09:00:00-08:00')

INSERT INTO employee
VALUES(119, 'Jill',   'Specialist', 14000.00, '2007-05-23T09:00:00-08:00')

INSERT INTO employee
VALUES(269, 'Wanida', 'Assistant', 8000.00, '2003-05-23T09:00:00-08:00')

INSERT INTO employee
VALUES(272, 'Mary',   'Assistant', 8000.00, '2004-05-23T09:00:00-08:00')
GO
--Results
--EmployeeID  EmpName Title      Salary   hireDate
------------- ------- ---------- -------- --------------------------
--6           David   CEO        35900.00 2000-05-23 08:30:00 -08:00
--46          Sariya  Specialist 14000.00 2002-05-23 09:00:00 -08:00
--271         John    Specialist 14000.00 2002-05-23 09:00:00 -08:00
--119         Jill    Specialist 14000.00 2007-05-23 09:00:00 -08:00
--269         Wanida  Assistant  8000.00  2003-05-23 09:00:00 -08:00
--272         Mary    Assistant  8000.00  2004-05-23 09:00:00 -08:00

 

圖 6 顯示了生成的簡單數據庫,僅包含一個員工表。MyCompany 數據庫中的該員工表不包含任何強加結構。這對於關係型數據庫而言很是正常,由於結構是由應用程序經過其查詢和處理代碼來動態強加的。
Figure 6  MyCompany 員工表 
可是,企業數據一般都具備內在結構。例如,每一個企業都具備報告結構,如 圖 7 中所示的 MyCompany 的報告結構。MyCompany 的全部員工都向 CEO David 報告。某些員工爲直接報告(如 Jill)。其餘人(如 Mary)則經過中間人報告。在編程術語中,MyCompany 的報告結構稱爲樹,由於其形狀很是像樹。最上方的 David 無需向任何人報告,他是父級或祖先。其下爲向 David 報告的員工。此類節點稱爲子級或後代。David 可擁有任意多個後代,以表明其直接下屬。
Figure 7  MyCompany 的組織結構 (單擊該圖像得到較大視圖)
圖 8 中的腳本使用 hierarchyid 數據類型重構了 MyCompany 數據庫,構建了一個符合 MyCompany 報告結構的關係。先使用 ALTER TABLE 語句添加一個 hierarchyid 列。而後使用 hierarchyid 的 GetRoot 方法插入 David 的節點。接着使用 GetDescendant 方法將 David 的直接下屬添加到樹中。
 
 
DELETE employee
GO
ALTER TABLE employee ADD OrgNode hierarchyid NOT NULL
GO

DECLARE @child hierarchyid,
@Manager hierarchyid = hierarchyid::GetRoot()

--The first step is to add the node at the top of the
--tree. Since David is the CEO his node will be the
--root node.

INSERT INTO employee
VALUES(6,   'David',  'CEO', 35900.00,
       '2000-05-23T08:30:00-08:00', @Manager)

--The next step is to insert the records for
--the employees that report directly to David.

SELECT @child = @Manager.GetDescendant(NULL, NULL)

INSERT INTO employee
VALUES(46,  'Sariya', 'Specialist', 14000.00,
       '2002-05-23T09:00:00-08:00', @child)

SELECT @child = @Manager.GetDescendant(@child, NULL)
INSERT INTO employee
VALUES(271, ‚John',   ‚Specialist', 14000.00,
       '2002-05-23T09:00:00-08:00', @child)

SELECT @child = @Manager.GetDescendant(@child, NULL)
INSERT INTO employee
VALUES(119, ‚Jill',   ‚Specialist', 14000.00,
       ‚2007-05-23T09:00:00-08:00', @child)

--We can now insert the employee that reports to
--Sariya.
SELECT @manager = OrgNode.GetDescendant(NULL, NULL)
FROM employee WHERE EmployeeID = 46

INSERT INTO employee
VALUES(269, ‚Wanida', ‚Assistant', 8000.00,
       ‚2003-05-23T09:00:00-08:00', @manager)

--Next insert the employee that report to John.
SELECT @manager = OrgNode.GetDescendant(NULL, NULL)
FROM employee WHERE EmployeeID = 271

INSERT INTO employee
VALUES(272, ‚Mary',   ‚Assistant', 8000.00,
       ‚2004-05-23T09:00:00-08:00', @manager)
GO

 

 
添加數據庫記錄且構建好層次結構後,就可以使用相似如下的查詢來顯示員工表的內容:
 
 
SELECT EmpName, Title, Salary, OrgNode.ToString() AS OrgNode
FROM employee ORDER BY OrgNode
GO
--Results
--EmpName  Title      Salary    OrgNode
---------- ---------- --------- -------
--David    CEO        35900.00  /
--Sariya   Specialist 14000.00  /1/
--Wanida   Assistant  8000.00   /1/1/
--John     Specialist 14000.00  /2/
--Mary     Assistant  8000.00   /2/1/
--Jill     Specialist 14000.00  /3/

 

 
OrgNode 是 hierarchyid 列。結果中的每一個斜線 / 字符表示層次結構樹中的一個節點。David 位於根節點,所以顯示一個斜線。Sariya、John 和 Jill 向 David 報告,所以有兩個斜線,表示他們是層次結構中的第二層節點。數字 一、2 或 3 顯示各子節點的順序。該系統很是靈活。可根據須要刪除、插入或添加子節點。例如,若是在 John 和 Jill 之間添加一名員工,該員工在結果集中將列爲:/2.1/.
要回答問題(如「誰向 Sariya 報告?」),可建立如下 T-SQL 代碼中所示的查詢:
 
 
DECLARE @Sariya hierarchyid

SELECT @Sariya = OrgNode
FROM employee WHERE EmployeeID = 46

SELECT EmpName, Title, Salary, OrgNode.ToString() AS 'OrgNode'
FROM employee
WHERE OrgNode.GetAncestor(1) = @Sariya
GO
--Results
--EmpName Title     Salary  OrgNode
--------- --------- ------- -------
--Wanida  Assistant 8000.00 /1/1/

 

 
此查詢使用 hierarchyid 的 GetAncestor 方法,它會返回當前 hierarchyid 節點的父項。在以前的代碼中,將變量 @Sariya 設爲 Sariya 的層次結構節點。由於 Sariya 是向她報告的全部員工的直接前輩。所以,要編寫一個返回直接向 Sariya 報告的員工的查詢,需從樹中檢索 Sariya 的節點,而後選擇前輩節點爲 Sariya 節點的全部員工。
Hierarchyid 列應很是緊湊,由於表明樹中節點所需的位數取決於節點的平均子項數(一般稱爲節點的扇出)。例如,擁有 100,000 名員工且平均扇出爲六級的組織層次結構中的新節點需五個存儲字節。
Hierarchyid 數據類型提供了多個便於處理層次數據的方法。 圖 9 概要顯示了這些方法。有關全部方法的詳細信息,請參閱 SQL Server 聯機叢書 ( msdn2.microsoft.com/ms130214)。

方法 說明
GetAncestor 返回表明該 hierarchyid 節點第 n 代前輩的 hierarchyid。
GetDescendant 返回該 hierarchyid 節點的子節點。
GetLevel 返回一個整數,表明該 hierarchyid 節點在整個層次結構中的深度。
GetRoot 返回該層次結構樹的根 hierarchyid 節點。靜態。
IsDescendant 若是傳入的子節點是該 hierarchyid 節點的後代,則返回 true。
Parse 將層次結構的字符串表示轉換成 hierarchyid 值。靜態。
Reparent 將層次結構中的某個節點移動另外一個位置。
ToString 返回包含該 hierarchyid 邏輯表示的字符串。

 

空間數據類型
空間數據是用於肯定地理位置和形狀(主要是在地球上)的數據。它們能夠是界標、道路甚至企業所在地。SQL Server 2008 提供了 geography 和 geometry 數據類型來處理此類數據。
Geography 數據類型處理圓地信息。圓地模型在計算時考慮了地球的曲面。位置信息是由經度和緯度組成。該模型極其適合越洋運輸、軍事規劃等應用程序以及涉及地球表面的短程應用程序。若是數據是按經度和緯度存儲的,則使用此模型。
Geometry 數據類型處理平地或平面模型。在此模型中,將地球看成從已知點起的平面投影。平地模型不考慮地球的彎曲,所以主要用於描述較短的距離,如映射建築物內部的數據庫應用程序。
Geography 和 geometry 類型從矢量對象構建,格式爲 Well-Known Text (WKT) 或 Well-Known Binary (WKB)。它們是開放地理空間聯盟 (OGC) SQL 簡單特徵規範描述的空間數據傳輸格式。 圖 10 列出了 SQL Server 2008 支持的七種矢量對象類型。

對象 說明
Point 一個位置。
MultiPoint 一系列點。
LineString 由直線鏈接的零個或多個點。
MultiLineString 一組 linestring。
Polygon 一組封閉 linestring 造成的相連區域。
MultiPolygon 一組多邊形。
GeometryCollection geometry 類型集合。
要使用一個或多個矢量對象構建一個 geography 類型,首先在 T-SQL 腳本中聲明 geography 類型(如 圖 11 所示)。而後調用 圖 12 中列出的一個方法,並傳入矢量對象字符串和空間參照 ID (SRID)。SRID 是歐洲石油調查組定義的空間參照標識系統。它是針對繪圖、調查和測量數據存儲制定的一組標準的組成部分。每一個 SRID 標識地理計算中使用的一個具體橢圓體類型。由於地球並不是標準的球體,因此這是必須的。SQL Server 2008 僅能對相同 SRID 執行計算。

方法 說明
STGeomFromText 根據輸入文本構建任意類型的 geography 實例。
STPointFromText 根據輸入文本構建一個 geography 的 Point 實例。
STMPointFromText 根據輸入文本構建一個 geography 的 MultiPoint 實例。
STLineFromText 根據輸入文本構建一個 geography 的 LineString 實例。
STMLineFromText 根據輸入文本構建一個 geography 的 MultiLineString 實例。
STPolyFromText 根據輸入文本構建一個 geography 的 Polygon 實例。
STMPolyFromText 根據輸入文本構建一個 geography 的 MultiPolygon 實例。
STGeomCollFromText 根據輸入文本構建一個 geography 的 GeometryCollection 實例。
 
 
DECLARE @geo1 geometry
SELECT @geo1 = geometry::STGeomFromText('POINT (3 4)', 0)
PRINT @geo1.ToString()

DECLARE @geo2 geometry
SELECT @geo2 = geometry::Parse('POINT(3 4 7 2.5)')
PRINT @geo2.STX;
PRINT @geo2.STY;
PRINT @geo2.Z;
PRINT @geo2.M;

DECLARE @geo3 geography;
SELECT @geo3 = geography::STGeomFromText(
    'LINESTRING(47.656 -122.360, 47.656 -122.343)', 4326);
SELECT @geo3.ToString();

--Results
--POINT (3 4)
--3
--4
--7
--2.5

DECLARE @gx geometry; 
SET @gx = geometry::STPolyFromText(
    'POLYGON ((5 5, 10 5, 10 10, 5 5))', 0);
PRINT @gx.ToString();
--Results
--POLYGON ((5 5, 10 5, 10 10, 5 5))

 

 

Geography 和 Geometry 之間的差異
Geography 和 geometry 數據類型專用於處理不一樣類型的數據,所以必須瞭解一些關鍵差異。使用 geometry 數據類型時,距離和麪積的度量單位需與實例的座標一致。例如,點 (0,0) 和點 (6,8) 之間的距離將始終爲 10 個單位。使用 geography 類型時則不同,它使用的是以經度和緯度表示的橢圓體座標。
當座標以經度緯度對錶示時,GEOMETRY 數據類型返回的是不一樣的結果。如下 T-SQL 代碼計算點 (90 0) 和點 (90 180) 之間的距離。這兩個點均表明北極,所以它們之間的距離應爲 0。在使用 GEOMETRY 時,計算後的距離爲 180。
 
 
DECLARE @g1 GEOMETRY, @g2 GEOMETRY, @g3 GEOGRAPHY, @g4 GEOGRAPHY
SELECT @g1 = GEOMETRY::STGeomFromText('POINT (90 0)', 0)
SELECT @g2 = GEOMETRY::STGeomFromText('POINT (90 180)', 0)

SELECT @g3 = GEOGRAPHY::STGeomFromText('POINT (90 0)', 4326)
SELECT @g4 = GEOGRAPHY::STGeomFromText('POINT (90 180)', 4326)
SELECT @g2.STDistance(@g1) AS 'GEOMETRY',
       @g4.STDistance(@g3) AS 'GEOGRAPHY';

--Results
--GEOMETRY               GEOGRAPHY
------------------------ ----------------------
--180                    0

 

兩種數據類型的空間數據方向也不一樣。在 geometry 數據類型所使用的平面系統中,多邊形的方向並不是重要因素。例如,座標爲 ((0, 0), (10, 0), (0, 20), (0, 0)) 的多邊形被視爲等同於多邊形 ((0, 0), (0, 20), (10, 0), (0, 0))。可是,在 geography 數據類型所使用的數據模型中,若是沒有指定方向,則並不能肯定多邊形。例如,假定有個環繞赤道的環。那麼,該環所造成的多邊形表明的是北半球仍是南半球?所以,在使用 geography 數據時,必須準確指出方向和位置。
SQL Server 2008 對 geography 數據類型還設有一些限制。例如,每一個 geography 實例均必須位於單個半球內。不容許更大的空間對象,不然會拋出 ArgumentException。若是方法的結果並不位於單個半球內,則須要兩個輸入的 Geography 數據類型會返回 NULL。
SQL Server 提供了多個可針對 geography 和 geometry 實例執行操做的方法。 圖 13 顯示了使用 SQL Server 2008 提供的方法來處理空間數據的一些示例。鑑於篇幅有限,在此就再也不詳述該主題,SQL Server 聯機叢書中提供有完整說明。
 
 
DECLARE @gm geometry;
DECLARE @gg geography;
DECLARE @h geography;

SET @gm = geometry::STGeomFromText('POLYGON((0 0, 13 0, 3 3, 0 13, 0 0),(2 2, 2 1, 1 1, 1 2, 2 2))', 0);
SELECT @gm.STArea();

--Results
--38

SET @gg = geography::STGeomFromText('LINESTRING(0 0, 5 5)', 4326);
--Calculate the distance to a point slightly offset from the LINESTRING.
SET @h = geography::STGeomFromText('POINT(4 4)', 4326);
SELECT @gg.STDistance(@h);

--Results
-- 430.182777043046

--Calculate the distance to a point on the LINESTRING.
SET @h = geography::STGeomFromText('POINT(5 5)', 4326);
SELECT @gg.STDistance(@h);

--Results
-- 0

DECLARE @temp table ([name] varchar(10), [geom] geography);

INSERT INTO @temp values ('Point', geography::STGeomFromText('POINT(
5 10)', 4326));
INSERT INTO @temp values ('LineString', geography::STGeomFromText(
'LINESTRING(13 5, 50 25)', 4326));
--Calculate the distance to a point on the LINESTRING.
--Display the number of dimensions for a geography object stored in a --table variable.
INSERT INTO @temp values ('Polygon', geography::STGeomFromText(
'POLYGON((47.653 -122.358, 47.649 -122.348, 47.658 -122.348, 47.658 -122.358, 47.653 -122.358))', 4326));

SELECT [name], [geom].STDimension() as [dim]
FROM @temp;

--Results
--name       dim
------------ -----------
--Point      0
--LineString 1
--Polygon    2
相關文章
相關標籤/搜索