Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 75 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
75
Dung lượng
798,83 KB
Nội dung
After all the parameters have been added to the Parameters collection, you call the ExecuteStoredProcedure method in the base class to execute the stored procedure and set the results of that call to this function. The CATCH block handles any exceptions that may be thrown and returns the exception to the caller: ‘Execute the stored procedure AddTimeSheet = ExecuteStoredProcedure() Catch ExceptionErr As Exception Throw New System.Exception(ExceptionErr.Message, _ ExceptionErr.InnerException) End Try End Function The WBLTimeSheets class is added next to the business logic component and implements the IDisposable interface just as the other classes in this component do. You add a private variable to represent the corresponding class in the data access component, create the constructor, and modify the Dispose procedure. Refer to the Try It Out exercise to review that. You’ll be adding functions to this class in the next chapter when you start writing more complex SELECT statements in your stored procedures. Summary This chapter has taken a close look at data validation on all fronts. You did a little data validation in the client application when you validated that the ranking for a role was a numeric value. This demon- strated how you could perform data validation in the client application. You also did some data valida- tion in the usp_InsertRole stored procedure, which demonstrated how to perform data validation in a stored procedure, which was more efficient than executing a separate stored procedure to determine if a ranking already existed before calling the stored procedure to insert data. The bulk of the data validation, however, was performed where it should be, in the business logic component. Here you not only validate data to ensure that it conforms to the business rules, but you also massage the data to remove blank spaces from it and set empty strings to NULL values. This increases the efficiency of your data storage in the database because there’s no need to store blank spaces when they are not needed. You also took a more detailed look at insert stored procedures, but you have only scratched the surface of the real power of stored procedures. You learned that you could perform conditional processing and error handling, and execute transactions in your stored procedures. This knowledge will serve you well in the future and I cannot stress enough the importance of error handling in your VB 2005 code as well as in your stored procedures. To summarize, you should know: ❑ How to remove unwanted leading and trailing spaces from your data ❑ How to use regular expressions to validate data ❑ How to declare and use local variables in your stored procedures 363 Inserting Data 14_58894x ch11.qxd 10/13/05 5:56 PM Page 363 ❑ How to perform error handling in your stored procedures ❑ How to use conditional logic and transactions in your stored procedures ❑ How to use cursors in your stored procedures In Chapter 12, you will write a lot of SELECT stored procedures to select data, and implement code to display the Login and TimeSheet forms. Exercises Exercise 1 Using Exercise 1 from the last chapter as a base, modify the ListBox1_Click procedure to validate the ProjectDescription column in the Project table before setting the Text property of the txtProjectDescription text box. If the column contains an empty string then set the Text property of the txtProjectDescription text box to “No Data Available.” Run your TimeTracker application and insert a project with no description. Exercise 2 Modify your usp_InsertRole stored procedure to include the appropriate error handling code for your database. 364 Chapter 11 14_58894x ch11.qxd 10/13/05 5:56 PM Page 364 12 Selecting Data Up until this point, the SELECT stored procedures that you have written have been simple and have selected data from a single table. The functionality that you implement in your Time Tracker application in this chapter requires more complex SELECT stored procedures. Sometimes, selecting data from a single table does not produce the desired results. Often, you want to calculate or summarize the results of the data in a column. Your application’s business requirements may also dictate that you select data from multiple columns and have it returned as a single column in your result set. It may also be desirable to select data from multiple rows in a table and have it returned as a single row of data in the result set. Other business requirements of your application may dictate that you select data from multiple tables in a single stored procedure to process the data in your application efficiently. These are the situations that you will be examining in this chapter as you learn how to write more complex SELECT stored procedures. The topics covered in this chapter lay the groundwork for writing more effective stored procedures and will serve you well in the future. In this chapter, you: ❑ Learn about column aliases ❑ Learn about table aliases ❑ Learn about join fundamentals ❑ Learn how to use like comparisons when selecting data ❑ Learn how to select data from multiple rows and return the results as a single row in the result set Column Aliases A column alias is an alternate name for a column of data or the name for an expression in your SELECT statement. You can use column aliases to shorten the column name in the result set or to assign a name to an unnamed expression in the result set. You can also use a column alias to provide a more descriptive name for a column in a result set. 15_58894x ch12.qxd 10/13/05 5:56 PM Page 365 The following SQL SELECT statement selects the minimum and maximum values from the SequenceNumber column in the Projects table: SELECT MIN(SequenceNumber), MAX(SequenceNumber) FROM Projects When the results are returned in a DataSet in your VB 2005 program, you see some unexpected column names. In SQL Server, the column names are returned as Column1 and Column2, whereas Oracle returns the column names as MIN(SEQUENCENUMBER) and MAX(SEQUENCENUMBER). Such results can be confusing. Using a column alias for the expressions in your query causes the results to be returned with the column name that you specify. Now consider the following modifications to the previous query. Here you specify the AS keyword followed by the column alias that should be assigned to your expression. The use of the AS keyword is optional when specifying a column alias but it helps to make your SQL statements more readable. SELECT MIN(SequenceNumber) AS MinSeq, MAX(SequenceNumber) AS MaxSeq FROM Projects When this query is executed, the column names are returned in the DataSet as MinSeq and MaxSeq by both SQL Server and Oracle. As expected, Oracle returns the column names in uppercase characters but they can be accessed in the DataSet using mixed case. Assigning a column alias to an expression is not the limit of column aliases. You can also assign a column alias to an existing column name to shorten it in the query results, as shown in the following example: SELECT SequenceNumber AS SeqNum FROM Projects In this case, you are selecting the data from the SequenceNumber column in the Projects table. However, the column name in the results will be displayed as SeqNum rather than the original column name of SequenceNumber. Because you assigned a column alias to the column, you shortened the column name in your result set, reducing the amount of typing needed in your programs. This can also work in reverse by allowing you to provide a more descriptive column name in your results set for a column in the database that is somewhat cryptic. Table Aliases A table alias is similar to a column alias in that it allows you to assign a new name to a table in your query. You may want to do this for several reasons but the most common reason is that it may be necessary to use the same table twice in a query. That is, you may want to join the same table to itself to produce the required results. You’ll see an example of this shortly. A table alias works the same in SQL Server and Oracle. You specify the table name to which you assign an alias and follow that up with the table alias. Oracle does not support the AS keyword when assigning a table alias; however, SQL Server does. I provide the examples in a format that works with both databases. 366 Chapter 12 15_58894x ch12.qxd 10/13/05 5:56 PM Page 366 In the following example, you are selecting two columns from the same table. However, they are treated as different tables in the query because you joined the tables and assigned a table alias to the second table. The FROM clause specifies the Users table as the primary table to select data from. The INNER JOIN statement joins the Users table to the Users table as the Managers table because you specified a table alias of Managers. The condition of the join is specified following the ON keyword. Here you specify that the Managers table is joined such that the ManagerID column in the Users table is equal to the UserID in the Managers table. Remember that the ManagerID column in the Users table is a circular reference to the UserID of the manager in the Users table. You see more on joins shortly. SELECT Users.LoginName, Managers.LoginName AS ManagerLogin FROM Users INNER JOIN Users Managers ON Users.ManagerID = Managers.UserID When you specify a table alias for a table, all references to columns in that table are made with the table alias that you specify. It is not always necessary to prefix the column names in the SELECT list with the table name, but it is required in this example to prevent an ambiguous column name error, as you are selecting the LoginName column from both tables. Notice also that a column alias has been assigned to the LoginName column from the Managers table so that it is obvious what this column represents. Concatenation Sometimes you want to concatenate the results of two or more columns into a single column. For example, you may want to display a person’s first and last name as a single string in your program. You could select the first name and last name columns from your table and join the two columns in your program. However, it is more efficient to have the database do this for you and simply return the results of the two columns as one column in your result set. Concatenation is performed the same way in SQL Server and Oracle, but each database uses a different concatenation character. SQL Server uses a single plus ( +) sign to concatenate two columns. Oracle uses two consecutive pipe characters ( ||), as examples in this section demonstrate. This first example demonstrates how concatenation is performed in SQL Server. You can see that you are concatenating the FirstName and LastName columns from the Users table. You specify the FirstName column in the SELECT statement followed by the concatenation character of a plus sign. Because you want a space to appear between the first and last names, you include this space between single quote marks as a string literal and then use another concatenation character followed by the LastName column. Concatenated columns will be displayed without a column name so you use a column alias to assign a name to the concatenated results. SELECT FirstName + ‘ ‘ + LastName AS UserName FROM Users This next example demonstrates how concatenation is performed in Oracle. As you can see, the only difference is in the use of the concatenation character, which is two consecutive pipe characters: SELECT FirstName || ‘ ‘ || LastName AS UserName FROM Users 367 Selecting Data 15_58894x ch12.qxd 10/13/05 5:56 PM Page 367 Joins A join is a logical relationship between two tables that enables you to select data from both tables. Joins are based on a logical relationship between the tables, such as the primary and foreign keys. This enables two tables to be joined on the common value of the primary key in one table and a foreign key in another table. Joins do not have to join tables using a primary and foreign key relationship. Any column in the tables being joined that contain the same values can be used. For example, you could join two tables on a column that contains a date value. However, using the primary and foreign key is the typical choice for joins as they provide the logical relationship between the tables. The primary and foreign key columns are also indexed, which greatly improves the efficiency of the join. Several different types of joins are available in both SQL Server and Oracle. As space is limited, I don’t cover each different join in both databases. What I cover are the types of joins that you use in your stored procedures for the Time Tracker application. Inner or natural join The default join in SQL Server is referred to as an INNER JOIN, whereas the default join in Oracle is referred to as a natural JOIN. The join in both databases operates the same and the SQL statements for the join are the same in both databases. This type of join displays only the rows of data that match the primary and foreign keys in both tables. Because an INNER JOIN or natural JOIN is the default join type for both databases, you can specify this type of join in several ways in both databases. In the following example, the Roles table is joined to the Users table based on the primary and foreign keys specified in the WHERE clause. The join in this SELECT statement is not very obvious at first glance because you do not see the JOIN clause. SELECT LoginName, RoleName FROM Users, Roles WHERE Users.RoleID = Roles.RoleID In this next example, the JOIN clause is specified and the condition of the join is made a part of the JOIN clause. A join in this SQL statement is more obvious with the inclusion of the JOIN clause. SELECT LoginName, RoleName FROM Users JOIN Roles ON Users.RoleID = Roles.RoleID In this final example, the full JOIN clause is specified as INNER JOIN, which leaves no doubt as to what type of join is being used. Again, the condition of the join is specified in the JOIN clause. SELECT LoginName, RoleName FROM Users INNER JOIN Roles ON Users.RoleID = Roles.RoleID All of the previous examples produce the same results: They select the data from the Users table and all matching rows from the Roles table based on the RoleID in both tables. 368 Chapter 12 15_58894x ch12.qxd 10/13/05 5:56 PM Page 368 LEFT OUTER JOIN A LEFT OUTER JOIN returns all rows of data from the left table even when there are no matching rows of data in the joined table. This ensures that all rows of data are returned from the primary table and any data that does not match in the joined table is returned as a NULL value. The LEFT OUTER JOIN has the same syntax and works the same way in both SQL Server and Oracle. Consider the following example, which returns the login name of each user in the Users table as well as the login name of the manager assigned to that user. A NULL value is returned where a manager has not been assigned to a user. This ensures that you get a complete list of all users in the Users table even when no manager has been assigned to that user. SELECT Users.LoginName, Managers.LoginName AS ManagerLogin FROM Users LEFT OUTER JOIN Users Managers ON Users.ManagerID = Managers.UserID To give you an idea of the results that you can expect from an LEFT OUTER JOIN, the results of this query are listed here. As you can see, a NULL value is returned where no manager has been assigned to a user and all users in the Users table are listed in the results. LoginName ManagerLogin admin NULL zmanager NULL zuser1 zmanager zuser2 NULL In this Try It Out, you implement the functionality in your Time Tracker application to display all users and roles in the Admin form. You also create the stored procedures required to display all roles as well as a single role, and all users as well as a single user. Because users can have a manager assigned, you also need a stored procedure to select all managers so they can be displayed in the combo box on the Users screen in the Admin form. Try It Out Stored Procedures, Joins, Concatenation, and Column Aliases To implement this functionality: 1. Open your Time Tracker application in Visual Studio 2005. 2. View the Server Explorer window and click the Auto Hide icon on the window to keep it visible and then view the Stored Procedures node for your database. 3. Readers using SQL Server should right-click the Stored Procedures and choose Add New Stored Procedure from the context menu. Readers using Oracle should use their favorite Oracle tool such as iSQL *Plus to create the stored procedures. Enter the code for the following stored procedure: SQL Server CREATE PROCEDURE usp_SelectRoles AS SELECT RoleID, RoleName, RoleDescription, Ranking, LastUpdateDate FROM ROLES ORDER BY Ranking, RoleName 369 Selecting Data 15_58894x ch12.qxd 10/13/05 5:56 PM Page 369 Click the Save icon on the toolbar to create the stored procedure. Oracle CREATE OR REPLACE PACKAGE RolesPackage AS TYPE CURSOR_TYPE IS REF CURSOR; PROCEDURE usp_SelectRoles (results_cursor OUT CURSOR_TYPE); END; Click the Execute button to create the package in your database and then enter the following code to create the package body: CREATE OR REPLACE PACKAGE BODY RolesPackage AS PROCEDURE usp_SelectRoles (results_cursor OUT CURSOR_TYPE) AS BEGIN OPEN results_cursor FOR SELECT RoleID, RoleName, RoleDescription, Ranking, LastUpdateDate FROM ROLES ORDER BY Ranking, RoleName; END; END; Click the Execute button to have the package body created in your database. 4. The next stored procedure that you want to create is the usp_SelectRole stored procedure, which selects a single role from the database. SQL Server users should right-click the Stored Procedures node in the Server Explorer and choose Add New Stored Procedure and Oracle users should use their Oracle tool. Enter the following code: SQL Server CREATE PROCEDURE usp_SelectRole ( @RoleID UNIQUEIDENTIFIER ) AS SELECT RoleID, RoleName, RoleDescription, Ranking, LastUpdateDate FROM ROLES WHERE RoleID = @RoleID Click the Save icon on the toolbar to have the stored procedure created in your database. Oracle Enter the following code to create the package: CREATE OR REPLACE PACKAGE RolePackage AS TYPE CURSOR_TYPE IS REF CURSOR; PROCEDURE usp_SelectRole (inRoleID IN CHAR, results_cursor OUT CURSOR_TYPE); END; 370 Chapter 12 15_58894x ch12.qxd 10/13/05 5:56 PM Page 370 Click the Execute button to create the package in your database and then enter the following code to create the package body: CREATE OR REPLACE PACKAGE BODY RolePackage AS PROCEDURE usp_SelectRole (inRoleID IN CHAR, results_cursor OUT CURSOR_TYPE) AS BEGIN OPEN results_cursor FOR SELECT RoleID, RoleName, RoleDescription, Ranking, LastUpdateDate FROM ROLES WHERE RoleID = inRoleID; END; END; Click the Execute button to have the package body created in your database. 5. The next stored procedure to create is the usp_SelectUsers stored procedure, which returns all users in the Users table. SQL Server users should right-click the Stored Procedures node in the Server Explorer and choose Add New Stored Procedure and Oracle users should use their Oracle tool. Enter the following code: SQL Server CREATE PROCEDURE usp_SelectUsers AS SELECT UserID, LoginName, FirstName + ‘ ‘ + LastName AS UserName, Email, Phone, Status FROM Users ORDER BY UserName Click the Save icon on the toolbar to have the stored procedure created in your database. Oracle Enter the following code to create the package: CREATE OR REPLACE PACKAGE UsersPackage AS TYPE CURSOR_TYPE IS REF CURSOR; PROCEDURE usp_SelectUsers (results_cursor OUT CURSOR_TYPE); END; Click the Execute button to create the package in your database and then enter the following code to create the package body: CREATE OR REPLACE PACKAGE BODY UsersPackage AS PROCEDURE usp_SelectUsers (results_cursor OUT CURSOR_TYPE) AS BEGIN OPEN results_cursor FOR SELECT UserID, LoginName, FirstName || ‘ ‘ || LastName AS UserName, Email, Phone, Status FROM Users ORDER BY UserName; END; END; 371 Selecting Data 15_58894x ch12.qxd 10/13/05 5:56 PM Page 371 Click the Execute button to have the package body created in your database. 6. Now you create the usp_SelectUser stored procedure to select the details for a single user from the Users table. SQL Server users should right-click the Stored Procedures node in the Server Explorer and choose Add New Stored Procedure and Oracle users should use their Oracle tool. Enter the following code: SQL Server CREATE PROCEDURE usp_SelectUser ( @UserID UNIQUEIDENTIFIER ) AS SELECT UserID, LoginName, FirstName, LastName, Email, Phone, Status, GroupID, RoleID, ManagerID, LastUpdateDate FROM Users WHERE UserID = @UserID Click the Save icon on the toolbar to have the stored procedure created in your database. Oracle Enter the following code to create the package: CREATE OR REPLACE PACKAGE UserPackage AS TYPE CURSOR_TYPE IS REF CURSOR; PROCEDURE usp_SelectUser (inUserID IN CHAR, results_cursor OUT CURSOR_TYPE); END; Click the Execute button to create the package in your database and then enter the following code to create the package body: CREATE OR REPLACE PACKAGE BODY UserPackage AS PROCEDURE usp_SelectUser (inUserID IN CHAR, results_cursor OUT CURSOR_TYPE) AS BEGIN OPEN results_cursor FOR SELECT UserID, LoginName, FirstName, LastName, Email, Phone, Status, GroupID, RoleID, ManagerID, LastUpdateDate FROM Users WHERE UserID = inUserID; END; END; Click the Execute button to have the package body created in your database. 7. The final stored procedure for this exercise is the usp_SelectManagers stored procedure. This stored procedure returns all managers in the Users table. SQL Server users should right-click the Stored Procedures node in the Server Explorer and choose Add New Stored Procedure and Oracle users should use their Oracle tool. Enter the following code: 372 Chapter 12 15_58894x ch12.qxd 10/13/05 5:56 PM Page 372 [...]... logging in, you display the Admin form or the TimeSheet form Try It Out Implementing Login and TimeSheet Functionality To implement this functionality: 1 2 3 394 Open your Time Tracker application in Visual Studio 2005 View the Server Explorer window and click the Auto Hide icon on the window to keep it visible The first stored procedure to create is usp_SelectTimeSheet, which selects the timesheet for a... = “RolePackage.usp_SelectRole” ‘Initialize the Command object MyBase.InitializeCommand() ‘Add a Parameter to the Parameters collection MyBase.AddParameter(“inRoleID”, OracleClient.OracleType.Char, _ 36, RoleID.ToString) MyBase.AddParameter(“results_cursor”, _ OracleClient.OracleType.Cursor, ParameterDirection.Output) ‘Fill the DataSet MyBase.FillDataSet(GetRole, “Role”) 374 Selecting Data Catch ExceptionErr... DataSet MyBase.SQL = “usp_SelectUser” ‘Initialize the Command object MyBase.InitializeCommand() ‘Add a Parameter to the Parameters collection MyBase.AddParameter(“@UserID”, SqlDbType.UniqueIdentifier, _ 16, UserID) 375 Chapter 12 ‘Fill the DataSet MyBase.FillDataSet(GetUser, “User”) Catch ExceptionErr As Exception Throw New System.Exception(ExceptionErr.Message, _ ExceptionErr.InnerException) End Try End... = “UserPackage.usp_SelectUser” ‘Initialize the Command object MyBase.InitializeCommand() ‘Add a Parameter to the Parameters collection MyBase.AddParameter(“inUserID”, OracleClient.OracleType.Char, _ 36, UserID.ToString) MyBase.AddParameter(“results_cursor”, _ OracleClient.OracleType.Cursor, ParameterDirection.Output) ‘Fill the DataSet MyBase.FillDataSet(GetUser, “User”) Catch ExceptionErr As Exception... DataSet MyBase.SQL = “ManagersPackage.usp_SelectManagers” ‘Initialize the Command object MyBase.InitializeCommand() ‘Add a Parameter to the Parameters collection MyBase.AddParameter(“results_cursor”, _ 3 76 Selecting Data OracleClient.OracleType.Cursor, ParameterDirection.Output) ‘Fill the DataSet MyBase.FillDataSet(GetManagers, “Managers”) Catch ExceptionErr As Exception Throw New System.Exception(ExceptionErr.Message,... the data component to get all user GetUsers = objWDAUsers.GetUsers Catch ExceptionErr As Exception Throw New System.Exception(ExceptionErr.Message, _ ExceptionErr.InnerException) End Try End Function 16 The GetUser function is next and returns the details for a single user Add this function to your class: Public Function GetUser(ByVal UserID As Guid) As DataSet Try ‘Call the data component to get a... cboUserGroup.DataSource = objGroupsDS.Tables(“Groups”) cboUserGroup.DisplayMember = “GroupName” cboUserGroup.ValueMember = “GroupID” ‘Reset the selected index cboGroups.SelectedIndex = -1 cboUserGroup.SelectedIndex = -1 26 The next step is to modify the code under the Case Roles statement in the ActionAdd procedure to reload the list of roles Modify the relevant sections of this procedure as shown here: ‘Clear the input... concatenation and a column alias it has a unique WHERE clause The SELECT statement for this stored procedure is listed here for SQL Server only, as the WHERE clause is the same for both SQL Server and Oracle 3 86 Selecting Data The join used in this stored procedure is an INNER JOIN and joins only the rows in the Roles table where the RoleID in the Users table matches the RoleID in the Roles table Thus, only... The LIKE keyword determines whether a string matches a given pattern The percent (%) signs in the string to be compared against are used as wildcard characters, and by including the percent sign at the beginning and end of the word MANAGER, you are specifying that any role name that contains the word MANAGER is considered a match SELECT UserID AS ManagerID, FirstName + ‘ ‘ + LastName AS ManagerName FROM... DataSet MyBase.SQL = “usp_SelectRole” ‘Initialize the Command object MyBase.InitializeCommand() ‘Add a Parameter to the Parameters collection MyBase.AddParameter(“@RoleID”, SqlDbType.UniqueIdentifier, _ 16, RoleID) ‘Fill the DataSet MyBase.FillDataSet(GetRole, “Role”) Catch ExceptionErr As Exception Throw New System.Exception(ExceptionErr.Message, _ ExceptionErr.InnerException) End Try End Function Oracle . does. I provide the examples in a format that works with both databases. 366 Chapter 12 15_58894x ch12.qxd 10/13/05 5: 56 PM Page 366 In the following example, you are selecting two columns from. to include the appropriate error handling code for your database. 364 Chapter 11 14_58894x ch11.qxd 10/13/05 5: 56 PM Page 364 12 Selecting Data Up until this point, the SELECT stored procedures. How to declare and use local variables in your stored procedures 363 Inserting Data 14_58894x ch11.qxd 10/13/05 5: 56 PM Page 363 ❑ How to perform error handling in your stored procedures ❑ How