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

Beginning SQL Server 2005 for Developers From Novice to Professional phần 8 potx

53 348 0

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 53
Dung lượng 1,71 MB

Nội dung

348 CHAPTER 10 ■ STORED PROCEDURES EXECUTE @RetVal=CustomerDetails.apf_CustBalances 1, @ClearedBalance OUTPUT, @UnclearedBalance OUTPUT SELECT @RetVal AS ReturnValue, @ClearedBalance AS ClearedBalance, @UnclearedBalance AS UnclearedBalance GO 9. Now that the template has been altered with the changes we need, execute the template by pressing Ctrl+E or F5, or clicking the execute button on the toolbar. This will create the stored procedure and run the examples at the end to demonstrate the procedure. Of course, we can run this section of code as many times as we want because the whole scenario, from dropping and losing the stored procedure through to re-creating the stored procedure, is all there, ready for us. The stored procedure will pass back its output parameter value to the @ClearedBalance and @UnclearedBalance variables defined within the execution batch and the return value to the @RetVal variable. From there, once the variables are set, the values can be printed out using a SELECT statement. This will produce the output shown in Figure 10-7 in the results pane. Figure 10-7. Results after running the OUTPUT stored procedure We have now built two very basic stored procedures in which we are performing an INSERT and a SELECT. Next we look at control of flow. Controlling the Flow When working on a stored procedure, there will be times when it is necessary to control the flow of information through it. The main control of flow is handled with an IF ELSE statement. You can also control the flow with a WHILE BREAK statement. ■Note The GOTO statement can also control the flow of a stored procedure. You can use this statement to jump to a label within a stored procedure, but this can be a dangerous practice and really is something that should be avoided. For example, it might be better to nest the stored procedure calls. Controlling the flow through a stored procedure will probably be required when a procedure does anything more than working with one T-SQL statement. The flow will depend on your procedure taking an expression and making a true or false decision, and then taking two separate actions depending on the answer from the decision. Dewson_5882C10.fm Page 348 Tuesday, January 3, 2006 1:15 PM CHAPTER 10 ■ STORED PROCEDURES 349 IF ELSE At times a logical expression will need to be evaluated that results in either a true or false answer. This is where an IF ELSE statement is needed. There are many ways of making a true or false condition, and most of the possibilities involve relational operators such as <, >, =, and NOT; however, these can be combined with string functions, other mathematical equations, or comparisons between values in local variables, or even system-wide variables. It is also possible to place a SELECT statement within an IF ELSE block, as long as a single value is returned. A basic IF ELSE would perhaps look like the following: IF A=B Statement when True ELSE Statement when False IF ELSE statements can also be nested and would look like the following; this example also shows you how to include a SELECT statement within an IF decision. IF A=B IF (SELECT ClearedBalance FROM Customers WHERE CustomerId = 1) > $20000 Statement2 when True ELSE Statement2 when False ELSE Statement when False As you can see, there is only one statement within each of the IF ELSE blocks. If you wish to have more than one line of executable code after the IF or the ELSE, you must include another control-of-flow statement, the BEGIN END block. Before we can try this out, let’s take a look at how to code for multiple statements within an IF ELSE block. BEGIN END If you wish to execute more than one statement in the IF or ELSE code block, you need to batch the statements up. To batch statements together within an IF ELSE, you must surround them with a BEGIN END block. If you try to have more than one statement after the IF, the second and subsequent statements will run no matter what the setting of the IF statement is. So if you have DECLARE @VarTest SET @VarTest = 2 IF @VarTest=1 SELECT 1 SELECT 2 then the SELECT 2 statement would run no matter what value you have for @VarTest. If you only want SELECT 2 to run when @VarTest is 1, then you would code the example, thus placing the code you want to run within the BEGIN END block. Dewson_5882C10.fm Page 349 Tuesday, January 3, 2006 1:15 PM 350 CHAPTER 10 ■ STORED PROCEDURES DECLARE @VarTest SET @VarTest = 2 IF @VarTest=1 BEGIN SELECT 1 SELECT 2 END If you use an ELSE statement after a second or subsequent statement after an IF that has no BEGIN END block, you would get an error message. Therefore, the only way around this is to use BEGIN END. WHILE BREAK Statement The WHILE BREAK statement is a method of looping around the same section of code from zero to multiple times based on the answer from a Boolean test condition, or until explicitly informed to exit via the keyword BREAK. The syntax for this command is as follows: WHILE Boolean_expression { sql_statement | statement_block } [ BREAK ] { sql_statement | statement_block } [ CONTINUE ] { sql_statement | statement_block } The code defined for the WHILE statement will execute while the Boolean expression returns a value of True. You can have other control-of-flow statements such as an IF ELSE block within your WHILE block. This is where BREAK and CONTINUE could be used if required. You may wish to test a condition and, if it returns a particular result, BREAK the loop and exit the WHILE block. The other option that can be used is the CONTINUE statement. This moves processing straight to the WHILE statement again and will stop any execution of code that is defined after it. The best way to illustrate these concepts is to show a simple example of these three options in action. Try It Out: WHILE BREAK 1. The first option demonstrates how to build a WHILE loop and then test the value of a variable. If the test returns True, we will break out of the loop; if it returns False, we will continue processing. Within the example there are two SELECT statements before and after an IF ELSE statement. In this example, the first SELECT will show the values of the variables, but the IF test will either stop the loop via BREAK or will move the code back to the WHILE statement via the CONTINUE statement. Either of these actions will mean that the second SELECT will not execute. Dewson_5882C10.fm Page 350 Tuesday, January 3, 2006 1:15 PM CHAPTER 10 ■ STORED PROCEDURES 351 DECLARE @LoopCount int, @TestCount int SET @LoopCount = 0 SET @TestCount = 0 WHILE @LoopCount < 20 BEGIN SET @LoopCount = @LoopCount + 1 SET @TestCount = @TestCount + 1 SELECT @LoopCount, @TestCount IF @TestCount > 10 BREAK ELSE CONTINUE SELECT @LoopCount, @TestCount END 2. When the code is executed, we don’t actually make it around the 20 loops due to the value of @TestCount causing the break. The output is shown in Figure 10-8. Figure 10-8. WHILE with BREAK and CONTINUE 3. If we change the code to remove the ELSE CONTINUE statement, the second SELECT statement will be executed. The two rows changed have been highlighted. We are not going to execute the two lines because they have been commented out by prefixing the code with two hyphens, Dewson_5882C10.fm Page 351 Tuesday, January 3, 2006 1:15 PM 352 CHAPTER 10 ■ STORED PROCEDURES DECLARE @LoopCount int, @TestCount int SET @LoopCount = 0 SET @TestCount = 0 WHILE @LoopCount < 20 BEGIN SET @LoopCount = @LoopCount + 1 SET @TestCount = @TestCount + 1 SELECT @LoopCount, @TestCount IF @TestCount > 10 BREAK ELSE CONTINUE SELECT @LoopCount, @TestCount END A snapshot of some of the output from this is shown in Figure 10-9. Figure 10-9. WHILE with BREAK only The third statement we’ll look at in this section is the CASE statement. While not a control-of-flow statement for your stored procedure, it can control the output displayed based on decisions. CASE Statement When a query has more than a plain true or false answer—in other words, when there are several potential answers—you should use the CASE statement. A CASE statement forms a decision-making process within a SELECT or UPDATE statement. It is possible to set a value for a column within a recordset based on a CASE statement and the resultant value. Obviously, with this knowledge, a CASE statement cannot form part of a DELETE statement. Dewson_5882C10.fm Page 352 Tuesday, January 3, 2006 1:15 PM CHAPTER 10 ■ STORED PROCEDURES 353 Several parts of a CASE statement can be placed within a stored procedure to control the statement executed depending on each scenario. Two different syntax structures exist for the CASE statement depending on how you want to test a condition or what you want to test. Let’s take a look at all the parts to the first CASE statement syntax: CASE expression WHEN value_matched THEN statement [[WHEN value_matched2 THEN] [Statement2]] [[ELSE] [catch_all_code] END First of all, you need to define the expression that is to be tested. This could be the value of a variable, or a column value from within the T-SQL statement, or any valid expression within SQL Server. This expression is then used to determine the values to be matched in each WHEN statement. You can have as many WHEN statements as you wish within the CASE condition, and you do not need to cover every condition or possible value that could be placed within the condition. Once a condition is matched, then only the statements within the appropriate WHEN block will be executed. Of course, only the WHEN conditions that are defined will be tested. However, you can cover yourself for any value within the expression that has not been defined within a WHEN statement by using an ELSE condition. This is used as a catchall statement. Any value not matched would drop into the ELSE condition, and from there you could deal with any scenario that you desire. The second syntax is where you don’t define the expression prior to testing it and each WHEN statement performs any test expression you desire. CASE WHEN Boolean_expression THEN result_expression [ n ] [ ELSE else_result_expression ] END As just indicated, CASE statements form part of a SELECT, UPDATE, or INSERT statement, therefore possibly working on multiple rows of data. As each row is retrieved from the table, the CASE statement kicks in, and instead of the column value being returned, it is the value from the decision-making process that is inserted instead. This happens after the data has been retrieved and just before the rows returned are displayed in the results pane. The actual value is returned initially from the table and is then validated through the CASE statement; once this is done, the value is discarded if no longer required. Now that you are familiar with CASE statements, we can look at them in action. Dewson_5882C10.fm Page 353 Tuesday, January 3, 2006 1:15 PM 354 CHAPTER 10 ■ STORED PROCEDURES Try It Out: Using the CASE Statement 1. Our first example will demonstrate the first CASE syntax, where we will take a column and test for a specific value. The results of this test will determine which action will be performed. We will prepopulate the TransactionDetails.TransactionTypes table first so that you can see how populating this table and the CASE statement work. INSERT INTO TransactionDetails.TransactionTypes (TransactionDescription,CreditType,AffectCashBalance) VALUES ('Deposit',1,1) INSERT INTO TransactionDetails.TransactionTypes (TransactionDescription,CreditType,AffectCashBalance) VALUES ('Withdrawal',0,1) INSERT INTO TransactionDetails.TransactionTypes (TransactionDescription,CreditType,AffectCashBalance) VALUES ('BoughtShares',1,0) SELECT TransactionDescription, CASE CreditType WHEN 0 THEN 'Debiting the account' WHEN 1 THEN 'Crediting the account' END FROM TransactionDetails.TransactionTypes 2. Execute this code, and you should see the output shown in Figure 10-10. Figure 10-10. Simple CASE statement output 3. A customer can have a positive or negative ClearedBalance. The CASE statement that follows will demonstrate this by showing either In Credit or Overdrawn. In this case, we want to use the second CASE syntax. We cannot use the first syntax, as we have an operator included within the test and we are not looking for a specific value. The code is defined as follows: SELECT CustomerId, CASE WHEN ClearedBalance < 0 THEN 'OverDrawn' WHEN ClearedBalance > 0 THEN ' In Credit' ELSE 'Flat' END, ClearedBalance FROM CustomerDetails.Customers Dewson_5882C10.fm Page 354 Tuesday, January 3, 2006 1:15 PM CHAPTER 10 ■ STORED PROCEDURES 355 4. Execute the code. This produces output similar to what you see in Figure 10-11. Figure 10-11. Searched CASE statement output Bringing It All Together Now that you have seen the control-of-flow statements, we can bring all of this together in our most complex set of code so far. The aim of this stored procedure is to take a “from” and “to” date, which can be over any period, and return the movement of a particular customer’s trans- actions that have affected the cash balance. This mimics your bank statement when it says whether you have spent more than you have deposited. This example includes one topic that is not covered until the next chapter: joining data from more than one table together. For the moment, just accept that when you see the state- ment JOIN, all it is doing is taking data from another table and allowing you to work with it. So let’s build that example. Try It Out: Bringing It All Together ■Note In this example, we are performing a loop around rows of data within a table. This example demon- strates some of the functionality just covered with decisions and control of flow. SQL Server works best with sets of data, rather than a row at a time. However, there will be times that row-by-row processing like this happens. In SQL Server 2005, you have the option to write .NET-based stored procedures, and this example would certainly be considered a candidate for this treatment. Our example works with one row at a time, where you would have a running total of a customer’s balance so that you can calculate interest to charge or to pay. 1. First of all, let’s create our stored procedure. We have our CREATE PROCEDURE statement that we enter in an empty Query Editor pane, and then we name the procedure with our three input parameters. CREATE PROCEDURE CustomerDetails.apf_CustMovement @CustId bigint, @FromDate datetime, @ToDate datetime AS BEGIN Dewson_5882C10.fm Page 355 Tuesday, January 3, 2006 1:15 PM 356 CHAPTER 10 ■ STORED PROCEDURES 2. We then need three internal variables. This stored procedure will return one row of transactions at a time while we are still in the date range. As we move through each row, we need to keep a running balance of the amounts for each transaction. We know that the data in the TransactionDetails. Transactions table has an ascending TransactionId as each transaction is entered, so the next trans- action from the one returned must have a higher value. Therefore, we can store the transaction ID in a variable called @LastTran and use that in our filtering. Once the variables are declared, we then set them to an initial value. We use @StillCalc as a test for the WHILE loop. This could be any variable as we are using the CONTINUE and BREAK statements to determine when we should exit the loop. DECLARE @RunningBal money, @StillCalc Bit, @LastTran bigint SELECT @StillCalc = 1, @LastTran = 0, @RunningBal = 0 3. We tell the loop to continue until we get no rows back from our SELECT statement. Once we get no rows, we know that there are no more transactions in the date range. WHILE @StillCalc = 1 BEGIN 4. Our more complex SELECT statement will return one row where the TransactionId is greater than the previous TransactionId returned; the transaction would affect the customer’s cash balance; and the transaction is between the two dates passed in. If there is a transaction, then we add or subtract the value from the @RunningBal variable. We use a CASE statement to decide whether we need to make the value a negative value for adding to the variable. SELECT TOP 1 @RunningBal = @RunningBal + CASE WHEN tt.CreditType = 1 THEN t.Amount ELSE t.Amount * -1 END, @LastTran = t.TransactionId FROM CustomerDetails.Customers c JOIN TransactionDetails.Transactions t ON t.CustomerId = c.CustomerId JOIN TransactionDetails.TransactionTypes tt ON tt.TransactionTypeId = t.TransactionType WHERE t.TransactionId > @LastTran AND tt.AffectCashBalance = 1 AND DateEntered BETWEEN @FromDate AND @ToDate ORDER BY DateEntered 5. If we get a row returned, then we continue the loop. Once we get no rows returned, we know that there are no further transactions in the date range. IF @@ROWCOUNT > 0 Perform some interest calculation here CONTINUE ELSE BREAK END SELECT @RunningBal AS 'End Balance' END GO Dewson_5882C10.fm Page 356 Tuesday, January 3, 2006 1:15 PM CHAPTER 10 ■ STORED PROCEDURES 357 6. We can now create the stored procedure and test our results. The example is going to check whether Vic McGlynn, customer ID 1, has had a positive or negative movement on her cash balance in the month of August 2005. The code to find this out follows. First of all, we insert some TransactionDetails.Transactions records to test it out. We also prefix the stored procedure with an EXEC(UTE) statement, as this is part of a batch of statements. INSERT INTO TransactionDetails.Transactions (CustomerId,TransactionType,DateEntered,Amount,RelatedProductId) VALUES (1,1,'1 Aug 2005',100.00,1) INSERT INTO TransactionDetails.Transactions (CustomerId,TransactionType,DateEntered,Amount,RelatedProductId) VALUES (1,1,'3 Aug 2005',75.67,1) INSERT INTO TransactionDetails.Transactions (CustomerId,TransactionType,DateEntered,Amount,RelatedProductId) VALUES (1,2,'5 Aug 2005',35.20,1) INSERT INTO TransactionDetails.Transactions (CustomerId,TransactionType,DateEntered,Amount,RelatedProductId) VALUES (1,2,'6 Aug 2005',20.00,1) EXEC CustomerDetails.apf_CustMovement 1,'1 Aug 2005','31 Aug 2005' 7. Execute the preceding code, which should return a value that we expect, as shown in Figure 10-12. Figure 10-12. Complex stored procedure output Summary In this chapter, you have met stored procedures, which are collections of T-SQL statements compiled and ready to be executed by SQL Server. You have learned the advantages of a stored procedure over an ad hoc query, encountered the basic CREATE PROCEDURE syntax, and created some simple stored procedures. The basics of building a stored procedure are very simple and straightforward. Therefore, building a stored procedure within Query Editor may be as attractive as using a template. As stored procedures are sets of T-SQL statements combined together, you will tend to find that you build up your query, and then at the end surround it with a CREATE PROCEDURE statement. Probably the largest area of code creation outside of data manipulation and searching will be through control-of-flow statements. We look at other areas, such as error handling, in Chapter 11, which aims to advance your T-SQL knowledge. Dewson_5882C10.fm Page 357 Tuesday, January 3, 2006 1:15 PM [...]... only want to exist for a short period Quite a great deal to cover, but this chapter and the next will be the stepping stones that move you from a novice to a professional developer This chapter will therefore look at the following: • Joining two or more tables to see more informational results • Having a method of storing information on a temporary basis via variables • How to hold rows of information...Dewson_ 588 2C10.fm Page 3 58 Tuesday, January 3, 2006 1:15 PM Dewson_ 588 2C11.fm Page 359 Tuesday, January 10, 2006 3:03 PM CHAPTER 11 ■■■ T -SQL Essentials N ow that you know how to build and work with SQL Server objects, and insert, update, and delete data as well as retrieve it, we can now move on to more of the T -SQL essentials required to complete your programming knowledge... defining the INTO table to reside within the tempdb However, it will still exist within tempdb until it is either dropped or SQL Server is stopped and restarted Slightly better, but not perfect for when you just want to build an interim table between two sets of T -SQL statements Requiring a temporary table could happen for a number of reasons Building a single T -SQL statement returning information from a number... shares, you may be thinking you need to provide a SELECT AVG() for each share This section will demonstrate that this is not the case By using GROUP BY, you instruct SQL Server to group the data to return and provide a summary value for each grouping of data To clarify, as you will see in the Dewson_ 588 2C11.fm Page 373 Tuesday, January 10, 2006 3:03 PM CHAPTER 11 ■ T -SQL ESSENTIALS upcoming examples,... every column within the table, we don’t need to list the columns in the INSERT INTO table part of the query Then we use the results from a SELECT statement to populate many rows in one set of T -SQL You can execute the code now if you want, but when we get to the third part in a moment, run the SELECT * from the same Query Editor window INSERT SELECT FROM JOIN INTO #SharesTmp s.ShareDesc,sp.Price,sp.PriceDate... temporary tables First, create the temporary table For the moment, just enter the code, don’t execute it 367 Dewson_ 588 2C11.fm Page 3 68 Tuesday, January 10, 2006 3:03 PM 3 68 CHAPTER 11 ■ T -SQL ESSENTIALS CREATE TABLE #SharesTmp (ShareDesc varchar(50), Price numeric( 18, 5), PriceDate datetime) 2 Next we want to populate the temporary table with information from the ShareDetails.Shares and the ShareDetails.SharePrices... table, it is then available to be used by any user and any connection, just like a permanent table A global temporary table will only then be “deleted” when all connections to it have been closed In Chapter 8, when looking at the SELECT statement, you were introduced to SELECT INTO, which allows a permanent table to be built from data from either another table or tables, or from a list of variables We... variable can be declared at any time within a set of T -SQL, whether it is ad hoc or a stored procedure or trigger However, a variable has a finite lifetime To inform SQL Server you wish to use a variable, use the following syntax: DECLARE @variable_name datatype, @variable_name2 datatype All variables have to be preceded with an @ sign, and as you can see from the syntax, more than one variable can be declared,... returned from a particular set of filtering criteria Quite often this will be used to cross-check the number of rows from a query in SQL Server with the number of rows an application is showing to a user The syntax is COUNT(*) or COUNT_BIG(*) There are no columns defined, as it is rows that are being counted 369 Dewson_ 588 2C11.fm Page 370 Tuesday, January 10, 2006 3:03 PM 370 CHAPTER 11 ■ T -SQL ESSENTIALS... optimized for returning the data quickly Splitting the query into two may make the code easier to maintain and perform better To give an example, as our customers “age,” they will have more and more transactions against their account IDs It may be that when working out any interest to accrue, the query is taking a long time to run, as there are more and more transactions It might be better to create . which aims to advance your T -SQL knowledge. Dewson_ 588 2C10.fm Page 357 Tuesday, January 3, 2006 1:15 PM Dewson_ 588 2C10.fm Page 3 58 Tuesday, January 3, 2006 1:15 PM 359 ■ ■ ■ CHAPTER 11 T -SQL Essentials Now. exist for a short period. Quite a great deal to cover, but this chapter and the next will be the stepping stones that move you from a novice to a professional developer. This chapter will therefore. scenario, from dropping and losing the stored procedure through to re-creating the stored procedure, is all there, ready for us. The stored procedure will pass back its output parameter value to the

Ngày đăng: 14/08/2014, 10:22

TỪ KHÓA LIÊN QUAN