📄 ch13.htm
字号:
is no longer valid. <P> <LI>Trigger--A cursor created inside a trigger has the same restrictions as one created inside a stored procedure.</UL><H2><FONT COLOR="#000077">Creating and Using Stored Procedures</FONT></H2><P>The concept of stored procedures is an important one for the professional databaseprogrammer to master. Stored procedures are functions that contain potentially largegroupings of SQL statements. These functions are called and executed just as C, FORTRAN,or Visual Basic functions would be called. A stored procedure should encapsulatea logical set of commands that are often executed (such as a complex set of queries,updates, or inserts). Stored procedures enable the programmer to simply call thestored procedure as a function instead of repeatedly executing the statements insidethe stored procedure. However, stored procedures have additional advantages.</P><P>Sybase, Inc., pioneered stored procedures with its SQL Server product in the late1980s. These procedures are created and then stored as part of a database, just astables and indexes are stored inside a database. Transact SQL permits both inputand output parameters to stored procedure calls. This mechanism enables you to createthe stored procedures in a generic fashion so that variables can be passed to them.</P><P>One of the biggest advantages to stored procedures lies in the design of theirexecution. When executing a large batch of SQL statements to a database server overa network, your application is in constant communication with the server, which cancreate an extremely heavy load on the network very quickly. As multiple users becomeengaged in this communication, the performance of the network and the database serverbecomes increasingly slower. The use of stored procedures enables the programmerto greatly reduce this communication load.</P><P>After the stored procedure is executed, the SQL statements run sequentially onthe database server. Some message or data is returned to the user's computer onlywhen the procedure is finished. This approach improves performance and offers otherbenefits as well. Stored procedures are actually compiled by database engines thefirst time they are used. The compiled map is stored on the server with the procedure.Therefore, you do not have to optimize SQL statements each time you execute them,which also improves performance.</P><P>Use the following syntax to create a stored procedure using Transact-SQL:</P><H5>SYNTAX:</H5><PRE><FONT COLOR="#0066FF">create procedure procedure_name [[(]@parameter_name datatype [(length) | (precision [, scale]) [= default][output] [, @parameter_name datatype [(length) | (precision [, scale]) [= default][output]]...[)]] [with recompile] as SQL_statements</FONT></PRE><P>This <TT>EXECUTE</TT> command executes the procedure:</P><H5>SYNTAX:</H5><PRE><FONT COLOR="#0066FF">execute [@return_status = ] procedure_name [[@parameter_name =] value | [@parameter_name =] @variable [output]...]] [with recompile]</FONT></PRE><H4><FONT COLOR="#000077">Example 13.5</FONT></H4><P>This example creates a simple procedure using the contents of Example 13.4.</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF">1> <B>create procedure Print_Artists_Name</B>2> <B>as</B>3> <B>declare @name char(30)</B>4> <B>declare @homebase char(40)</B>5> <B>declare @style char(20)</B>6> <B>declare @artist_id int</B>7> <B>create Artists_Cursor cursor</B>8> <B>for select * from ARTISTS</B>9> <B>open Artists_Cursor</B>10> <B>fetch Artists_Cursor into @name, @homebase, @style, @artist_id</B>11> <B>while (@@sqlstatus = 0)</B>12> <B>begin</B>13> <B>print @name</B>14> <B>fetch Artists_Cursor into @name, @homebase, @style, @artist_id</B>15> <B>end</B>16> <B>close Artists_Cursor</B>17><B> deallocate cursor Artists_Cursor</B>18> <B>go</B></FONT></PRE><P>You can now execute the<TT> Print_Artists_Name</TT> procedure using the <TT>EXECUTE</TT>statement:</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF">1> <B>execute Print_Artists_Name</B>2> <B>go</B></FONT></PRE><H5><FONT COLOR="#000000">OUTPUT:</FONT></H5><PRE><FONT COLOR="#0066FF">Soul AsylumMaurice RavelDave Matthews BandVince GillOingo BoingoCrowded HouseMary Chapin-CarpenterEdward MacDowell</FONT></PRE><P>Example 13.5 was a small stored procedure; however, a stored procedure can containmany statements, which means you do not have to execute each statement individually.<H3><FONT COLOR="#000077">Using Stored Procedure Parameters</FONT></H3><P>Example 13.5 was an important first step because it showed the use of the simplest<TT>CREATE PROCEDURE</TT> statement. However, by looking at the syntax given here,you can see that there is more to the <TT>CREATE PROCEDURE</TT> statement than wasdemonstrated in Example 13.5. Stored procedures also accept parameters as input totheir SQL statements. In addition, data can be returned from a stored procedure throughthe use of output parameters.</P><P>Input parameter names must begin with the <TT>@</TT> symbol, and these parametersmust be a valid Transact-SQL data type. Output parameter names must also begin withthe <TT>@</TT> symbol. In addition, the <TT>OUTPUT</TT> keyword must follow the outputparameter names. (You must also give this <TT>OUTPUT</TT> keyword when executingthe stored procedure.)</P><P>Example 13.6 demonstrates the use of input parameters to a stored procedure.<H4><FONT COLOR="#000077">Example 13.6</FONT></H4><P>The following stored procedure selects the names of all artists whose media typeis a CD:</P><PRE><FONT COLOR="#0066FF">1> <B>create procedure Match_Names_To_Media @description char(30)</B>2> <B>as</B>3> <B> select ARTISTS.name from ARTISTS, MEDIA, RECORDINGS</B>4> <B>where MEDIA.description = @description and</B>5> <B> MEDIA.media_type = RECORDINGS.media_type and</B>6> <B> RECORDINGS.artist_id = ARTISTS.artist_id</B>7> <B>go</B>1> <B>execute Match_Names_To_Media "CD"</B>2> <B>go</B></FONT></PRE><P>Executing this statement would return the following set of records:</P><H5>OUTPUT:</H5><PRE><FONT COLOR="#0066FF">NAMESoul AsylumMaurice RavelVince GillCrowded HouseMary Chapin-Carpenter</FONT></PRE><H4><FONT COLOR="#000077">Example 13.7</FONT></H4><P>This example demonstrates the use of output parameters. This function takes theartist's homebase as input and returns the artist's name as output:</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF">1> <B>create procedure Match_Homebase_To_Name @homebase char(40), @name char(30) output</B>2> <B>as</B>3> <B>select @name = name from ARTISTS where homebase = @homebase</B>4><B> go</B>1> <B>declare @return_name char(30)</B>2> <B>execute Match_Homebase_To_Name "Los Angeles", @return_name = @name output</B>3> <B>print @name</B>4> <B>go</B></FONT></PRE><H5><FONT COLOR="#000000">OUTPUT:</FONT></H5><PRE><FONT COLOR="#000000"></FONT></PRE><PRE><FONT COLOR="#0066FF">Oingo Boingo</FONT></PRE><H3><FONT COLOR="#000077">Removing a Stored Procedure</FONT></H3><P>By now, you can probably make an educated guess as to how to get rid of a storedprocedure. If you guessed the <TT>DROP</TT> command, you are absolutely correct.The following statement removes a stored procedure from a database:</P><H5>SYNTAX:</H5><PRE><FONT COLOR="#0066FF">drop procedure procedure_name</FONT></PRE><P>The <TT>DROP</TT> command is used frequently: Before a stored procedure can bere-created, the old procedure with its name must be dropped. From personal experience,there are few instances in which a procedure is created and then never modified.Many times, in fact, errors occur somewhere within the statements that make up theprocedure. We recommend that you create your stored procedures using an SQL scriptfile containing all your statements. You can run this script file through your databaseserver to execute your desired statements and rebuild your procedures. This techniqueenables you to use common text editors such as vi or Windows Notepad to create andsave your SQL scripts. When running these scripts, however, you need to rememberto always drop the procedure, table, and so forth from the database before creatinga new one. If you forget the <TT>DROP</TT> command, errors will result.</P><P>The following syntax is often used in SQL Server script files before creatinga database object:</P><H5>SYNTAX:</H5><PRE><FONT COLOR="#0066FF">if exists (select * from sysobjects where name = "procedure_name")begin drop procedure procedure_nameendgocreate procedure procedure_nameas...</FONT></PRE><P>These commands check the <TT>SYSOBJECTS</TT> table (where database object informationis stored in SQL Server) to see whether the object exists. If it does, it is droppedbefore the new one is created. Creating script files and following the precedingsteps saves you a large amount of time (and many potential errors) in the long run.<H3><FONT COLOR="#000077">Nesting Stored Procedures</FONT></H3><P>Stored procedure calls can also be nested for increased programming modularity.A stored procedure can call another stored procedure, which can then call anotherstored procedure, and so on. Nesting stored procedures is an excellent idea for severalreasons:<UL> <LI>Nesting stored procedures reduces your most complex queries to a functional level. (Instead of executing 12 queries in a row, you could perhaps reduce these 12 queries to three stored procedure calls, depending on the situation.) <P> <LI>Nesting stored procedures improves performance. The query optimizer optimizes smaller, more concise groups of queries more effectively than one large group of statements.</UL><P>When nesting stored procedures, any variables or database objects created in onestored procedure are visible to all the stored procedures it calls. Any local variablesor temporary objects (such as temporary tables) are deleted at the end of the storedprocedure that created these elements.</P><P>When preparing large SQL script files, you might run into table or database objectreferencing problems. You must create the nested stored procedures before you cancall them. However, the calling procedure may create temporary tables or cursorsthat are then used in the called stored procedures. These called stored proceduresare unaware of these temporary tables or cursors, which are created later in thescript file. The easiest way around this problem is to create the temporary objectsbefore all the stored procedures are created; then drop the temporary items (in thescript file) before they are created again in the stored procedure. Are you confusedyet? Example 13.8 should help you understand this process.<H4><FONT COLOR="#000077">Example 13.8</FONT></H4><H5><FONT COLOR="#000000">INPUT:</FONT><FONT COLOR="#000077"></FONT></H5><PRE><FONT COLOR="#0066FF">1> <B>create procedure Example13_8b</B>2> <B>as</B>3> <B> select * from #temp_table</B>4> <B>go</B>1> <B>create procedure Example13_8a</B>2> <B>as</B>3> <B>create #temp_table (</B>4> <B> data char(20),</B>5> <B> numbers int)</B>6> <B> execute Example13_8b</B>7> <B> drop table #temp_table</B>8> <B>go</B></FONT></PRE><H5>ANALYSIS:</H5><P>As you can see, procedure <TT>Example13_8b</TT> uses the <TT>#temp_table</TT>.However, the <TT>#temp_table</TT> is not created until later (in procedure <TT>Example13_8a</TT>).This results in a procedure creation error. In fact, because <TT>Example13_8b</TT>was not created (owing to the missing table <TT>#temp_table</TT>), procedure <TT>Example13_8a</TT>is not created either (because <TT>Example13_8b</TT> was not created).</P><P>The following code fixes this problem by creating the <TT>#temp_table</TT> beforethe first procedure is created. <TT>#temp_table</TT> is then dropped before the creationof the second procedure:</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF">1> <B>create #temp_table (</B>2> <B>data char(20),</B>3> <B>numbers int)</B>4><B> go</B>1> <B>create procedure Example13_8b</B>2><B> as</B>3> <B> select * from #temp_table</B>4> <B>go</B>1> <B>drop table #temp_table</B>2> <B>go</B>1> <B>create procedure Example13_8a</B>2> <B>as</B>3> <B> create #temp_table (</B>4> <B> data char(20),</B>5> <B> numbers int)</B>6> <B> execute Example13_8b</B>7> <B> drop table #temp_table</B>8> <B>go</B></FONT></PRE><H2><FONT COLOR="#000077">Designing and Using Triggers</FONT></H2><P>A trigger is essentially a special type of stored procedure that can be executedin response to one of three conditions:<UL> <LI>An <TT>UPDATE</TT> <P> <LI>An <TT>INSERT</TT> <P> <LI>A <TT>DELETE</TT></UL><P>The Transact-SQL syntax to create a trigger looks like this:</P><H5>SYNTAX:</H5><PRE><FONT COLOR="#0066FF">create trigger trigger_name on table_name for {insert, update, delete} as SQL_Statements</FONT></PRE><P>The Oracle7 SQL syntax used to create a trigger follows.</P><H5>SYNTAX:</H5><PRE><FONT COLOR="#0066FF">CREATE [OR REPLACE] TRIGGER [schema.]trigger_name {BEFORE | AFTER} {DELETE | INSERT | UPDATE [OF column[, column]...]}[OR {DELETE | INSERT | UPDATE [OF column [, column] ...]}]... ON [schema.]table[[REFERENCING { OLD [AS] old [NEW [AS] new] | NEW [AS] new [OLD [AS] old]}]FOR EACH ROW[WHEN (condition)] ]pl/sql statements...</FONT></PRE><P>Triggers are most useful to enforce referential integrity, as mentioned on Day9, "Creating and Maintaining Tables," when you learned how to create tables.Referential integrity enforces rules used to ensure that data remains valid acrossmultiple tables. Suppose a user entered the following command:</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF">1> <B>insert RECORDINGS values (12, "The Cross of Changes", 3, 1994)</B>2> <B>go</B></FONT></PRE><H5>ANALYSIS:</H5><P>This perfectly valid SQL statement inserts a new record in the <TT>RECORDINGS</TT>table. However, a quick check of the <TT>ARTISTS</TT> table shows that there is no<TT>Artist_ID = 12</TT>. A user with <TT>INSERT</TT> privileges in the <TT>RECORDINGS</TT>table can completely destroy your referential integrity.<BLOCKQUOTE> <P><HR><FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>Although many database systems can enforce referential integrity through the use of constraints in the <TT>CREATE TABLE</TT> statement, triggers provide a great deal more flexibility. Constraints return system error messages to the user, and (as you probably know by now) these error messages are not always helpful. On the other hand, triggers can print error messages, call other stored procedures, or try to rectify a problem if necessary. <HR></BLOCKQUOTE><H3><FONT COLOR="#000077">Triggers and Transactions</FONT></H3><P>The actions executed within a trigger are implicitly executed as part of a transaction.Here's the broad sequence of events:<DL> <DD><B>1.</B> A <TT>BEGIN TRANSACTION</TT> statement is implicitly issued (for tables with triggers). <P><B>2. </B>The insert, update, or delete operation occurs.</P> <P><B>3.</B> The trigger is called and its statements are executed.</P> <P><B>4.</B> The trigger either rolls back the transaction or the transaction is implicitly committed.</DL><H4><FONT COLOR="#000077">Example 13.9</FONT></H4><P>This example illustrates the solution to the <TT>RECORDINGS</TT> table updateproblem mentioned earlier.</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF">1> <B>create trigger check_artists</B>2> <B>on RECORDINGS</B>3> <B>for insert, update as</B>4> <B>if not exists (select * from ARTISTS, RECORDINGS</B>5> <B>where ARTISTS.artist_id = RECORDINGS.artist_id)</B>6> <B>begin</B>7> <B> print "Illegal Artist_ID!"</B>8> <B> rollback transaction</B>9> <B> end</B>10> <B>go</B></FONT></PRE><H5>ANALYSIS:</H5><P>A similar problem could exist for deletes from the <TT>RECORDINGS</TT> table.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -