• Tidak ada hasil yang ditemukan

Three-Valued Logic

Dalam dokumen Book MySQL Stored Procedure Programming (Halaman 110-114)

Boolean expressions can returnthreepossible results. When all values in a Boolean expression are known, the result is either TRUE or FALSE. For example, there is no doubt when determining the truth or falsity of an expression such as:

(2 < 3) AND (5 < 10)

Sometimes, however, you don’t know all values in an expression. That’s because data- bases allow for values to be NULL, or missing. What, then, can be the result from an expression involving NULLs? For example:

2 < NULL

Because you don’t know what the missing value is, the only answer you can give is “I don’t know.” This is the essence of so-calledthree-valued logic, that you can have not only TRUE and FALSE as a possible result, but also NULL.

To learn more about three-valued logic, we recommend C. J. Date’s bookDatabase In Depth: Relational Theory for the Practitioner (O’Reilly).

Example 4-6. Example of simple IF statement IF sale_value > 200 THEN

CALL apply_free_shipping(sale_id);

END IF;

Example 4-7. Multistatement IF statement IF sale_value > 200 THEN

CALL apply_free_shipping(sale_id);

CALL apply_discount(sale_id,10);

END IF;

Example 4-8. Nested IF statements IF sale_value > 200 THEN

CALL apply_free_shipping(sale_id);

IF sale_value > 500 THEN

CALL apply_discount(sale_id,20);

END IF;

END IF;

It is not necessary to break theIFstatement across multiple lines; all of theIFstate- ments in Example 4-9 are treated identically by MySQL.

It’s probably OK to put a very simpleIFstatement on a single line, but it is definitely not a good practice to do this for complex or nested IF structures. For instance, which is easier to read, understand, and maintain? This:

IF sale_value > 200 THEN

CALL apply_free_shipping(sale_id);

IF sale_value > 500 THEN

CALL apply_discount(sale_id,20);

END IF;

END IF;

Or this:

IF sale_value > 200 THEN CALL apply_free_shipping(sale_id); IF sale_value > 500 THEN CALL apply_discount(sale_id,20);END IF;END IF;

Some programmers like to place theTHEN clause on a separate line, as follows:

IF sale_value > 200 THEN

CALL apply_free_shipping(sale_id);

END IF;

But this is really a matter of personal preference and/or programming standards.

For any nontrivial IF statement, use indenting and formatting to ensure that the logic of yourIF statement is easily understood.

IF-THEN-ELSE statements

Adding anELSEcondition to yourIFstatements allows you to specify statements that will execute if theIFcondition is NOT TRUE. We’ll emphasize again—because it is important—that NOT TRUE does not always mean FALSE. If theIFstatement con- dition evaluates to NULL, then the ELSEstatements will still be executed; this can lead to subtle bugs if you don’t protect against NULL variables in yourIF conditions.

Example 4-9. Alternate formatting for IF statements

IF sale_value > 200 THEN CALL apply_free_shipping(sale_id); END IF;

IF sale_value > 200 THEN

CALL apply_free_shipping(sale_id);

END IF;

IF sale_value > 200 THEN

CALL apply_free_shipping(sale_id);

END IF;

AnIF-THEN-ELSE block has the following syntax:

IF expression THEN

statements that execute if the expression is TRUE ELSE

statements that execute if the expression is FALSE or NULL END IF;

So in Example 4-10, we apply shipping to an order if it is less than $200; otherwise, we apply a discount (and don’t charge shipping).

IF-THEN-ELSEIF-ELSE statements

The full syntax of theIFstatements allows for multiple conditions to be defined. The first condition that evaluates to TRUE will execute. If none of the statements evalu- ates to TRUE, then the ELSEclause (if present) will execute. The syntax for an IF- THEN-ELSEIF-ELSE IF statement looks like this:

IF expression THEN

statements that execute if the expression is TRUE ELSEIF expression THEN

statements that execute if expression1 is TRUE ELSE

statements that execute if all the preceding expressions are FALSE or NULL END IF;

You can have as manyELSEIF conditions as you like.

The conditions do not need to be mutually exclusive. That is, more than one of the conditions can evaluate to TRUE. The first condition that evaluates to TRUE is the one that executes. Creating overlapping conditions like this can be useful, but you have to be very careful when ordering the conditions. For instance, consider theIF- ELSEIF statement shown in Example 4-11.

The intention of this code fragment is clear: apply free shipping to all orders over

$200, and add a 20% discount for preferred customers. However, because the first Example 4-10. Simple IF-THEN ELSE example

IF sale_value <200 THEN

CALL apply_shipping(sale_id);

ELSE

CALL apply_discount(sale_id);

END IF;

Example 4-11. Example of an IF-ELSEIF block with overlapping conditions IF (sale_value>200) THEN

CALL free_shipping(sale_id);

ELSEIF (sale_value >200 and customer_status='PREFERRED') THEN CALL free_shipping(sale_id);

CALL apply_discount(sale_id,20);

END IF;

condition will evaluate to TRUE for all orders over $200, theELSEIFcondition will not be evaluated for any orders over $200, and our preferred customers will not get their discount. No discount for preferred customers means no end-of-year bonus for our stored procedure programmer!

There are a number of better ways to craft this statement: for one thing, we could move the ELSEIF condition into the IF clause to ensure that it gets evaluated first;

alternately, we could nest anIFstatement within thesale_value>200 IFclause to test the customer status, as shown in Example 4-12.

Both of the alternatives shown in Example 4-12 are perfectly valid. Generally we want to avoid nestingIF statements where possible, but if there are a lot of addi- tional evaluations that we need to conduct when thesale_valueis greater than $200, then it might make sense to perform thesale_valuetest once, and then individually test for all the other conditions. So let’s say our business rules state that for orders over $200 we give free shipping, along with a variable discount based on the cus- tomer’s status in our loyalty program. The logic in a singleIF-ELSEIF block might look like that shown in Example 4-13.

Example 4-12. Two ways of correcting the logic error in the previous example /* Reordering the IF conditions */

IF (sale_value >200 and customer_status='PREFERED') THEN CALL free_shipping(sale_id);

CALL apply_discount(sale_id,20);

ELSEIF (sale_value>200) THEN CALL free_shipping(sale_id);

END IF;

/* Nesting the IF conditions */

IF (sale_value >200) THEN CALL free_shipping(sale_id);

IF (customer_satus='PREFERRED') THEN CALL apply_discount(sale_id,20);

END IF;

END IF:

Example 4-13. IF block with many redundant conditions IF (sale_value >200 and customer_status='PLATINUM') THEN CALL free_shipping(sale_id); /* Free shipping*/

CALL apply_discount(sale_id,20); /* 20% discount */

ELSEIF (sale_value >200 and customer_status='GOLD') THEN CALL free_shipping(sale_id); /* Free shipping*/

CALL apply_discount(sale_id,15); /* 15% discount */

In this case, the constant repetition of the sale_value condition and the free_

shippingcall actually undermines the readability of our logic—as well as imposing a performance overhead (see Chapter 22). It might be better to use a nestedIFstruc- ture that makes it clear that everyone gets free shipping for orders over $200, and that discounts are then applied based on the customer loyalty status only.

Example 4-14 shows the nestedIF implementation.

Dalam dokumen Book MySQL Stored Procedure Programming (Halaman 110-114)