【转】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
相关文章
相关标签/搜索