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

Hướng dẫn học Microsoft SQL Server 2008 part 71 doc

10 242 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 0,97 MB

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

Nội dung

The following code is a simple example of a rollback DDL trigger blocking any stored procedures from being altered in the database: CREATE TRIGGER NoTouchDaProc ON DATABASE FOR ALTER_PRO

Trang 1

Nielsen c27.tex V4 - 07/23/2009 8:27pm Page 662

Developing DDL Triggers

The code in the trigger is normal T-SQL code In some way, a DDL trigger is easier to write than a DML

trigger because DDL triggers always fire for a single event, whereas DML triggers must handle events

with multiple affected rows involving the base table, and theinsertedanddeletedvirtual tables

The complexity of the DDL trigger results from the fact that the data about the event is in XML

EventData()

DDL triggers can respond to so many different events that they need some method of capturing data

about the event that caused them to fire DML triggers have theinsertedanddeletedvirtual tables;

DDL triggers have theEventData()function This function returns XML-formatted data about the

event The XML schema varies according to the type of event captured Note that parts of the XML

schema are case sensitive

Using theEventData()function to populate an XML variable, the trigger can use XQuery to

investi-gate the values Use the XQueryValue()method to extract the data from the XML

The XML schema for event data is atC:\Program Files\Microsoft SQL Server\100\Tools\

Binn\schemas\sqlserver\2006\11\events\events.xsd

Alternatively, the event schema is published athttp://schemas.microsoft.com/sqlserver

The following code example creates a DDL trigger that readsEventData()into an XML variable and

then selects from the variable to display the data:

CREATE TRIGGER DDLTrigger

ON DATABASE FOR CREATE_TABLE AS

Set NoCount ON

DECLARE @EventData XML = EventData()

SELECT

@EventData.value (’data(/EVENT_INSTANCE/SchemaName)[1]’,’VARCHAR(50)’) as

‘Schema’,

@EventData.value (’data(/EVENT_INSTANCE/ObjectName)[1]’, ‘VARCHAR(50)’) as

‘Object’,

@EventData.value (’data(/EVENT_INSTANCE/EventType)[1]’, ‘VARCHAR(50)’) as

‘EventType’

With the DDL triggers in place, the next comamnd creates a table, which fires the trigger, which

examinesEventData’s XML, and returns the values to the client:

CREATE TABLE Test (Col1 INT)

Trang 2

Nielsen c27.tex V4 - 07/23/2009 8:27pm Page 663

DDL Triggers 27

Result:

- -

For more on XML and working with XQuery, see Chapter 18, ‘‘Manipulating XML Data.’’

Preventing database object changes

DDL triggers can execute code, including executing a transaction rollback command Such a trigger

could prohibit anyone from making server- or database-level changes

The following code is a simple example of a rollback DDL trigger blocking any stored procedures from

being altered in the database:

CREATE TRIGGER NoTouchDaProc

ON DATABASE

FOR ALTER_PROCEDURE, DROP_PROCEDURE

AS

Set NoCount ON

Raiserror (’These Procs may not be altered or dropped!’,16,1)

Rollback

To test the DDL trigger, the next few commands attempt to modify the procedure so it won’t print

‘‘SQL Rocks!’’:

DROP PROC QuickProc

Result:

Msg 50000, Level 16, State 1, Procedure NoTouchDaProc, Line 6

These Procs may not be altered or dropped!

Msg 3609, Level 16, State 2, Procedure QuickProc, Line 3

The transaction ended in the trigger The batch has been aborted

And

ALTER PROC QuickProc

AS

Print ‘Oracle Rocks!’

Result:

Msg 50000, Level 16, State 1, Procedure NoTouchDaProc, Line 6

These Procs may not be altered or dropped!

Trang 3

Nielsen c27.tex V4 - 07/23/2009 8:27pm Page 664

Part IV Developing with SQL Server

With DDL triggers, you can write your own system to prevent object changes that disagree with your

shop’s policies, but a more strategic solution might be to use SQL Server 2008’s new policy-based

management feature, documented in Chapter 40, ‘‘Policy-Based Management.’’

Summary

DDL triggers provide a safety net — a way to track every change to the schema The event model that

can be tracked is comprehensive and the data available to the trigger using theEventData()function

and XML is dynamic and complete Without a doubt, DDL triggers serve their purpose well

Highlights from this chapter are as follows:

■ Server-level DDL triggers can trap any event and are seen in Object Explorer under the Server Objects➪ Triggers node

■ Database-level DDL triggers exist in the user database, can only fire for database-level events,

and are listed in Object Explorer in the [Database]➪ Programmability ➪ Database Triggers node

■ DDL Triggers can fire for any specific DDL event, or for DDL Event Groups — a hierarchy of DDL events

■ Because DDL triggers can fire for such a broad range of events, theEventData()function returns XML data about the event

The next chapter continues the theme of developing with SQL Server with the critical concepts of

build-ing out the abstraction layer

Trang 4

Nielsen c28.tex V4 - 07/23/2009 4:58pm Page 665

Building Out the Data

Abstraction Layer

IN THIS CHAPTER

Buying database extensibility Building CRUD stored procedures

Searching stored procedures

Irecently blogged the question, ‘‘Why use stored procedures?’’ (http://

tinyurl.com/ohauye) and received a firestorm of replies I invite

you to add your view to the replies — let’s attempt the most replies on

SQLBlog.com

My post is based on the discussion of extensibility presented in Chapter 2, ‘‘Data

Architecture,’’ and makes the point that the abstraction layer should be as

perma-nent as the data it encapsulates The only effective data abstraction layer is T-SQL

One of the talks I give at conferences is ‘‘7 SQL Server development practices

more evil than cursors.’’ What’s the number one worst development practice on

my list? Ad-hoc SQL, because it violates the abstraction layer and creates a brittle

database

There are many good reasons for wrapping the database in a protective layer of

stored procedures:

■ Extensibility: It’s far easier to modify the database when there’s a

consistent contract to access the database

■ Usability: It’s far easier for application developers to call a set of stored

procedure API calls that return the correct result set than for them to

write correct SQL queries

■ Integrity: The goal is to get the correct answer to the question Stored

procedures written by database developers will include better queries

than ad-hoc SQL written by application developers

■ Performance: Moving the lookups and validation closer to the data

improves performance

■ Security: The best security (tighter control, reduced surface area, limits

Trang 5

Nielsen c28.tex V4 - 07/23/2009 4:58pm Page 666

Part IV Developing with SQL Server

The basic idea is that a contract, or API agreement, drives development on both the database and

the client side If the database developers want to refactor the database to increase performance or

integrity or add new features that don’t change the API, then they are free to do so without affecting

any other code If the application needs a new feature that affects the API, then both sides need to agree

on the change and can work on the modification independently until both are ready for integration

testing

CRUD Stored Procedures

Generally speaking, the data abstraction layer needs an interface for each table for each of the following

tasks:

■ Searching for multiple rows

■ Fetching a single row

■ Inserting new data

■ Updating existing data

■ Deleting existing data Each of these stored procedures should include data validation, transaction control, and error handling

For lookup tables, some choose to build a more dynamic solution that allows a single set of stored

pro-cedures to work against multiple tables by making the table name a parameter and dynamically building

theFROMclause within the stored procedure

For examples of these stored procedures, please download the latest version of the

OBXKites sample database from www.sqlserverbible.com I’m also considering developing an AutoCRUD utility that will code-gen CRUD stored procedures If

you’d like to use such a utility, please e-mail me at pauln@sqlserverbible.com

Best Practice

When designing the data abstraction layer, avoid using a CRUD matrix approach — CRUD being a list

of create, retrieve, update, and delete functions for every table A data abstraction layer — that is,

a set of sprocs for every table — will tend to lock in the schema to that set of sprocs Instead, design the

data abstraction layer as a set of logical contracts that deal with business entities and tasks, even though

the contract may involve multiple underlying tables

For example, design a single interface that involves the inventory, order, and shipping tables Decreasing

the inventory count for an item might involve updating the count field, triggering a reorder, and updating a

physical capacity table You want to ensure that one contract does it all

Trang 6

Nielsen c28.tex V4 - 07/23/2009 4:58pm Page 667

Building Out the Data Abstraction Layer 28

Google-Style Search Procedure

Of the standard data abstraction layer stored procedures, the most interesting one is the search stored

procedure This Google-style search comes from Nordic (New Object/Relational Design) version 2.09 —

my CodePlex.com project that transforms SQL Server into an object database It works very well even

against millions of rows Of course, this is a work in progress, so please get the newest version from

CodePlex.com or SQLServerBible.com

The goal of the Google-style search is to enable users to enter as many search words as desired in any

order and then find the best results I’ve had a lot of fun designing this search routine

The common solution is to use dynamic SQL to generate a complexWHEREclause This solution instead

splits the@SearchStringwords entry into a set-based list and stores the search words in a table

vari-able The table variable is then joined with several data sources — names, object code, and a list of data

extracted from searchable columns Each time a row is found it’s added to the #Resultstable As the

row is found multiple times, itshitscounter is incremented At the end, the rows with the most hits

are sorted to the top of the list This search also handles class, workflow state, and association filters,

which are shown toward the end of the listing:

Create

alter

PROC SearchObjects

(@ClassID INT,

@StateID INT = NULL,

@SearchString VARCHAR(500) = NULL,

@AssocMMID INT = NULL,

@HASAssoc BIT = 0)

WITH recompile

AS

CREATE TABLE #Results (

ObjectID INT NOT NULL PRIMARY KEY ,

Hits TINYINT NULL

) ;

CREATE TABLE #Classes (ClassID INT)

INSERT #Classes

SELECT ClassID

FROM dbo.SubClassesID(@ClassID)

DECLARE @SQL NVARCHAR(MAX)

SET NoCount ON

IF @SearchString = ‘’

SET @SearchString = NULL

Trang 7

Nielsen c28.tex V4 - 07/23/2009 4:58pm Page 668

IF @SearchString IS NULL AND @StateID IS NULL INSERT #Results (ObjectID, Hits)

SELECT top(1000) o.ObjectID, 1 FROM Object o

JOIN #Classes c

ON o.ClassID = c.ClassID LEFT JOIN dbo.State s ON o.StateID = s.StateID WHERE o.ClassID IN (SELECT ClassID FROM dbo.SubClassesID(@ClassID))

- All in class / state search

IF @SearchString IS NULL AND @StateID IS NOT NULL INSERT #Results (ObjectID, Hits)

SELECT top(1000) o.ObjectID, 1 FROM Object o

JOIN #Classes c

ON o.ClassID = c.ClassID JOIN dbo.State s

ON o.StateID = s.StateID WHERE o.StateID = @StateID - save search string

IF @SearchString IS NOT NULL BEGIN

DECLARE @User SYSNAME SET @User = SUSER_SNAME() upsert

UPDATE dbo.SearchHistory SET LastViewDate = GETDATE() WHERE SearchString = @SearchString AND [User] = @User

IF @@RowCount = 0 rewrite as MERGE INSERT dbo.SearchHistory ([User], SearchString, LastViewDate) VALUES (@User, @SearchString, GETDATE())

- Object Code Exact match / first word entry /

regardless of class / state / associations / anything

IF Exists(SELECT * FROM dbo.Object WHERE ObjectCode = @SearchString) BEGIN

EXEC SearchObjects_ObjectCode @SearchString RETURN

END

Trang 8

Nielsen c28.tex V4 - 07/23/2009 4:58pm Page 669

Building Out the Data Abstraction Layer 28

- Parse out multiple search words

DECLARE @SearchWords TABLE

(Word VARCHAR(50))

INSERT @SearchWords (Word)

SELECT String

FROM dbo.String2Set(LTRIM(RTRIM(@SearchString)))

Exact Name2 Match - 1 points

should be a merge

INSERT #Results (ObjectID, Hits)

SELECT ObjectID, 1

FROM @SearchWords W

JOIN dbo.Object O

ON O.Name2 = W.Word

JOIN #Classes C

ON O.ClassID = C.ClassID

GROUP BY ObjectID

Exact Name1 Match - 1 points

MERGE #Results AS R

USING (

SELECT ObjectID , COUNT(*) as Hits

FROM @SearchWords W JOIN dbo.Object O

ON O.Name1 = W.Word JOIN #Classes C

ON O.ClassID = C.ClassID GROUP BY ObjectID

) as S

ON R.ObjectID = S.ObjectID

WHEN Matched

THEN UPDATE

SET Hits += R.Hits

WHEN NOT MATCHED BY TARGET

THEN INSERT (ObjectID, Hits)

VALUES(ObjectID, 1);

Name1 Soundex - 1 point

MERGE #Results AS R

USING (

SELECT ObjectID

FROM @SearchWords W JOIN dbo.Object O

ON O.Name1Soundex = Soundex(W.Word)

Trang 9

Nielsen c28.tex V4 - 07/23/2009 4:58pm Page 670

ON R.ObjectID = S.ObjectID WHEN Matched

THEN UPDATE

SET Hits = R.Hits + 1 WHEN NOT MATCHED BY TARGET THEN INSERT (ObjectID, Hits)

VALUES(ObjectID, 1);

Name2 Soundex - 1 point MERGE #Results AS R

USING (

SELECT ObjectID FROM @SearchWords W JOIN dbo.Object O

ON O.Name2Soundex = Soundex(W.Word) JOIN #Classes C

ON O.ClassID = C.ClassID) as S

ON R.ObjectID = S.ObjectID WHEN Matched

THEN UPDATE

SET Hits = R.Hits + 1 WHEN NOT MATCHED BY TARGET THEN INSERT (ObjectID, Hits)

VALUES(ObjectID, 1);

Exact Seachable Column Match - 1 point per hit MERGE #Results AS R

USING (

SELECT ObjectID, COUNT(*) as Hits FROM SearchWordList SWL

JOIN @SearchWords W

ON SWL.Word = W.Word JOIN #Classes C

ON O.ClassID = C.ClassID GROUP BY ObjectID) as S

ON R.ObjectID = S.ObjectID WHEN Matched

THEN UPDATE

SET Hits = R.Hits + S.Hits WHEN NOT MATCHED BY TARGET

THEN INSERT (ObjectID, Hits)

VALUES(ObjectID, 1);

END @SearchString IS NOT NULL - apply filters

IF @StateID IS NOT NULL

Trang 10

Nielsen c28.tex V4 - 07/23/2009 4:58pm Page 671

Building Out the Data Abstraction Layer 28

DELETE #Results

WHERE ObjectID IN

(SELECT ObjectID FROM dbo.Object WHERE StateID <> @StateID)

IF @AssocMMID IS NOT NULL AND @HASAssoc = 0

DELETE #Results

WHERE ObjectID NOT IN

(SELECT ObjectID

FROM Association A JOIN AssociationMatrix AM

ON A.AssociationMatrixID = AM.AssociationMatrixID JOIN dbo.ClassStateAssociationMatrix CSAM

ON AM.AssociationMatrixID = CSAM.AssociationMatrixID WHERE AM.AssociationMatrixMasterID = @AssocMMID)

IF @AssocMMID IS NOT NULL AND @HASAssoc = 1

DELETE #Results

WHERE ObjectID IN

(SELECT ObjectID

FROM Association A JOIN AssociationMatrix AM

ON A.AssociationMatrixID = AM.AssociationMatrixID JOIN dbo.ClassStateAssociationMatrix CSAM

ON AM.AssociationMatrixID = CSAM.AssociationMatrixID WHERE AM.AssociationMatrixMasterID = @AssocMMID)

Return Results

SELECT TOP 1000 o.ObjectID, c.ClassID, c.ClassName, s.StateID,

s.StateName, o.ObjectCode, o.Name1, o.Name2,

‘(’ + Cast(r.Hits as VARCHAR(9)) + ‘) ’

+ IsNull(dbo.SearchDetails(o.ObjectID),’’) AS Descript, o.Created, o.Modified,

o.Version

FROM #Results r

JOIN dbo.Object o

ON r.ObjectID = o.ObjectID

JOIN dbo.Class c

ON o.ClassID = c.ClassID

LEFT JOIN dbo.State s

ON o.StateID = s.StateID

WHERE r.Hits > (Select max(Hits) /2 FROM #Results)

ORDER BY r.Hits DESC, ObjectCode

RETURN

The real point of this procedure isn’t the cool way it searches multiple locations for multiple words, but

Ngày đăng: 04/07/2014, 09:20

TỪ KHÓA LIÊN QUAN