1. Trang chủ
  2. » Công Nghệ Thông Tin

Microsoft SQL Server 2008 R2 Unleashed- P164 ppsx

10 114 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 189,59 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

if exists select * from sys.systypes t where t.name = ‘ytdsales_tabletype’ and t.uid = USER_ID‘dbo’ drop type ytdsales_tabletype go CREATE TYPE ytdsales_tabletype AS TABLE title_id char6

Trang 1

CHAPTER 42 What’s New for Transact-SQL in SQL Server 2008

@time3 as ‘time3’

select

@datetime2 as ‘datetime2’,

@datetimeoffset as ‘datetimeoffset’,

@utcdatetime as ‘utcdatetime’

select SYSDATETIMEOFFSET() as sysdatetimeoffset,

SYSDATETIME() as sysdatetime

go

datetime date time time3

- - -

-2010-03-28 23:18:30.490 -2010-03-28 23:18:30.4904294 23:18:30.492

datetime2 datetimeoffset utcdatetime

-

-2010-03-28 23:18:30.49 -2010-03-28 23:18:30.4924295 -04:00 2010-03-29 03:18:30.49

sysdatetimeoffset sysdatetime

-

-2010-03-28 23:24:10.7485902 -04:00 -2010-03-28 23:24:10.74

Be aware that retrieving the value from getdate()orsysdatetime()into a

datetimeoffsetvariable or column does not capture the offset from UTC, even if you

store the returned value in a column or variable defined with the datetimeoffsetdata

type To do so, you need to use the SYSDATETIMEOFFSET()function:

declare @datetimeoffset1 datetimeoffset,

@datetimeoffset2 datetimeoffset

select

@datetimeoffset1 = SYSDATETIME(),

@datetimeoffset2 = SYSDATETIMEOFFSET()

select @datetimeoffset1, @datetimeoffset2

go

-2010-03-28 23:36:39.7271831 +00:00 -2010-03-28 23:36:39.7271831 -04:00

Note that in the output, SQL Server Management Studio (SSMS) trims the time values

down to two decimal places when it displays the results in the Text Results tab However,

this is just for display purposes (and applies only with text results; grid results display the

full decimal precision) The actual value does store the precision down to the specified

number of decimal places, which can be seen if you convert the datetime2value to a

string format that displays all the decimal places:

Trang 2

select SYSDATETIME() as datetime2_trim,

convert(varchar(30), SYSDATETIME(), 121) as datetime2_full

go

datetime2_trim datetime2_full

-

-2010-03-30 23:52:30.68 -2010-03-30 23:52:30.6851262

TheSWITCHOFFSET()function can be used to convert a datetimeoffsetvalue into a

differ-ent time zone offset value:

select SYSDATETIMEOFFSET(), SWITCHOFFSET ( SYSDATETIMEOFFSET(), ‘-07:00’ )

go

-2010-03-29 00:07:21.1335738 -04:00 2010-03-28 21:07:21.1335738 -07:00

When you are specifying a time zone value for the SWITCHOFFSETorTODATETIMEOFFSET

offset functions, the value can be specified as an integer value representing the number of

minutes of offset or as a time value in hh:mm format The range of allowed values is +14

hours to -13 hours

select TODATETIMEOFFSET ( SYSDATETIME(), -300 )

select TODATETIMEOFFSET ( SYSDATETIME(), ‘-05:00’ )

go

-2010-03-29 00:23:05.5773288 -05:00

-2010-03-29 00:23:05.5773288 -05:00

Date and Time Conversions

If an existing CONVERTstyle includes the time part, and the conversion is from

datetimeoffsetto a string, the time zone offset (except for style 127) is included If you

do not want the time zone offset, you need to use cast or convert the datetimeoffset

value to datetime2first and then to a string:

select convert(varchar(35), SYSDATETIMEOFFSET(), 121) as datetime_offset,

CONVERT(varchar(30), cast(SYSDATETIMEOFFSET() as datetime2),121) as datetime2

go

datetime_offset datetime2

-

-2010-03-30 23:57:36.1015950 -04:00 -2010-03-30 23:57:36.1015950

Trang 3

CHAPTER 42 What’s New for Transact-SQL in SQL Server 2008

When you convert from datetime2ordatetimeoffsettodate, there is no rounding and

the date part is extracted explicitly For any implicit conversion from datetimeoffsetto

date,time,datetime2,datetime, or smalldatetime, conversion is based on the local date

and time value (to the persistent time zone offset) For example, when the

datetimeoffset(3)value,2006-10-21 12:20:20.999 -8:00, is converted to time(3), the

result is 12:20:20.999,not20:20:20.999(UTC)

If you convert from a higher-precision time value to a lower-precision value, the conversion

is permitted, and the higher-precision values are truncated to fit the lower precision type

If you are converting a time(n),datetime2(n),ordatetimeoffset(n)value to a string,

the number of digits depends on the type specification If you want a specific precision in

the resulting string, convert to a data type with the appropriate precision first and then to

a string, as follows:

select

convert(varchar(35), sysdatetime(), 121) as datetime_offset,

CONVERT(varchar(30), cast(sysdatetime() as datetime2(3)), 121) as datetime2

go

datetime_offset datetime2

-

-2010-03-31 00:04:37.3306880 -2010-03-31 00:04:37.331

If you attempt to cast a string literal with a fractional seconds precision that is more than

that allowed for smalldatetimeordatetime, Error 241 is raised:

declare @datetime datetime

select @datetime = ‘2010-03-31 00:04:37.3306880’

go

Msg 241, Level 16, State 1, Line 2

Conversion failed when converting date and/or time from character string.

Table-Valued Parameters

In previous versions of SQL Server, it was not possible to share the contents of table

vari-ables between stored procedures SQL Server 2008 changes that with the introduction of

table-valued parameters, which allow you to pass table variables to stored procedures as

input parameters Table-valued parameters provide more flexibility and, in many cases,

better performance than temporary tables as a means to pass result sets between stored

procedures

Trang 4

To create and use table-valued parameters, you must first create a user-defined table type

as a TABLEdata type and define the table structure This is done using the CREATE TYPE

command, as shown in Listing 42.10

if exists (select * from sys.systypes t where t.name = ‘ytdsales_tabletype’

and t.uid = USER_ID(‘dbo’)) drop type ytdsales_tabletype

go

CREATE TYPE ytdsales_tabletype AS TABLE

(title_id char(6),

title varchar(50),

pubdate date,

ytd_sales int)

go

After creating the user-defined table data type, you can use it for declaring local table

vari-ables and for stored procedure parameters To use the table-valued parameter in a

proce-dure, you create a procedure to receive and access data through a table-valued parameter,

as shown in Listing 42.11

/* Create a procedure to receive data for the table-valued parameter */

if OBJECT_ID(‘tab_parm_test’) is not null

drop proc tab_parm_test

go

create proc tab_parm_test

@pubdate datetime = null,

@sales_minimum int = 0,

@ytd_sales_tab ytdsales_tabletype READONLY

as

set nocount on

if @pubdate is null

if no date is specified, set date to last year

set @pubdate = dateadd(month, -12, getdate())

select * from @ytd_sales_tab

where pubdate > @pubdate

and ytd_sales >= @sales_minimum

return

go

Trang 5

CHAPTER 42 What’s New for Transact-SQL in SQL Server 2008

Then, when calling that stored procedure, you declare a local table variable using the table

data type defined previously, populate the table variable with data, and then pass the table

variable to the stored procedure (see Listing 42.12)

/* Declare a variable that references the table type */

declare @ytd_sales_tab ytdsales_tabletype

/* Add data to the table variable */

insert @ytd_sales_tab

select title_id, convert(varchar(50), title), pubdate, ytd_sales

from titles

/* Pass the table variable populated with data to a stored procedure */

exec tab_parm_test ‘6/1/2001’, 10000, @ytd_sales_tab

go

title_id title ytd_sales

- -

-BU2075 You Can Combat Computer Stress! 18722

MC3021 The Gourmet Microwave 22246

TC4203 Fifty Years in Buckingham Palace Kitchens 15096

The scope of a table-valued parameter is limited to only the stored procedure to which it is

passed To access the contents of a table-valued parameter in a procedure called by

another procedure that contains a valued parameter, you need to pass the

table-valued parameter to the subprocedure Listing 42.13 provides an example of a

subproce-dure and alters the procesubproce-dure created in Listing 42.6 to call the subprocesubproce-dure

/* Create the sub-procedure */

create proc tab_parm_subproc

@pubdate datetime = null,

@sales_minimum int = 0,

@ytd_sales_tab ytdsales_tabletype READONLY

as

select * from @ytd_sales_tab

where ytd_sales <= @sales_minimum

and ytd_sales <> 0

Trang 6

go

/* modify the tab_part_test proc to call the sub-procedure */

alter proc tab_parm_test

@pubdate datetime = null,

@sales_minimum int = 0,

@ytd_sales_tab ytdsales_tabletype READONLY

as

set nocount on

if @pubdate is null

if no date is specified, set date to last year

set @pubdate = dateadd(month, -12, getdate())

select * from @ytd_sales_tab

where pubdate > @pubdate

and ytd_sales >= @sales_minimum

exec tab_parm_subproc @pubdate,

@sales_minimum,

@ytd_sales_tab return

go

/* Declare a variable that references the type */

declare @ytd_sales_tab ytdsales_tabletype

/* Add data to the table variable */

insert @ytd_sales_tab

select title_id, convert(varchar(50), title), pubdate, ytd_sales

from titles

where type = ‘business’

/* Pass the table variable populated with data to a stored procedure */

exec tab_parm_test ‘6/1/2001’, 10000, @ytd_sales_tab

go

title_id title pubdate ytd_sales

- - -

-BU2075 You Can Combat Computer Stress! 2004-06-30 18722

title_id title pubdate ytd_sales

- - -

-BU1032 The Busy Executive’s Database Guide 2004-06-12 4095

Trang 7

CHAPTER 42 What’s New for Transact-SQL in SQL Server 2008

BU1111 Cooking with Computers: Surreptitious Balance Shee 2004-06-09 3876

BU7832 Straight Talk About Computers 2004-06-22 4095

Table-Valued Parameters Versus Temporary Tables

Table-valued parameters offer more flexibility and in some cases better performance than

temporary tables or other ways to pass a list of values to a stored procedure One benefit is

table-valued parameters do not acquire locks for the initial population of data from a

client Also, table-valued parameters are memory resident and do not incur physical I/O

unless they grow too large to remain in cache memory

However, table-valued parameters do have some restrictions:

SQL Server does not create or maintain statistics on columns of table-valued

parame-ters

Table-valued parameters can be passed only as READONLYinput parameters to T-SQL

routines You cannot perform UPDATE,DELETE, or INSERToperations on a table-valued

parameter within the body of the stored procedure to which it is passed

Like table variables, a table-valued parameter cannot be specified as the target of a

SELECT INTOorINSERT EXECstatement They can only be populated using an

INSERTstatement

Hierarchyid Data Type

TheHierarchyiddata type introduced in SQL Server 2008 is actually a system-supplied

common language runtime (CLR) user-defined type (UDT) that can be used for storing and

manipulating hierarchical structures (for example, parent-child relationships) in a

rela-tional database The Hierarchyidtype is stored as a varbinaryvalue that represents the

position of the current node in the hierarchy (both in terms of parent-child position and

position among siblings) You can perform manipulations on the type in Transact-SQL by

invoking methods exposed by the type

Creating a Hierarchy

First, let’s define a hierarchy in a table using the Hierarchyiddata type For example, this

section uses the Partstable example used in Chapter 28, “Creating and Managing Stored

Procedures,” to demonstrate how a stored procedure could be used to traverse a hierarchy

stored in a table There is also an example in Chapter 52 using a recursive common table

expression (CTE) to perform a similar action Let’s see how to implement an alternative

solution by adding a Hierarchyidcolumn to the Parts table First, you create a version of

thePartstable using the Hierarchyiddata type (see Listing 42.14)

Trang 8

Use bigpubs2008

Go

CREATE TABLE PARTS_hierarchy(

partid int NOT NULL,

hid hierarchyid not null,

lvl as hid.GetLevel() persisted,

partname varchar(30) NOT NULL,

PRIMARY KEY NONCLUSTERED (partid),

UNIQUE NONCLUSTERED (partname)

)

Note the hidcolumn defined with the Hierarchyiddata type Notice also how the lvl

column is defined as a compute column using the GetLevelmethod of the hidcolumn to

define the persisted computed column level The GetLevelmethod returns the level of the

current node in the hierarchy

TheHierarchyiddata type provides topological sorting, meaning that a child’s sort value is

guaranteed to be greater than the parent’s sort value This guarantees that a node’s sort value

will be higher than all its ancestors You can take advantage of this feature by creating an index

on the Hierarchyidcolumn because the index will sort the data in a depth-first manner This

ensures that all members of the same subtree are close to each other in the leaf level of the

index, which makes the index useful as an efficient mechanism for returning all descendents of

a node To take advantage of this, you can create a clustered index on the hidcolumn:

CREATE UNIQUE CLUSTERED INDEX idx_hid_first ON Parts_hierarchy (hid);

You can also use another indexing strategy called breadth-first, in which you organize all

nodes from the same level close to each other in the leaf level of the index This is done by

building the index such that the leading column is level in the hierarchy Queries that need

to get all nodes from the same level in the hierarchy can benefit from this type of index:

CREATE UNIQUE INDEX idx_lvl_first ON Parts_hierarchy(lvl, hid);

Populating the Hierarchy

Now that you’ve created the hierarchy table, the next step is to populate it To insert a

new node into the hierarchy, you must first produce a new Hierarchyidvalue that

repre-sents the correct position in the hierarchy There are two methods available with the

Hierarchyiddata type to do this: the HIERARCHYID::GetRoot()method and

GetDescendantmethod You use the HIERARCHYID::GetRoot()method to produce the

value for the root node of the hierarchy This method simply produces a Hierarchyid

value that is internally an empty binary string representing the root of the tree

You can use the GetDescendantmethod to produce a value below a given parent The

GetDescendantmethod accepts two optional Hierarchyidinput values that represent the

two nodes between which you want to position the new node If both values are not NULL,

the method produces a new value positioned between the two nodes If the first parameter

Trang 9

CHAPTER 42 What’s New for Transact-SQL in SQL Server 2008

is not NULLand the second parameter is NULL, the method produces a value greater than

the first parameter Finally, if the first parameter is NULLand the second parameter is not

NULL, the method produces a value smaller than the second parameter If both parameters

areNULL, the method produces a value simply below the given parent

NOTE

TheGetDescendantmethod does not guarantee that Hierarchyidvalues are unique

To enforce uniqueness, you must define either a primary key, unique constraint, or

unique index on the Hierarchyidcolumn

The code in Listing 42.15 uses a cursor to loop through the rows currently in the Parts

table and populates the Parts_hierarchytable If the part is the first node in the

hierar-chy, the procedure uses the HIERARCHYID::GetRoot()method to assign the hidvalue for

the root node of the hierarchy Otherwise, the code in the cursor looks for the last child

hidvalue of the new part’s parent part and uses theGetDescendantmethod to produce a

value that positions the new node after the last child of that parent part

NOTE

Listing 42.15 also makes use of a recursive common table expression to traverse the

existingPartstable in hierarchical order to add in the rows at the proper level, starting

with the top-most parent part If you are unfamiliar with CTEs (which were introduced in

SQL Server 2005), you may want to review the “In Case you Missed it…” section in

Chapter 43

DECLARE

@hid AS HIERARCHYID,

@parent_hid AS HIERARCHYID,

@last_child_hid AS HIERARCHYID,

@partid int,

@partname varchar(30),

@parentpartid int

declare parts_cur cursor for

WITH PartsCTE(partid, partname, parentpartid, lvl)

AS

(

SELECT partid, partname, parentpartid, 0

FROM PARTS

WHERE parentpartid is null

Trang 10

UNION ALL

SELECT P.partid, P.partname, P.parentpartid, PP.lvl+1

FROM Parts as P

JOIN PartsCTE as PP

ON P.parentpartid = PP.Partid

)

SELECT PartID, Partname, ParentPartid

FROM PartsCTE

order by lvl

open parts_cur

fetch parts_cur into @partid, @partname, @parentpartid

while @@FETCH_STATUS = 0

begin

if @parentpartid is null

set @hid = HIERARCHYID::GetRoot()

else

begin

select @parent_hid = hid from PARTS_hierarchy

where partid = @parentpartid

select @last_child_hid = MAX(hid) from PARTS_hierarchy

where hid.GetAncestor(1) = @parent_hid

select @hid = @parent_hid.GetDescendant(@last_child_hid, NULL)

end

insert PARTS_hierarchy (partid, hid, partname)

values (@partid, @hid, @partname)

fetch parts_cur into @partid, @partname, @parentpartid

end

close parts_cur

deallocate parts_cur

go

Querying the Hierarchy

Now that you’ve populated the hierarchy, you should query it to view the data and verify

the hierarchy was populated correctly However, If you query the hidvalue directly, you

see only its binary representation, which is not very meaningful To view the Hierarchyid

value in a more useful manner, you can use the ToStringmethod, which returns a logical

string representation of the Hierarchyid This string representation is shown as a path

Ngày đăng: 05/07/2014, 02:20

TỪ KHÓA LIÊN QUAN