Tài liệu Oracle PL/SQL by Example- P7 docx

50 379 0
Tài liệu Oracle PL/SQL by Example- P7 docx

Đ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

▼ ROLLBACK; SELECT * FROM statistics; TABLE_NAME TRANSACTIO TRANSACTION_USER TRANSACTI INSTRUCTOR UPDATE STUDENT 09-MAR-08 Notice that even though you roll the UPDATE statement against the INSTRUCTOR table, the record is inserted in the STATISTICS table due to the autonomous transaction specified in the trigger body. LAB 13.1 EXERCISES This section provides exercises and suggested answers, with discussion related to how those answers resulted.The most important thing to realize is whether your answer works.You should figure out the implications of the answers and what the effects are of any different answers you may come up with. 13.1.1 Understand What a Trigger Is In this exercise, you need to determine the trigger firing event, its type, and so on based on the trigger’s CREATE clause. Consider the following CREATE clause: CREATE TRIGGER student_au AFTER UPDATE ON STUDENT FOR EACH ROW WHEN (NVL(NEW.ZIP, ' ') <> OLD.ZIP) Trigger Body In the WHEN statement of the CREATE clause, the pseudorecord :OLD allows you to access a row currently being processed. It is important to note that neither :NEW nor :OLD is prefixed by a colon (:) when it is used in the condition of the WHEN statement. You are already familiar with the pseudorecord :NEW.The :OLD pseudorecord allows you to access the current information of the record being updated. In other words, it is information currently present in the STUDENT table for a specified record.The :NEW pseudorecord allows you to access the new information for the current record. In other words, :NEW indicates the updated values. For example, consider the following UPDATE statement: UPDATE student SET zip = '01247' WHERE zip = '02189'; The value 01247 of the ZIP column is a new value, and the trigger references it as :NEW.ZIP. The value 02189 in the ZIP column is the previous value and is referenced as :OLD.ZIP. LAB 13.1 272 Lab 13.1 Exercises Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. DID YOU KNOW? :OLD is undefined for INSERT statements, and :NEW is undefined for DELETE statements. However, the PL/SQL compiler does not generate syntax errors when :OLD or :NEW is used in triggers where the triggering event is an INSERT or DELETE operation, respectively. In this case, the field values are set to NULL for :OLD and :NEW pseudorecords. Answer the following questions: A) Assume that a trigger named STUDENT_AU already exists in the database. If you use the CREATE clause to modify the existing trigger, what error message is generated? Explain your answer. ANSWER: You see an error message stating that the STUDENT_AU name is already being used by another object.The CREATE clause can create new objects in the database, but it is unable to handle modifications.To modify the existing trigger, you must add the REPLACE statement to the CREATE clause. In this case, the old version of the trigger is dropped without warning, and the new version of the trigger is created. B) If an update statement is issued on the STUDENT table, how many times does this trigger fire? ANSWER: The trigger fires as many times as there are rows affected by the triggering event, because the FOR EACH ROW statement is present in the CREATE trigger clause. When the FOR EACH ROW statement is not present in the CREATE trigger clause, the trigger fires once for the triggering event. In this case, if the following UPDATE statement UPDATE student SET zip = '01247' WHERE zip = '02189'; is issued against the STUDENT table, it updates as many records as there are students with a zip code of 02189. C) How many times does this trigger fire if an update statement is issued against the STUDENT table but the ZIP column is not changed? ANSWER: The trigger does not fire, because the condition of the WHEN statement evaluates to FALSE. The condition (NVL(NEW.ZIP, ' ') <> OLD.ZIP) of the WHEN statement compares the new value of the zip code to the old value of the zip code. If the value of the zip code is not changed, this condition evaluates to FALSE. As a result, this trigger does not fire if an UPDATE statement does not modify the value of the zip code for a specified record. D) Why do you think an NVL function is present in the WHEN statement of the CREATE clause? ANSWER: If an UPDATE statement does not modify the column ZIP, the value of the field NEW.ZIP is undefined. In other words, it is NULL. A NULL value of ZIP cannot be compared with a non-NULL value of ZIP.Therefore, the NVL function is present in the WHEN condition. Because the column ZIP has a NOT NULL constraint defined, there is no need to use the NVL func- tion for the OLD.ZIP field. An UPDATE statement issued against the STUDENT table always has a value of ZIP present in the table. LAB 13.1 Lab 13.1 Exercises 273 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 13.1.2 Use BEFORE and AFTER Triggers In this exercise, you create a trigger on the INSTRUCTOR table that fires before an INSERT statement is issued against the table.The trigger determines the values for the columns CREATED_BY, MODIFIED_BY, CREATED_DATE, and MODIFIED_DATE. In addition, it determines if the value of zip provided by an INSERT statement is valid. Create the following trigger: ch13_1a.sql, version 1.0 CREATE OR REPLACE TRIGGER instructor_bi BEFORE INSERT ON INSTRUCTOR FOR EACH ROW DECLARE v_work_zip CHAR(1); BEGIN :NEW.CREATED_BY := USER; :NEW.CREATED_DATE := SYSDATE; :NEW.MODIFIED_BY := USER; :NEW.MODIFIED_DATE := SYSDATE; SELECT 'Y' INTO v_work_zip FROM zipcode WHERE zip = :NEW.ZIP; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR (-20001, 'Zip code is not valid!'); END; Answer the following questions: A) If an INSERT statement issued against the INSTRUCTOR table is missing a value for the column ZIP, does the trigger raise an exception? Explain your answer. ANSWER: Yes, the trigger raises an exception.When an INSERT statement does not provide a value for the column ZIP, the value of :NEW.ZIP is NULL.This value is used in the WHERE clause of the SELECT INTO statement. As a result, the SELECT INTO statement is unable to return data. Therefore, the trigger raises a NO_DATA_FOUND exception. B) Modify this trigger so that another error message is displayed when an INSERT statement is missing a value for the column ZIP. ANSWER: The script should look similar to the following. All changes are shown in bold. ch13_1b.sql, version 2.0 CREATE OR REPLACE TRIGGER instructor_bi BEFORE INSERT ON INSTRUCTOR FOR EACH ROW DECLARE v_work_zip CHAR(1); BEGIN :NEW.CREATED_BY := USER; :NEW.CREATED_DATE := SYSDATE; LAB 13.1 274 Lab 13.1 Exercises Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. :NEW.MODIFIED_BY := USER; :NEW.MODIFIED_DATE := SYSDATE; IF :NEW.ZIP IS NULL THEN RAISE_APPLICATION_ERROR (-20002, 'Zip code is missing!'); ELSE SELECT 'Y' INTO v_work_zip FROM zipcode WHERE zip = :NEW.ZIP; END IF; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR (-20001, 'Zip code is not valid!'); END; Notice that an IF-ELSE statement is added to the body of the trigger.This IF-ELSE statement evalu- ates the value of :NEW.ZIP. If the value of :NEW.ZIP is NULL, the IF-ELSE statement evaluates to TRUE, and another error message is displayed, stating that the value of ZIP is missing. If the IF-ELSE statement evaluates to FALSE, control is passed to the ELSE part of the statement, and the SELECT INTO statement is executed. C) Modify this trigger so that there is no need to supply the value for the instructor’s ID at the time of the INSERT statement. ANSWER: The version of the trigger should look similar to the following. All changes are shown in bold. ch13_1c.sql, version 3.0 CREATE OR REPLACE TRIGGER instructor_bi BEFORE INSERT ON INSTRUCTOR FOR EACH ROW DECLARE v_work_zip CHAR(1); BEGIN :NEW.CREATED_BY := USER; :NEW.CREATED_DATE := SYSDATE; :NEW.MODIFIED_BY := USER; :NEW.MODIFIED_DATE := SYSDATE; SELECT 'Y' INTO v_work_zip FROM zipcode WHERE zip = :NEW.ZIP; :NEW.INSTRUCTOR_ID := INSTRUCTOR_ID_SEQ.NEXTVAL; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR (-20001, 'Zip code is not valid!'); END; LAB 13.1 Lab 13.1 Exercises 275 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. The original version of this trigger does not derive a value for the instructor’s ID.Therefore, an INSERT statement issued against the INSTRUCTOR table has to populate the INSTRUCTOR_ID column as well.The new version of the trigger populates the value of the INSTRUCTOR_ID column so that the INSERT statement does not have to do it. Generally, it is a good idea to populate columns holding IDs in the trigger, because when a user issues an INSERT statement, he or she might not know that an ID must be populated at the time of the insert. Furthermore, a user may not know—more than likely does not know—how to operate sequences to populate the ID. As mentioned previously, the ability to access a sequence via a PL/SQL expression is a new feature introduced in Oracle 11g. Prior to Oracle 11g, you needed to employ the SELECT INTO statement in the body of the trigger to populate the INSTRUCTOR_ID column. CREATE OR REPLACE TRIGGER instructor_bi BEFORE INSERT ON INSTRUCTOR FOR EACH ROW DECLARE v_work_zip CHAR(1); v_instructor_id INSTRUCTOR.INSTRUCTOR_ID%TYPE; BEGIN :NEW.CREATED_BY := USER; :NEW.CREATED_DATE := SYSDATE; :NEW.MODIFIED_BY := USER; :NEW.MODIFIED_DATE := SYSDATE; SELECT 'Y' INTO v_work_zip FROM zipcode WHERE zip = :NEW.ZIP; SELECT INSTRUCTOR_ID_SEQ.NEXTVAL INTO v_instructor_id FROM dual; :NEW.INSTRUCTOR_ID := v_instructor_id; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR (-20001, 'Zip code is not valid!'); END; LAB 13.1 276 Lab 13.1 Exercises Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. LAB 13.2 Types of Triggers LAB OBJECTIVES After completing this lab, you will be able to . Use row and statement triggers . Use INSTEAD OF triggers In the preceding lab you encountered the term row trigger. A row trigger is fired as many times as there are rows affected by the triggering statement. When the statement FOR EACH ROW is present in the CREATE TRIGGER clause, the trigger is a row trigger. Consider the following code: FOR EXAMPLE CREATE OR REPLACE TRIGGER course_au AFTER UPDATE ON COURSE FOR EACH ROW In this code fragment, the statement FOR EACH ROW is present in the CREATE TRIGGER clause. Therefore, this trigger is a row trigger. If an UPDATE statement causes 20 records in the COURSE table to be modified, this trigger fires 20 times. A statement trigger is fired once for the triggering statement. In other words, a statement trigger fires once, regardless of the number of rows affected by the triggering statement. To create a statement trigger, you omit the FOR EACH ROW in the CREATE TRIGGER clause. Consider the following code fragment: FOR EXAMPLE CREATE OR REPLACE TRIGGER enrollment_ad AFTER DELETE ON ENROLLMENT This trigger fires once after a DELETE statement is issued against the ENROLLMENT table. Whether the DELETE statement removes one row or five rows from the ENROLLMENT table, this trigger fires only once. LAB 13.2 277 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. Statement triggers should be used when the operations performed by the trigger do not depend on the data in the individual records. For example, if you want to limit access to a table to busi- ness hours only, a statement trigger is used. Consider the following example: FOR EXAMPLE CREATE OR REPLACE TRIGGER instructor_biud BEFORE INSERT OR UPDATE OR DELETE ON INSTRUCTOR DECLARE v_day VARCHAR2(10); BEGIN v_day := RTRIM(TO_CHAR(SYSDATE, 'DAY')); IF v_day LIKE ('S%') THEN RAISE_APPLICATION_ERROR (-20000, 'A table cannot be modified during off hours'); END IF; END; This is a statement trigger on the INSTRUCTOR table, and it fires before an INSERT, UPDATE, or DELETE statement is issued. First, the trigger determines the day of the week. If the day is Saturday or Sunday, an error message is generated. When the following UPDATE statement on the INSTRUCTOR table is issued on Saturday or Sunday: UPDATE instructor SET zip = 10025 WHERE zip = 10015; the trigger generates this error message: update INSTRUCTOR * ERROR at line 1: ORA-20000: A table cannot be modified during off hours ORA-06512: at "STUDENT.INSTRUCTOR_BIUD", line 6 ORA-04088: error during execution of trigger 'STUDENT.INSTRUCTOR_BIUD' Notice that this trigger checks for a specific day of the week. However, it does not check the time of day. You can create a more sophisticated trigger that checks what day of the week it is and if the current time is between 9 a.m. and 5 p.m. If the day is during the business week but the time of day is not between 9 a.m. and 5 p.m., the error is generated. INSTEAD OF TRIGGERS So far you have seen triggers that are defined on database tables. PL/SQL provides another kind of trigger that is defined on database views. A view is a custom representation of data and can be called a stored query. Consider the following example of the view created against the COURSE table: LAB 13.2 278 Types of Triggers Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. FOR EXAMPLE You may find that you do not have privileges to create a view when logged in as STUDENT. If this is so, you need to log in as SYS and grant a CREATE VIEW privilege as follows: GRANT CREATE VIEW TO student; As soon as the privilege has been granted, the view on the COURSE table may be created as follows: CREATE VIEW course_cost AS SELECT course_no, description, cost FROM course; DID YOU KNOW? When a view is created, it does not contain or store any data.The data is derived from the SELECT statement associated with the view. Based on the preceding example, the COURSE_COST view contains three columns that are selected from the COURSE table. Similar to tables, views can be manipulated via INSERT, UPDATE, or DELETE statements, with some restrictions. However, it is important to note that when any of these statements are issued against a view, the corresponding data is modified in the underlying tables. For example, consider an UPDATE statement against the COURSE_COST view: FOR EXAMPLE UPDATE course_cost SET cost = 2000 WHERE course_no = 450; COMMIT; After the UPDATE statement is executed, both SELECT statements against the COURSE_COST view and the COURSE table return the same value of the cost for course number 450: SELECT * FROM course_cost WHERE course_no = 450; COURSE_NO DESCRIPTION COST 450 DB Programming in Java 2000 SELECT course_no, cost FROM course WHERE course_no = 450; COURSE_NO COST 450 2000 LAB 13.2 Types of Triggers 279 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. As mentioned earlier, some views are restricted as to whether they can be modified by INSERT, UPDATE, or DELETE statements. Specifically, these restrictions apply to the underlying SELECT statement, which is also called a view query. Thus, if a view query performs any of the opera- tions or contains any of the following constructs, a view cannot be modified by an UPDATE, INSERT, or DELETE statement: . Set operations such as UNION, UNION ALL, INTERSECT, and MINUS . Group functions such as AVG, COUNT, MAX, MIN, and SUM . GROUP BY or HAVING clauses . CONNECT BY or START WITH clauses . The DISTINCT operator . The ROWNUM pseudocolumn Consider the following view created on the INSTRUCTOR and SECTION tables: FOR EXAMPLE CREATE VIEW instructor_summary_view AS SELECT i.instructor_id, COUNT(s.section_id) total_courses FROM instructor i LEFT OUTER JOIN section s ON (i.instructor_id = s.instructor_id) GROUP BY i.instructor_id; Note that the SELECT statement is written in the ANSI 1999 SQL standard. It uses the outer join between the INSTRUCTOR and SECTION tables. The LEFT OUTER JOIN indicates that an instructor record in the INSTRUCTOR table that does not have a corresponding record in the SECTION table is included in the result set with TOTAL_COURSES equal to 0. BY THE WAY You will find detailed explanations and examples of the statements using the new ANSI 1999 SQL standard in Appendix C,“ANSI SQL Standards,” and in the Oracle help.Throughout this book we try to provide examples illustrating both standards; however, our main focus is on PL/SQL features rather than SQL. In the previous versions of Oracle, this statement would look as follows: SELECT i.instructor_id, COUNT(s.section_id) total_courses FROM instructor i, section s WHERE i.instructor_id = s.instructor_id (+) GROUP BY i.instructor_id; LAB 13.2 280 Types of Triggers Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. This view is not updatable, because it contains the group function, COUNT(). As a result, the following DELETE statement DELETE FROM instructor_summary_view WHERE instructor_id = 109; causes the error shown: DELETE FROM instructor_summary_view * ERROR at line 1: ORA-01732: data manipulation operation not legal on this view You will recall that PL/SQL provides a special kind of trigger that can be defined on database views. This trigger is called an INSTEAD OF trigger and is created as a row trigger. An INSTEAD OF trigger fires instead of the triggering statement (INSERT, UPDATE, DELETE) that has been issued against a view and directly modifies the underlying tables. Consider an INSTEAD OF trigger defined on the INSTRUCTOR_SUMMARY_VIEW created earlier. This trigger deletes a record from the INSTRUCTOR table for the corresponding value of the instructor’s ID. FOR EXAMPLE CREATE OR REPLACE TRIGGER instructor_summary_del INSTEAD OF DELETE ON instructor_summary_view FOR EACH ROW BEGIN DELETE FROM instructor WHERE instructor_id = :OLD.INSTRUCTOR_ID; END; After the trigger is created, the DELETE statement against the INSTRUCTOR_SUMMARY_VIEW does not generate any errors: DELETE FROM instructor_summary_view WHERE instructor_id = 109; 1 row deleted. When the DELETE statement is issued, the trigger deletes a record from the INSTRUCTOR table corresponding to the specified value of INSTRUCTOR_ID. Consider the same DELETE state- ment with a different instructor ID: DELETE FROM instructor_summary_view WHERE instructor_id = 101; When this DELETE statement is issued, it causes the error shown: DELETE FROM instructor_summary_view * ERROR at line 1: LAB 13.2 Types of Triggers 281 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. [...]... INSERT ON COURSE FOR EACH ROW BEGIN :NEW.COURSE_NO := COURSE_NO_SEQ.NEXTVAL; :NEW.CREATED _BY := USER; :NEW.CREATED_DATE := SYSDATE; :NEW.MODIFIED _BY := USER; :NEW.MODIFIED_DATE := SYSDATE; END; As mentioned, the ability to access sequence via a PL/SQL expression is a new feature introduced in Oracle 11g Prior to Oracle 11g, you would have needed to employ the SELECT INTO statement in the body of the... EXCEPTION WHEN NO_DATA_FOUND THEN INSERT INTO ZIPCODE (zip, city, state, created _by, created_date, modified _by, modified_date) VALUES (:NEW.zip, :NEW.city, :NEW.state, USER, SYSDATE, USER, SYSDATE); END; INSERT INTO STUDENT (student_id, first_name, last_name, street_address, zip, registration_date, created _by, created_date, modified _by, modified_date) VALUES (:NEW.student_id, :NEW.first_name, :NEW.last_name,... the INSERT or UPDATE statement has been issued It checks the number of courses that are taught by a particular instructor and raises an error if the number is equal to or greater than 10 BY THE WAY As stated, these steps are used to resolve mutating table errors in versions of Oracle prior to 11g Starting with Oracle 11g, compound triggers are used to resolve this error Compound triggers are covered in... following INSERT and UPDATE statements: INSERT INTO ENROLLMENT (student_id, section_id, enroll_date, created _by, created_date, modified _by, modified_date) VALUES (184, 98, SYSDATE, USER, SYSDATE, USER, SYSDATE); INSERT INTO ENROLLMENT (student_id, section_id, enroll_date, created _by, created_date, modified _by, modified_date) VALUES (399, 98, SYSDATE, USER, SYSDATE, USER, SYSDATE); Please purchase PDF Split-Merge... Note that the SELECT statement is written in the ANSI 1999 SQL standard BY THE WAY You will find detailed explanations and examples of the statements using the new ANSI 1999 SQL standard in Appendix C and in the Oracle help Throughout this book we try to provide examples illustrating both standards; however, our main focus is on PL/SQL features rather than SQL Please purchase PDF Split-Merge on www.verypdf.com... TRIGGER student_address_ins INSTEAD OF INSERT ON student_address FOR EACH ROW BEGIN INSERT INTO STUDENT (student_id, first_name, last_name, street_address, zip, registration_date, created _by, created_date, modified _by, modified_date) VALUES (:NEW.student_id, :NEW.first_name, :NEW.last_name, :NEW.street_address, :NEW.zip, SYSDATE, USER, SYSDATE, USER, SYSDATE); END; Issue the following INSERT statements:... DECLARE v_zip VARCHAR2(5); BEGIN SELECT zip INTO v_zip FROM zipcode WHERE zip = :NEW.ZIP; INSERT INTO STUDENT (student_id, first_name, last_name, street_address, zip, registration_date, created _by, created_date, modified _by, modified_date) VALUES (:NEW.student_id, :NEW.first_name, :NEW.last_name, :NEW.street_address, :NEW.zip, SYSDATE, USER, SYSDATE, USER, SYSDATE); EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR... sequence COURSE_NO_SEQ to the filed COURSE_NO_SEQ to the filed COURSE_NO OF THE :NEW PSEUDORECORD Then, the values containing the current user’s name and date are assigned to the fields CREATED _BY, MODIFIED _BY, CREATED_DATE, and MODIFIED_DATE of the :NEW pseudorecord D) Modify this trigger so that if a prerequisite course is supplied at the time of the insert, its value is checked against the existing... mutating table issues and how triggers can be used to resolve these issues In Lab 14.1 you will see how to resolve mutating table issues in the Oracle database prior to version 11g In Lab 14.2 you will learn about compound triggers, which were introduced in Oracle 11g, and how they can be used to resolve mutating table issues Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark... this problem, you must follow these steps when using a version of Oracle prior to 11g: Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark LAB 14.1 Mutating Table Issues 294 1 To record the instructor’s ID and name as described in the preceding example, you must declare two global variables with the help of a PL/SQL package You will learn about global variables and packages . for the columns CREATED _BY, MODIFIED _BY, CREATED_DATE, and MODIFIED_DATE. In addition, it determines if the value of zip provided by an INSERT statement. previously, the ability to access a sequence via a PL/SQL expression is a new feature introduced in Oracle 11g. Prior to Oracle 11g, you needed to employ the SELECT

Ngày đăng: 21/01/2014, 08:20

Mục lục

  • Oracle PL/SQL by example

  • CHAPTER 1 PL/SQL Concepts

    • LAB 1.1 PL/SQL in Client/Server Architecture

      • 1.1.1 Use PL/SQL Anonymous Blocks

      • 1.1.2 Understand How PL/SQL Gets Executed

      • Chapter 1 Try It Yourself

      • CHAPTER 2 General Programming Language Fundamentals

        • LAB 2.1 PL/SQL Programming Fundamentals

          • 2.1.1 Make Use of PL/SQL Language Components

          • 2.1.2 Make Use of PL/SQL Variables

          • 2.1.3 Handle PL/SQL Reserved Words

          • 2.1.4 Make Use of Identifiers in PL/SQL

          • 2.1.5 Make Use of Anchored Datatypes

          • 2.1.6 Declare and Initialize Variables

          • 2.1.7 Understand the Scope of a Block, Nested Blocks, and Labels

          • Chapter 2 Try It Yourself

          • CHAPTER 3 SQL in PL/SQL

            • LAB 3.1 Making Use of DML in PL/SQL

              • 3.1.1 Use the Select INTO Syntax for Variable Initialization

              • 3.1.2 Use DML in a PL/SQL Block

              • 3.1.3 Make Use of a Sequence in a PL/SQL Block

              • LAB 3.2 Making Use of SAVEPOINT

                • 3.2.1 Make Use of COMMIT, ROLLBACK, and SAVEPOINT in a PL/SQL Block

                • Chapter 3 Try It Yourself

                • CHAPTER 4 Conditional Control: IF Statements

                  • LAB 4.1 IF Statements

                    • 4.1.1 Use the IF-THEN Statement

                    • 4.1.2 Use the IF-THEN-ELSE Statement

                    • LAB 4.2 ELSIF Statements

                      • 4.2.1 Use the ELSIF Statement

Tài liệu cùng người dùng

Tài liệu liên quan