This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Macromedia ColdFusion MX Development Copyright 2002 by Que
Executive Editor Candace Hall
Acquisitions Editor
All rights reserved. No part of this book shall be reproduced, stored in a retrieval system, or transmitted by any means, electronic, mechanical, photocopying, recording, or otherwise, without written permission from the publisher. No patent liability is assumed with respect to the use of the information contained herein. Although every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions. Nor is any liability assumed for damages resulting from the use of the information contained herein.
Lloyd Black
International Standard Book Number: 0789726939
Copy Editor
Library of Congress Catalog Card Number: 2002103038
Chuck Hutchinson
Printed in the United States of America First Printing: July 2002 05
04
03
02
Development Editor Maureen A. McDaniel
Technical Editor David Swim
Managing Editor Tom Hayes
Project Editor Natalie Harris
Indexer Kelly Castell
Proofreader 4
3
2
1
Jessica McCarty
Team Coordinator
Trademarks
Cindy Teeters
All terms mentioned in this book that are known to be trademarks or service marks have been appropriately capitalized. Que cannot attest to the accuracy of this information. Use of a term in this book should not be regarded as affecting the validity of any trademark or service mark.
Interior Designer Trina Wurst
Cover Designer Radar Design
Page Layout
Warning and Disclaimer Every effort has been made to make this book as complete and as accurate as possible, but no warranty or fitness is implied. The information provided is on an “as is” basis. The author and the publisher shall have neither liability nor responsibility to any person or entity with respect to any loss or damages arising from the information contained in this book.
NOTE The text surrounded by is a ColdFusion comment. Comments describe what you’re doing in the code and are not processed by the ColdFusion Application Server.
When processed by the ColdFusion Application Server, the preceding code will result in the following HTML being delivered to the requesting browser: Outputting Variable Values into HTML Code
Welcome to ColdFusion!
Outputting Variable Values
47
The values “olive” and 5 are substituted into the tag, and the value “red” is substituted into the
tag, thereby producing a page with an olive-colored background, a 5-pixel left margin, and a red level 1 heading.
Example: Using a Single Tag Listing 2.2 shows an alternative version of the code in Listing 2.1 in which only one tag is used. Listing 2.2
Another Approach to Outputting Variable Values into HTML Code
Outputting Variable Values into HTML Code
Welcome to ColdFusion!
In this case, you are free to put a variable name enclosed in # characters anywhere between the opening and the closing . The resulting HTML sent to the browser will be exactly the same as it was
48
Chapter 2: Variables and Variable Scope
for Listing 2.1. Many developers prefer to code their instructions this way because it cuts down on typing and reduces the likelihood of unbalanced tags. There is a trade-off in performance, however. ColdFusion has to scan everything between and to look for places where it needs to do a substitution. When you increase the amount of text ColdFusion has to scan, you also increase the amount of time the script requires to run to completion. Granted, this time savings will be a very modest amount of time—probably a handful of milliseconds. Such a time interval won’t be perceptible to an end user, but when you multiply it by the number of hits per day your Web site gets, you can actually realize a substantial performance gain on your server.
Example: The # Characters Are Important! Remembering to use the # characters is important when you’re using . To illustrate what happens when you use one without the other, consider the code in Listing 2.3. Listing 2.3
and # Characters
cfoutput and # charactersTag with no # characters:company# characters with no tag: #company# Tag with # characters:#company#
When you request the script in Listing 2.3 from your ColdFusion server, you see a page that looks like the one in Figure 2.1. In the first case, the is not enough for the substitution of the variable’s value. Similarly, in the second case, you see #company# because of the lack of a
Outputting Variable Values
49
tag. Only in the third case, with both and # characters present, does the correct substitution of “Macromedia” occur.
Figure 2.1 Not using both and # characters can create unexpected output results. The moral here is to be sure to remember to use and # characters together to move variable values out of memory and onto the browser screen. NOTE The question “Where should I use the # characters, and where don’t I need them?” is vexing for new ColdFusion developers. When ColdFusion outputs variable values from memory, the # characters are definitely needed around the variable names. In other instances, however, the # characters are not necessary, but developers use them anyway. Using # characters where they aren’t needed is usually harmless in that it doesn’t keep the script from running properly, but it can reduce performance because you’re forcing ColdFusion to take extra processor time to deal with them. As you read this book, be on the lookout for Caution boxes that point out places where the # characters are not required. Similarly, when # characters are required, that point will be stressed, too.
50
Chapter 2: Variables and Variable Scope
Example: Formatting Your Output ColdFusion supports a number of formatting functions that you can use in conjunction with to produce output that is more readable to the end user. As an example where using such functions is necessary, consider the following code:
The current date and time is #Now()#.
The ColdFusion Now() function retrieves the date and time from the server’s system clock. When you output that information to the browser, you see the date and time printed in a format like that shown in Figure 2.2.
Figure 2.2 ColdFusion’s native date/time format is not suitable for direct output to an end user. The date/time format you see is called Open Database Connectivity (ODBC) date/time format. It is well suited for passing date and time information to an ODBC data source, but end users expect to see dates and times formatted a little more intuitively. To help with this formatting, ColdFusion provides two other functions: DateFormat() and TimeFormat(). To see how to use DateFormat(), consider the following code:
The current date is #DateFormat(Now(),”mm/dd/yy”)#.
When using DateFormat(), you pass it a date/time value (provided here by the Now() function) and an output mask. The mask, which specifies the
Outputting Variable Values
51
pattern ColdFusion should use to generate the output, should be enclosed in quotation marks. The result of processing the preceding code line is shown in Figure 2.3.
Figure 2.3 DateFormat() can be used to transfer an ODBC-formatted date into one that the user can more readily understand. The mask “mm/dd/yy” is just one of many you can use for date formatting. Table 2.1 shows a number of other useful masks. Table 2.1
Sample Masks for the DateFormat() Function
Mask
Sample Output
“m/d/yy”
6/1/02 (leading zeros not shown) 06/01/02 (leading zeros shown) 06/01/2002 (four-digit year) 01-Jun-02 (month rendered as three-letter abbreviation) June 1, 2002 (month spelled out completely)
NOTE The expression DateFormat(Now(),”mm/dd/yy”) is sometimes referred to as a nested function, meaning one function is inside another. When functions are nested, they are evaluated from innermost to outermost. In this case, the Now() function is evaluated first, and the value it produces is passed directly into the DateFormat() function.
52
Chapter 2: Variables and Variable Scope
Note also that the # characters go around the outermost function. Placing # characters around the Now() function as well causes an error message to be generated. TimeFormat() works similarly and has its own masks that involve hours,
minutes, and seconds. Expanding the previous example to include the time, you have
The current date is #DateFormat(Now(),”mm/dd/yy”)#. The current time is #TimeFormat(Now(),”hh:mm:ss tt”)#.
Table 2.2 shows some popular masks for the TimeFormat() function, and Figure 2.4 illustrates the output from the preceding code. Table 2.2
Sample Masks for the TimeFormat() Function
Mask
Sample Output
“h:mm:ss t”
1:17:09 P (leading zeros not shown for hours, one character for AM/PM) 1:17:09 PM (leading zeros not shown for hours, two characters shown for AM/PM) 01:17:09 PM (leading zeros shown for hours) 13:17:09 (hours taken from 24-hour clock)
“h:mm:ss tt” “hh:mm:ss tt” “HH:mm:ss”
Figure 2.4 TimeFormat() extracts time information from an ODBCformatted date and makes it readable.
ColdFusion Variable Scope
53
ColdFusion also supplies functions for number formatting as well. The NumberFormat()function supports an extensive number of mask characters that enable you to control how the formatted number appears. A very common type of number mask involves showing the number of digits before and after a decimal point. To accomplish this, you use an underscore character for each digit and a period for the location of the decimal point. For example, the following code yields the number 587.40 on the browser screen: #NumberFormat(myNumber,”___.__”)#
Sometimes numbers represent prices, in which case the DollarFormat()function is useful. You simply pass DollarFormat() the number, and it will take care of the dollar sign, the decimal point, and any necessary commas. If you run the following code, you’ll see that ColdFusion renders the total as $1,329.78: #DollarFormat(grandTotal)#
ColdFusion Variable Scope The variables you create with are called local variables. They are local in the sense that they exist only while the script they’re defined in is running. When that script finishes and the resulting HTML page is delivered to the requesting browser, the local variables are cleared out of memory so that ColdFusion has all its resources available to process the next request. In addition to the local variables, ColdFusion maintains several other variable collections in memory. These collections are called variable scopes, and you distinguish one scope from another by use of a prefix. The available prefixes include the following: • Variables for local variables • URL for variables passed on the query string • Form for variables passed by means of an HTML form submitted using the HTTP POST method • CGI for variables found in the HTTP environment (they are often called the environment variables) • Cookie for variables passed by means of an HTTP cookie • File for variables created as a result of processing a instruction
54
Chapter 2: Variables and Variable Scope
• Application for variables that are common to all users of an application • Session for variables stored in a user’s session object • Client for variables stored as client variables (storage can occur in the Windows Registry, browser cookies, or a data source) • Server for variables that are common to all applications on the server • A query name for data returned from a database query In each case, the name of the variable is separated from its prefix by a period. Thus, to refer to a session variable called loginStatus, you would use Session.loginStatus. Because you have been referring to local variables without using the Variables prefix, you might have already figured out that not all variable scopes require a prefix. Strictly speaking, the following scopes do not need a prefix: • Query results • Local variables • CGI variables • File variables • URL variables • Form variables • Cookie variables • Client variables The fact that not all variable scopes require a prefix provides some convenience in that you have less typing to do, but it can also make for some ambiguity as well. Suppose the browser has passed a cookie called ID with the value 19427 to ColdFusion when requesting a script with the following code: #ID#
In this case, two variables are named ID—one in the local Variables scope and one in the Cookie scope. When the variable ID is referenced inside , how can ColdFusion know which value is to be used? The
ColdFusion Variable Scope
55
answer lies in the order of precedence that ColdFusion gives to the various scopes. The order of precedence exactly matches the preceding bulleted list, meaning that query results will be checked first, then local variables, then CGI variables, and so on. Thus, the value ID that is output here corresponds to the value of the local variable named ID or 90473. If you want the value of the cookie variable named ID to be output, you would have to use #Cookie.ID#
As a general rule, developers who are concerned with performance make judicious use of the prefixes because doing so prevents ColdFusion from having to hunt through all the various scopes for a variable. In the preceding example, if there was no local variable called ID and you did not use the Cookie prefix, ColdFusion would have had to look through six different scopes before finally finding ID in the cookie scope. Of the eight scopes in the preceding list that do not require a prefix, you have seen how to work only with variables in the local scope by creating those variables by means of . Two of the other scopes—URL and Form—are critical to building Web applications with ColdFusion, and they are discussed in detail in the next two sections.
Example: Using URL Variables URL variables refer to variables passed on the query string. A query string is made up of variable names and values and is appended to the end of the URL of the script you’re calling. The query string is separated from the URL by a question mark. Thus, in the URL http://scully.rockcreekweb.com/que/CfbyEx/ch2/urlvars.cfm?fname=Ben&lname=Forta
the query string is represented by the following excerpt: fname=Ben&lname=Forta
Note that the basic unit of a query string is the name=value pairing. These pairings represent the names and associated values of the query string variables. Multiple name=value pairings have to be separated by an ampersand. CAUTION You can reference URL variables only in the ColdFusion script that is specified in the URL where the variables are found. For the preceding example, you could refer only to URL.fname and URL.lname in the script urlvars.cfm. In addition, these variables expire after the script runs to completion, so referring to them in any subsequent script isn’t legal.
You can get variables on the query string in two principal ways. The first is to have a form that submits its data by the HTTP GET method. In this case,
56
Chapter 2: Variables and Variable Scope
the form field names and their associated values are bundled by the browser and then are appended to the URL specified as the script designated to process the form. As an example, consider the short HTML form generated by the code in Listing 2.4. Listing 2.4
A Short HTML Form That Submits Data by the HTTP GET Method
A Short HTML Form that Submits Data by the HTTP GET Method
NOTE Because get is the default value for the method attribute of the ”>
Hello, #URL.name#!
The resulting Web page would have a green background and a heading that reads “Hello, Zack!”. The second way to place data into the URL is to put it there yourself. For example, you might set up a hyperlink on a person’s name in a corporate directory that links to a script showing detailed contact information for that person. You also have to communicate the identity of the person to the detail script so that it can know whose information it should retrieve. The most common approach to doing this is to pass the person’s employee ID number to the detail script. The following code illustrates how you might do this: Collins, Shane
TIP Special characters such as spaces and punctuation marks cannot be passed as part of a URL variable’s value. Instead, they have to go through a process called encoding, which converts them to characters that can be passed. When submitting form data by the HTTP get method, the browser takes care of the encoding for you. When you build your own query strings, however, you must make sure the data is encoded. The ColdFusion URLEncodedFormat() function can handle this task for you. The URLEncodedFormat() function is necessary in the following code because of the spaces in the value of the variable named school: George Washington University
58
Chapter 2: Variables and Variable Scope
Example: Using Form Variables The Form variable scope includes form field names and their associated values submitted by an HTML form using the HTTP POST method. To use the POST method, you explicitly have to say so in your
When the processing script called postformprocessor.cfm is invoked, it will have three Form variables at its disposal: Form.fname, Form.lname, and Form.age. You can use these variables to build a response page like the one shown in Figure 2.5. The code that generated the response page is shown in Listing 2.7.
Figure 2.5 Form data is easily incorporated into the response page thanks to the ColdFusion Form variable scope. Listing 2.7
The postformprocessor.cfm Script
Using Form Variables
60
Chapter 2: Variables and Variable Scope
Listing 2.7
continued
Hello, #Form.fname# #Form.lname#!
#Form.age# isn’t so old!
Example: Handling a Check Box Field One somewhat tricky aspect of form processing is the handling of check boxes and radio buttons. As mentioned earlier in the chapter, the name and value of a check box or radio button are not passed to the server if it is not selected. This means that you can’t assume the Form variable corresponding to the check box or radio button is going to be there. If you try to refer to the Form variable and it isn’t there, ColdFusion will generate an error message. In this instance, can be helpful. provides a default value for the Form variable in the event that it does not exist. That way, you can refer to the Form variable even though it was never really submitted to the server. To see an example, consider the form in Listing 2.8. Listing 2.8
A Short HTML Form with a Check Box Field
A Short HTML Form with a Checkbox Field
ColdFusion Variable Scope
61
The check box field named subscribe allows the user to decide whether to join a mailing list. If the user selects the box and submits the form, the subscribe field and its associated value, “Yes”, are passed to the server. In this case, there is no problem with referring to Form.subscribe because the field was passed. However, if the user does not want to sign up and therefore does not select the check box, the subscribe field and its value are not passed at all, and any reference to Form.subscribe will produce an error. To work around this problem, you can use in the mailinglist.cfm script to assign a default value to the variable Form.subscribe. In this situation, you would assign a default value of “No” because the default value will be necessary only if the user does not want to subscribe and leaves the check box unchecked. Listing 2.9 uses so that the form will be processed without error, regardless of the user’s choice. Listing 2.9
The mailinglist.cfm Script
Mailing List Signup Response Page Your decision on subscribing: #Form.subscribe#
Example: Using CGI Variables The CGI scope is made up of a set of standard information that is passed between browser and server when the two establish an HTTP connection. When you have the ColdFusion Administrator’s debugging feature called Variable Reporting turned on, you will see the CGI variables appended to each of your ColdFusion pages (refer to Figure 2.6). TIP Form and URL variables also show up in the debugging information when Variable Reporting is active.
62
Chapter 2: Variables and Variable Scope
Figure 2.6 Variables in the CGI scope can be inspected when you have the Show Parameters feature of the ColdFusion debugging facility turned on. CGI variables are not pieces of information that a Web developer is normally concerned with, but sometimes it is useful to retrieve one or more of their values. One such case occurs when you need to know the user’s IP address. This information is captured in the CGI variable named REMOTE_ADDR. Listing 2.10 shows a script that displays a user’s IP address back to her. Listing 2.10
Using CGI Variables
Big Brother is Watching!
I see your IP address is #CGI.REMOTE_ADDR#. Maybe your computer is not as secure as you thought!
ColdFusion Variable Scope
63
Of course, your browser routinely gives out your computer’s IP address, so nothing really underhanded is going on in Listing 2.10’s script. As you can see in Figure 2.6, there are plenty of other CGI variables. The following is a partial listing of some you might find useful: • CONTENT_LENGTH—Specifies the number of characters in the HTTP request made by the browser. • QUERY_STRING—Holds a copy of the query string, if one exists. • REQUEST_METHOD—Equal to GET or POST, depending on which method is employed for the current request. • SCRIPT_NAME—Tells the name of the script that the HTTP request asked to have run. • SERVER_NAME—Specifies the name of the Web server (for example, www.macromedia.com). • SERVER_PORT—Tells you which port is in use for the current request (HTTP traffic is generally handled by port 80). • SERVER_SOFTWARE—Indicates which HTTP server program is running (for example, Microsoft Internet Information Server or the Apache Web Server). • HTTP_USER_AGENT—Contains a string that describes which browser is in use, its version number, and the desktop operating system it’s running on. This CGI variable is frequently used to do server-side browser detection. NOTE You do not have to write the names of the CGI variables in uppercase letters, although that is how they are traditionally spelled out.
Other Variable Scopes You have learned about the URL, Form, and CGI variable scopes in some detail. The other scopes mentioned earlier in the chapter are equally useful, although discussions of how to work with those scopes will be postponed to later parts of the book where they fit into the context of the chapter. Use this guide to find more information on each of the other variable scopes: • Query results—Query result variables hold the data that is retrieved from a database. You will learn how to use query result variables in Chapter 4, “Interacting with Databases: Retrieving Data.”
64
Chapter 2: Variables and Variable Scope
• Cookie—HTTP cookies give you a way to track state information in the Web environment. You will find a full discussion of how to place cookies in Chapter 11, “Maintaining State Information.” • Application, Session, Client, and Server—These variable scopes are features of the ColdFusion Application Framework, which is discussed in Chapter 12, “Using the ColdFusion Application Framework.”
What’s Next This chapter demonstrated how to create and manipulate ColdFusion variables with . You learned how to use to test for a variable’s data type and, later in the chapter, to assign a default value for a variable that may not exist. You learned how to use to retrieve a variable’s value from memory and incorporate it into the output page you were building. Additionally, you learned about the many different variable scopes ColdFusion maintains and what order of precedence ColdFusion uses to look through them. Finally, you saw how to use URL, Form, and CGI variables in ColdFusion scripts. The scripts you have used thus far have been linear in nature. Every command is processed in the order in which it appears in the script. Sometimes, though, you need to process commands conditionally— executing the commands in some instances, but not in others. ColdFusion allows you to do so by means of the and instructions. The next chapter introduces you to these tags and how you can use them to implement conditional logic.
3 Implementing Conditional Logic The ColdFusion Markup Language (CFML) instructions you place in your ColdFusion scripts are processed just as they would be in any other language. The ColdFusion Application Server starts at the first line of the script and works its way sequentially through to the last line. Every command is processed unless it is part of a conditional statement. Conditional statements allow you to process or not process code, depending on the outcome of a condition you assess. Conditional statements typically use Boolean conditions, which can have only one of two possible values—TRUE or FALSE. The most basic form of conditional statement is the “if-then” rule. Our own behavior is governed by many such rules. For example, “If the traffic light is red, then stop the car.” In this rule, you assess the condition that asks whether the traffic light is red. If it is true, you stop the car. If it isn’t true, you don’t stop the car. Such a rule is frequently useful in dynamic Web development. ColdFusion implements “if-then” rules through the instruction. A instruction can be extended to include as well. Use of gives you some kind of recourse if the condition you’re testing turns out to have a value of FALSE. Sometimes when the condition you assess is false, you want to move on to assess a second condition. ColdFusion enables you to do so by means of the instruction. Finally, you may have to assess a question or situation that has an outcome that goes beyond TRUE or FALSE values. For example, the question “What day of the week is it?” has seven possible outcomes. No Boolean condition can handle all seven possibilities. In this case, you can use to set up code to be processed for each one of the seven outcomes. In this chapter, you will • Learn how to implement if-then rules using • Learn how to extend your if-then rules to if-then-else rules by adding
68
Chapter 3: Implementing Conditional Logic
• Learn how to extend your if-then and if-then-else rules to consider other conditions • Learn how to consider an expression with many possible values using
Basic If-Then Rules You use the instruction to implement an if-then rule. A simple example follows:
You don’t look a day over 29!
TIP Indenting the code between and helps to make your scripts more readable.
The instruction has both opening and closing tags, and the code you want to conditionally execute is located between the tags. The code can be HTML, CFML, or some combination of the two. The Boolean condition that you’re testing is located inside the tag. In the preceding example, the condition is Form.age gt 29. This condition tests whether the value of the Form variable called age is greater than 29. If it is, the user sees this sentence: “You don’t look a day over 29!”. If, however, the value of age is 29 or less, the user does not see the message. Note the use of gt instead of the greater than sign (>) in the expression of the condition. To see why this is necessary, look at the following code: 29>
You don’t look a day over 29!
If you use the greater than sign instead of gt, you prematurely close the tag. Because the greater than and less than signs are necessary for building tags, you can’t use them to express conditions. Table 3.1 shows the different comparison operators and how to express them in your Boolean conditions. Table 3.1
Expressions for Comparison Operators
Operator
Expressions
Equality Inequality Less than
eq, equals, is neq, is not less than, lt
Basic If-Then Rules
Table 3.1
69
continued
Operator
Expressions
Greater than Less than or equal to Greater than or equal to
greater than, gt less than or equal to, lte, le greater than or equal to, gte, ge
TIP You can use the Boolean conjunctions and and or to build more complex conditions in your tags, as in this example:
You’re in your 20’s.
The parentheses around each individual condition aren’t necessary, but they help make the statement more readable.
Example: Selecting Colors For a more extensive example of the ways you can use , consider the HTML form in Listing 3.1. This form allows a user to choose the foreground and background colors she prefers. Listing 3.1
Color Choice Form
Color Picker
Color Picker
Please pick a background and foreground color below and then click the “Submit” button.
Choosing the same foreground and background color would be a problem, so you can use to determine whether they are the same and respond accordingly. Listing 3.2 shows one possible response. Listing 3.2
The colorpage.cfm Script
Color choice error!
You choose the same foreground and background color! This would make the text on your pages unreadable. Please use your browser’s Back button and choose another color combination.
Basic If-Then Rules
71
Listing 3.2 continued Customized Color Page
Here is your custom color combination!
Note the use of the tag, which tells the ColdFusion Application Server to stop processing the script. Also, note that you can use
or
because both equals and is are valid ways to test for equality between Form.bgcolor and Form.fgcolor.
Example: Checking for the Existence of Form Fields In Chapter 2, “Variables and Variable Scope,” you learned how to use the tag to specify a default value for a variable that might not exist. This capability is particularly useful when you’re processing a form with check boxes or radio buttons because such form fields are not passed to the ColdFusion server if they aren’t selected. For this example, consider the HTML form in Listing 3.3, which asks users to indicate which age range they fall into. Listing 3.3
Age-Range Specification Form
Age Range
Please choose the age range your age falls within and click the “Continue” button.
72
Chapter 3: Implementing Conditional Logic
Listing 3.3 continued
Some people shy away from providing information about their age, so it’s certainly plausible that they might not select one of the radio buttons. In that case, Form.age will not be defined if you try to reference it in the processing script called ageprocessor.cfm. As an alternative to , you can use together with the IsDefined() function to see whether the form field is there. IsDefined() tests whether a variable exists and returns TRUE if the variable does exist and FALSE if it does not. Listing 3.4 shows you how to use this function. Listing 3.4
The ageprocessor.cfm Script
Age Information
Basic If-Then Rules
Listing 3.4
73
continued
Age range: #Form.age# years
Note the use of the Not operator in the instruction to check the case of the form field not being defined. Also, note that the variable whose existence you’re testing for has to be in quotation marks when you use the IsDefined() function. Figures 3.1 and 3.2 show the resulting page if the user does and does not specify an age range, respectively.
Figure 3.1 When the user chooses an age range, the response page displays the range correctly. The message in Figure 3.2, Not specified years, is something the user could make sense of, but it really doesn’t flow well. To alleviate this problem, you can add a second to the ageprocessor.cfm script to selectively drop in the word years. In this case, you don’t want to drop it in if Form.age has the value “Not specified”. Listing 3.5 shows the updated code.
74
Chapter 3: Implementing Conditional Logic
Figure 3.2 If the user doesn’t pick an age range, however, the response page reads somewhat awkwardly. Listing 3.5
An Improved ageprocessor.cfm Script
Age Information
Basic If-Then Rules
Listing 3.5
Age range: #Form.age#years
Example: Performing Substring Searches So far, you have seen how to use comparison operators and the IsDefined() function to set up Boolean expressions in your instructions. ColdFusion provides other mechanisms for setting up Boolean conditions as well. One is a substring search, in which you look for a smaller string inside a larger one. You do so by using the contains operator. For an example of a substring search, consider the form presented by the code in Listing 3.6. Here, you ask a user to enter his computing skills into a large text window. This form might be part of a job hunting site that you’re building. Listing 3.6
Input Form for Computing Skills Information
Skill Set
Please enter your computing skills in the text area below and click the “Continue” button.
Because you’re always on the lookout for new ColdFusion developers to join your team, you might scan the user’s skills summary to see whether he has ColdFusion skills. You could do so by using the code in Listing 3.7. Listing 3.7
The skillsprocessor.cfm Script
Skills Summary
We’re glad to see you have some ColdFusion skills! Your resume will be forwarded to our hiring manager.
Your skills include: #Form.skills#
In this example, ColdFusion will look through the value of Form.skills in an attempt to find “ColdFusion”. If it does, the user sees a message saying the hiring manager will be notified about his candidacy and then see a restatement of his skills. If the user doesn’t have ColdFusion skills, he simply sees his skill set confirmed. NOTE You also can use does not contain if you need to scan a string to see whether a specific substring is not part of it.
Expanding to an If-Then-Else Rule
77
Expanding to an If-Then-Else Rule The basic tag lets you do something if the associated Boolean condition evaluates to TRUE, but you can’t do anything if the condition turns out to have a value of FALSE. This can tie your hands in situations in which you need to respond differently to a false condition. To alleviate this constraint, ColdFusion supports the addition of a tag to your statement, thereby extending it to an “if-then-else” rule. You can expand the simple example you saw in the previous section to the following:
You don’t look a day over 29!
Hope you look that good at 30!
Note that is positioned between the and tags. acts as a separator between the code you want processed if the condition is true and the code you want processed if the condition is false. CAUTION The tag does not take any attributes, nor is there a closing tag. The only correct way to use is as you see it in the preceding example.
This added flexibility in your statements lets you code things a little more cleanly, as demonstrated in the following examples.
Example: Revisiting Color Selection Recall the background and foreground color selection example from earlier in the chapter. When processing the user’s submission, the colorpage.cfm script had to use the tag to stop processing in the event that the background and foreground colors were the same. In so doing, the script never sent the document structure tags (, , and ) to the browser. You can work around this inelegant solution by adding to the statement in colorpage.cfm, as shown in Listing 3.8. Listing 3.8
An Improved colorpage.cfm Script
Customized Color Page
78
Chapter 3: Implementing Conditional Logic
Listing 3.8
Color choice error!
You chose the same foreground and background color! This would make the text on your pages unreadable. Please use your browser’s Back button and choose another color combination.
Here is your custom color combination!
Expanding to an If-Then-Else Rule
79
Here, the script is expanded to two statements—one to drop in the appropriate tag and another to drop in the appropriate message to the user. You can, of course, handle both tasks by using a single statement, as shown in Listing 3.9. Listing 3.9
Improved colorpage.cfm Script with a Single
Customized Color Page
Color choice error!
You chose the same foreground and background color! This would make the text on your pages unreadable. Please use your browser’s Back button and choose another color combination.
Here is your custom color combination!
80
Chapter 3: Implementing Conditional Logic
Both scripts will produce the same output on the browser screen, but the version in Listing 3.9 is more efficient because it evaluates the condition only once.
Example: Making a Form Field Required Sometimes a user needs to fill out a form field but doesn’t for one reason or another. In this case, you can use to determine whether the field was completed and, in the event that it wasn’t, ask the user to return to the form page and fill out that field. Consider the mailing list sign-up form in Listing 3.10. Listing 3.10
A Form with a Required Field
An HTML Form with a Required Field
To sign up for our mailing list, please fill out the form below and click the “Submit” button. The E-Mail Address field is required.
Expanding to an If-Then-Else Rule
Listing 3.10
81
continued
The mail format information is collected by means of a radio button. Even if the user doesn’t fill in that field, you can still provide a default value for it using . If the user doesn’t provide an e-mail address, however, there’s no default value you can assume that will work. You have to get that information from the user. You can use a instruction in the listsignup.cfm script to determine whether the user filled in the e-mail address field. If she didn’t fill it in, the browser will submit a blank value (also called the empty string or a string with no characters in it). Thus, your should examine the contents of the Form.email variable and see whether it is equal to the empty string. If so, you need to tell the user to go back and fill in her address. Listing 3.11 shows you how to do this. Listing 3.11
The listsignup.cfm Script
Mailing List Sign Up
82
Chapter 3: Implementing Conditional Logic
Listing 3.11 continued
Error!
We need your e-mail address to be able to sign you up! Please use the Back button on your browser to return to the sign-up form and enter your e-mail address before submitting.
Sign-up Information
You are signing up for our mailing with the following information:
E-mail address: #Form.email#
Mail format: #Form.format#
By examining the condition Form.email eq “”, you are testing to see whether the user filled in the required field. Using this condition isn’t the only way to perform the test, though. Another approach involves the use of the ColdFusion Len() function. Len() tells you how many characters a string has, so if you pass Len() the value of Form.email, you can check whether it returns a value of zero as follows:
Error!
We need your e-mail address to be able to sign you up! Please use the Back button on your browser to return to the sign-up form and enter your e-mail address before submitting.
Sign-up Information
You are signing up for our mailing with the following information:
Expanding to an If-Then-Else Rule
83
E-mail address: #Form.email#
Mail format: #Form.format#
The if-then-else logic in the preceding example is equivalent to what you saw in Listing 3.11. There is an advantage to using the Len() function versus testing the string to see whether it is equal to the empty string. The Len() function returns a numeric value that is either zero (if the string contains no characters) or some positive number (if the string has some characters). ColdFusion interprets a zero as a Boolean FALSE and any non-zero numbers as a Boolean TRUE. Because expects an expression that evaluates to either TRUE or FALSE, you can rewrite the preceding instruction as follows:
Sign-up Information
You are signing up for our mailing with the following information:
E-mail address: #Form.email#
Mail format: #Form.format#
Error!
We need your e-mail address to be able to sign you up! Please use the Back button on your browser to return to the sign-up form and enter your e-mail address before submitting.
Note here that you have to reverse the two blocks of code to match the condition in the instruction. If the e-mail field was filled in, Len(Form.email) returns some positive number and is interpreted as TRUE. This compels you to take the code to process when the e-mail address is provided and move it between the and tags.
84
Chapter 3: Implementing Conditional Logic
✔ To learn how to add JavaScript to your HTML forms, see “Making Fields Required,” in Chapter 10.
You can use instructions to enforce the required fields on your forms, but the price you pay is an increased load on the server. It would be better if you knew that the form data submitted was complete so that you don’t have to use ColdFusion to check it. You can accomplish this by including JavaScript code in your code for the HTML form. When the user clicks the Submit button, JavaScript can inspect the required fields, flag any of them that aren’t filled out, and suppress the submission of the form data. This way, you know that if the form data was submitted, it has to be complete. Even if you don’t know JavaScript, ColdFusion can help you implement it in your forms. You’ll learn how to use JavaScript in Chapter 10, “Adding JavaScript to Your Forms.”
Example: Creating Grammatically Correct Output When you’re focused on building a dynamic, database-driven Web site, you can easily overlook good grammar in the HTML pages you generate. In particular, developers often miss using the plural forms of nouns and verbs in their output. Have you ever seen a sentence on a Web page like the following? 1 records found!
The word records doesn’t match the number 1. Sometimes developers try to gloss over this mistake with output like this: 1 record(s) found!
But you don’t need to do that with ColdFusion because you can use to determine which words are grammatically correct. Consider the pizza order form in Listing 3.12. Listing 3.12
Pizza Order Form
Pizza Order Form
Please choose the toppings you’d like on your pizza and click the “Continue Order” button.
The form uses a series of check boxes to ask the user which toppings to put on the pizza. The processing script processtoppings.cfm needs to be prepared for two possibilities: • The user chose no toppings, in which case Form.toppings is undefined. • The user chose one or more toppings, in which case Form.toppings is passed to ColdFusion as a comma-delimited list of the toppings selected. In the second case, you also have to be sensitive to the possibility that the user chose only one topping. If so, you need to use the singular forms of nouns and verbs. The script in Listing 3.13 shows you one way to do so. Listing 3.13
The processtoppings.cfm Script
Pizza Topping Processor
86
Chapter 3: Implementing Conditional Logic
Listing 3.13 continued
Your topping is: toppings are: #Form.toppings#.
Are you sure you want a plain pizza?
Adding More Conditions to Your If-Then-Else Rule
87
✔ To learn more details about ListLen() and other ColdFusion list functions, see “ColdFusion Lists” in Chapter 6.
The ListLen() function tells you how many items are in the commadelimited list stored in Form.toppings. If Form.toppings takes on the default value of the empty string, it is considered to be a list with zero items.
Adding More Conditions to Your If-Then-Else Rule Sometimes it’s not enough to have a separate code block to process when the Boolean condition in a instruction turns out to have a value of FALSE. In some instances, you might need to move on to test yet another condition rather than move directly to the “else” part of the statement. ColdFusion supports the tag to help you with this task. tags occur after the initial , but before the tag, if one exists. You are free to use as many tags as you like. As an example, consider the code that processes a form field named ssn that collects a Social Security number:
You must enter your Social Security number before submitting the form. Please use the Back button on your browser to go back and correct your submission.
Please enter your Social Security Number in the form xxx-xx-xxxx.
Your Social Security Number is #Form.ssn#.
The Boolean condition in the tag checks to see whether the ssn field was left blank. If it was, the user sees a message that submission of the Social Security number is required. If the field was not left blank, processing moves to the tag, which checks to make sure that the Social Security number is not made up of 11 characters (9 digits plus 2 dashes). If that condition has a value of TRUE, the user sees a message that indicates the expected format for the Social Security number. If the second condition is FALSE, processing passes to , where the user receives a confirmation of the Social Security number entered.
88
Chapter 3: Implementing Conditional Logic
In short, you use to test conditions beyond the initial one. The following examples illustrate situations in which you might need to test.
Example: Revisiting the Pizza Topping Selection Form Earlier, you saw how to process the pizza topping selection form using and to ensure grammatically correct sentences. Next, you’ll expand the form processing script to respond to certain topping choices. Examine the code shown in Listing 3.14. Listing 3.14
Expanded processtoppings.cfm Script
Pizza Topping Processor
Adding More Conditions to Your If-Then-Else Rule
Listing 3.14 continued
Your topping is: toppings are: #Form.toppings#.
Do you really want little salty fish on your pizza?
Green or black olives?
Shall we send you some breath mints, too?
Are you sure you want a plain pizza?
89
90
Chapter 3: Implementing Conditional Logic
The instruction added to the pizza topping processor will ask a follow-up question based on whether anchovies, olives, or onions were chosen as toppings. If the user picked anchovies, ColdFusion displays the question asking about little salty fish. Otherwise, if olives were chosen, the user is asked about green or black olives. If neither anchovies nor olives were selected and onions were selected, the user is offered some breath mints. Note that only one of the messages will be displayed. The anchovies message has precedence, followed by the olives message, and then the onions message. If you want combinations of the messages to appear, you have to create a separate instruction for each condition:
Do you really want little salty fish on your pizza?
Green or black olives?
Shall we send you some breath mints, too?
Example: Creating a Day-Specific Message Some sites rotate in content based on the day of the week. The content might be just a simple greeting, a new banner graphic, or a special being offered on the site that day. When considering days of the week, you have seven possibilities. To find out which day of the week it is currently, you can use the Now() function to get the current date and time from the server system clock and then feed that value into the DayOfWeek()function: DayOfWeek(Now())
This expression will return a value between 1 and 7, where 1 represents Sunday, 2 represents Monday, and so on. You can use a , together with five tags and a tag, to determine which day it is and respond appropriately. Listing 3.15 shows you how.
Adding More Conditions to Your If-Then-Else Rule
Listing 3.15
Incorporating Content Specific to a Day of the Week
Incorporating Day-Specific Content
91
92
Chapter 3: Implementing Conditional Logic
Listing 3.15 continued
Note here the use of the tag, which reads in content from a separate file and dynamically incorporates it into the current script. The separate file is specified by the template attribute. is ideal for helping to modularize your ColdFusion logic and your HTML content so that you can deploy it on every page but maintain it in only one place. TIP If one of the conditions you’re testing is more likely to turn out to have a value of TRUE than the other, put that condition in the tag. Then put your next most likely condition in the first tag, and so on. This coding technique improves performance because it prevents ColdFusion from having to work its way through the conditions that are less likely to be true. Because users can hit your site any day of the week, no day is probably more likely than any other, so the days are considered in the order they normally occur.
Considering Multiple Cases In the preceding example, you used several tags to test cases for five of the seven days in the week. For such situations, ColdFusion provides you with another tag——that you can use to test the same conditions, but in a more structured way.
Example: Revisiting the Day-Specific Content Listing 3.16 illustrates how to use the tag to implement the same logic as in Listing 3.15. Listing 3.16
Day-Specific Content Created with
Incorporating Day-Specific Content
The tag takes an expression attribute that is set equal to the expression that can have many possible values—DayOfWeek(Now()), in this
94
Chapter 3: Implementing Conditional Logic
case. For each possible value, you construct a block that contains the code to be processed if the value associated with that case matches the current value of the expression. The kicks in if none of the values in the tags match the value of the expression. TIP As with and , you should put your most likely cases first in the statement to keep processing time to a minimum.
NOTE You’ll get better performance if you implement the day-specific content logic with rather than with and several tags. This is true because, with the you have to evaluate the expression DayOfWeek(Now()) only once, but with the , you may have to evaluate it many times.
Example: Redirecting Users to Different Pages As a closing example for the chapter, consider the code in Listing 3.17, which shows you how to redirect users to specific pages based on which department they choose. You could use this code on an external Web site to direct visitors to information about the department they need to contact or on an intranet site to direct employees to online resources specific to their department. Listing 3.17
Redirecting Users to Departmental Pages
Redirecting to Department-Specific Pages
What’s Next
95
Listing 3.17 continued
Note that the first two blocks handle multiple values. For example, the first redirects the user to the accounting home page if the chosen department is Accounting, Payables, or Receivables. You can consolidate multiple values into a single tag by separating the values with commas. Note also the tag, which redirects users to a new page as specified by the tag’s url attribute.
What’s Next This chapter showed you how to implement conditional processing in a ColdFusion script. You learned how to construct an “if-then” rule using . You next learned how to extend your commands to “if-thenelse” rules by adding a tag. You also saw how to test other conditions in a command by adding a tag. Finally, you learned how to use to consider an expression with many possible outcomes.
96
Chapter 3: Implementing Conditional Logic
ColdFusion was originally released as a tool to help Web developers communicate with back-end databases. Indeed, many of the tags you’ve been using so far such as , , and used to be written as , , and to reflect ColdFusion’s early focus on database connectivity. As ColdFusion matured into a more robust application development environment, the db was dropped in favor of cf. ColdFusion still enables developers to work with databases, and the next two chapters will show you how to compose and issue commands to databases from within your ColdFusion scripts.
4 Interacting with Databases: Retrieving Data One of ColdFusion’s core strengths is its ability to interact with databases. For ColdFusion to work with a database, the database must be set up as a data source through the ColdFusion Administrator. Data sources can be set up through ODBC, OLE (Object Linking and Embedding) DB, or through native drivers that are provided with ColdFusion. After the data source is established, you use the tag to compose and send your commands to the database. Database commands are written in the Structured Query Language (SQL). Different SQL commands are available for each of the different ways you might interact with the database. This chapter focuses on the use of the SQL SELECT statement, which you use to retrieve data stored in the database. You’ll learn more details about the other kinds of SQL statements in Chapter 5, “Interacting with Databases: Inserting, Updating, and Deleting.” In this chapter, you’ll learn how to • Compose SQL SELECT statements that retrieve the data you need • Use to issue SQL statements against a data source • Generate HTML output using data retrieved from a query • Build pages that allow users to search your databases
100
Chapter 4: Interacting with Databases: Retrieving Data
Retrieving Information from a Database ColdFusion can use data retrieved from a database to construct a Web page, send an e-mail message, or perform many other functions. To get the data out of the database, you use the CFML tag together with an SQL SELECT statement that specifies the data that you want to retrieve. The ColdFusion Application Server executes the tag and stores the database data returned to it in a special memory area called a query variable. The query variable is structured in a way that makes it easy for you to access and use the data inside it to create many types of output. The next few sections introduce you to each basic aspect of using ColdFusion to work with databases.
Composing SQL SELECT Statements The most basic SELECT statement indicates the table containing the data you want to retrieve and the names of the fields where the data is stored. For example, the following query would retrieve the data stored in the StudentLastName and StudentFirstName fields of a table named Students: SELECT StudentLastName, StudentFirstName FROM Students
Assuming the fields are named intuitively, the query retrieves the first and last names of all the students in the table. If you want to retrieve the values in all the fields in the table, you can use the asterisk (*) as a wildcard character as follows: SELECT * FROM Students
TIP Using the asterisk as a wildcard character can certainly save you a good bit of typing, but in the interest of good performance, you should specify only the values of fields you really need instead of using the asterisk all the time. Otherwise, you use up memory to store database data that you don’t intend to use.
The two queries you’ve seen so far retrieve information from every record in the database table. Often, though, you need to restrict your focus to a certain subset of records in the table. You can do so by adding a WHERE clause to your statement. For example, you can extend the first query you saw to the following: SELECT StudentLastName, StudentFirstName FROM Students WHERE StudentGradeLevel = 10
Retrieving Information from a Database
101
Now the query returns only the first and last names of those students who are in grade 10. You can extend the WHERE clause to express more complex conditions by using AND and OR. For example, to retrieve the names of all students in grades 10 or 11, you would issue the following query: SELECT StudentLastName, StudentFirstName FROM Students WHERE (StudentGradeLevel = 10) OR (StudentGradeLevel = 11)
The parentheses are not syntactically necessary, but they do enhance the readability of the statement. Here, the OR means that one condition or the other needs to hold true for the record to be selected. Thus, the query will select the name of any student in grade 10 or 11 from the database. To retrieve the names of students in grade 10 whose last name is also Smith, you would write SELECT StudentLastName, StudentFirstName FROM Students WHERE (StudentGradeLevel = 10) AND (StudentLastName = ‘Smith’)
In this case, the AND forces both conditions to hold true for a record to be selected. In the last query, note that the last name Smith must be enclosed in single quotation marks. This is true of database fields that contain character data: Any time you refer to a specific literal value of that field, the value has to be enclosed in single quotation marks. This is not true of other kinds of database fields, though, so if you’re searching for a specific value of a numeric, date/time, or Boolean field, you would not need single quotation marks around the value. NOTE Database fields that contain character data can be identified by many different labels, depending mostly on which database platform you’re using. Some of the more popular labels include Text, Memo, Char, and Varchar. If you see any of these labels listed as a field’s data type, you’ll need single quotation marks around any literal values of the field.
Even though you can choose from plenty of existing algorithms for sorting data, having your SQL command sort the retrieved data is always better than doing it yourself. You accomplish this by adding an ORDER BY clause to the end of your query as follows: SELECT StudentLastName, StudentFirstName FROM Students WHERE StudentGradeLevel = 9 ORDER BY StudentLastName
102
Chapter 4: Interacting with Databases: Retrieving Data
The data returned by the preceding query will be sorted in alphabetical order by the students’ last names. Because two students might have the same last name, you’ll then want to use their first names to determine who comes first in the ordering. You can specify the use of the first name for secondary ordering by adding the StudentFirstName field to the ORDER BY clause: SELECT StudentLastName, StudentFirstName FROM Students WHERE StudentGradeLevel = 9 ORDER BY StudentLastName, StudentFirstName
CAUTION You can’t include a field in the ORDER BY clause that has not been named in the SELECT part of the statement. For example, in the preceding query, you could not include StudentGradeLevel in the ORDER BY clause because only StudentLastName and StudentFirstName are being selected as part of this query.
The kind of sorting that occurs depends on the data type of the database fields you’re using to do the sorting. In the preceding examples, the ordering is alphabetical because StudentLastName and StudentFirstName are both text fields. If you sort on a numeric field, the ordering goes from smaller numbers to larger numbers. If you sort on a date/time field, the ordering goes from least recent to most recent. TIP To reverse any of the orderings, add the SQL keyword DESC to the end of your ORDER BY clause. Adding this keyword has the effect of changing from ascending order to descending order.
What you have seen so far is enough to help you through most of the SELECT statements you’ll need to write. However, you can use some additional SQL operators with a SELECT statement to enhance your ability to retrieve data from your databases. This section wraps up with coverage of some of these extras. IN
The SQL IN operator provides a list of values that you’re interested in finding in the database. Suppose, for example, you want to see all the first and last names of students in grade 10, 11, or 12. You could write your query as follows: SELECT StudentLastName, StudentFirstName FROM Students WHERE (StudentGradeLevel = 10) OR (StudentGradeLevel = 11) OR (StudentGradeLevel = 12) ORDER BY StudentLastName, StudentFirstName
Retrieving Information from a Database
103
The preceding query would work just fine, but the IN keyword gives you a more compact way to express the same thing: SELECT StudentLastName, StudentFirstName FROM Students WHERE StudentGradeLevel IN (10,11,12) ORDER BY StudentLastName, StudentFirstName
The list of values following IN must be enclosed in parentheses for the statement to be syntactically correct. Also, the values must be separated from each other by a comma. If you use a text field value in your WHERE clause, each value has to be enclosed in single quotation marks, as in this example: SELECT StudentLastName, StudentFirstName FROM Students WHERE StudentLastName IN (‘Smith’,’Jones’,’Brown’) ORDER BY StudentLastName, StudentFirstName
BETWEEN
The SQL BETWEEN operator is useful when you want to search over a range of values. Recall the query from the preceding section where you queried out students who were in grade 10, 11, or 12. Another way to accomplish the same thing would be to use the following: SELECT StudentLastName, StudentFirstName FROM Students WHERE StudentGradeLevel BETWEEN 10 AND 12 ORDER BY StudentLastName, StudentFirstName
The WHERE clause that uses BETWEEN will be inclusive of values that defined the range you’re searching over, so the preceding query picks up students in grades 10 and 12 as well. Using BETWEEN is essentially a shorthand way of writing SELECT StudentLastName, StudentFirstName FROM Students WHERE (StudentGradeLevel >= 10) AND (StudentGradeLevel <= 12) ORDER BY StudentLastName, StudentFirstName
TIP BETWEEN tends to be most useful with numeric and date/time fields where you have a clear sense of
what it means to be between two numbers or two dates.
LIKE
The SQL LIKE operator scans through a text field looking for a match to a pattern that you specify. You have probably seen directory searches in which you can type the first letter of a last name and see all last names
104
Chapter 4: Interacting with Databases: Retrieving Data
beginning with that letter in the results. The following query shows how to do this: SELECT StudentLastName, StudentFirstName FROM Students WHERE StudentLastName LIKE ‘M%’ ORDER BY StudentLastName, StudentFirstName
The LIKE operator is followed by the pattern you want to match. In this case, the pattern is M%, which also has to be enclosed in single quotation marks because StudentLastName is a text field in the database. The pattern says that you want the student’s last name to start with M, and you don’t care what comes after it. Thus, the query will select the first and last names of only those students whose last names start with M. The % sign acts as a wildcard character for the LIKE operator. It can represent any number of characters, including no characters at all. You also can use the underscore character (_) in a pattern to represent any single character. DISTINCT
If you run the following query SELECT StudentLastName FROM Students
you get a copy of each student’s last name, regardless of whether some students share the same last name. Thus, you could end up with multiple copies of the same name. To eliminate these duplicates, you can use the SQL DISTINCT operator as follows: SELECT DISTINCT StudentLastName FROM Students
AGGREGATE FUNCTIONS The SQL aggregate functions perform a mathematical operation on all the values in a numeric field of your database table. The following aggregate functions are available: • COUNT—Returns the number of records in the table that meet a specified condition • MAX—Returns the largest value from a field • MIN—Returns the smallest value from a field • SUM—Adds up all the values in a field and returns the result • AVG—Returns the average of the values in a field
Retrieving Information from a Database
105
To find the highest grade point average in the Students table, for example, you would use the following: SELECT MAX(StudentGPA) AS HighestGPA FROM Students
The aggregate function MAX identifies the highest value in the StudentGPA field and then the SQL AS operator gives this value the special name HighestGPA. Use of the AS operator to rename a quantity queried out of the database is called aliasing. As another example of aliasing, consider the following query: SELECT AVG(StudentGPA) AS OverallGPA FROM Students
The preceding SQL statement would compute the average of all GPAs in the table, and the result would be stored in the query variable called OverallGPA. If you want to limit the computation to just those students in grade 12, you could add a WHERE clause as follows: SELECT AVG(StudentGPA) AS OverallGPA FROM Students WHERE StudentGradeLevel = 12
The aggregate function COUNT is a little different in that you very often use an asterisk (*) as the field it operates on. For example, to determine how many students have GPAs of 3.0 or higher, you would use the following: SELECT COUNT(*) AS DeansListCount FROM Students WHERE StudentGPA >= 3.0
With the basics of how to compose a SELECT query under your belt, you’re now ready to move on to the tag, which sends an SQL query on to the target database for processing.
Using has both opening and closing tags, and the SQL statement you want executed goes between the tags. also requires the datasource attribute, which you use to tell ColdFusion which data source you want the query executed against. A sample command might
look like this: SELECT ProductName, ProductPrice FROM Products WHERE ProductInStock = 1 ORDER BY ProductName
106
Chapter 4: Interacting with Databases: Retrieving Data
When you create a SELECT query like this, the data returned from the database will go into a query variable in ColdFusion’s memory. To facilitate your access to the data in the query variable, you should give the variable a name using the name attribute of the tag as follows: SELECT ProductName, ProductPrice FROM Products WHERE ProductInStock = 1 ORDER BY ProductName
After the preceding query executes, the data requested from the database will reside in a ColdFusion query variable named qGetProductData. TIP Making all your query names start with the letter q is good practice. This convention helps you to remember that the name refers to data returned from a query. ✔ To learn more details about the different types of data sources, see “Setting Up Data Sources,” in Chapter 1.
ColdFusion assumes you’re interacting with an ODBC data source. If you aren’t, you can use the dbtype attribute of the tag to indicate a different kind. For example, if the data source inventory in the preceding query were an OLE DB data source, you would write the command as follows: SELECT ProductName, ProductPrice FROM Products WHERE ProductInStock = 1 ORDER BY ProductName
has several other attributes that are useful in certain situations:
• maxrows—This attribute puts a limit on the number of records that the query can retrieve. This capability can be useful when a user is searching a very large database and you want to keep the amount of information coming back to him manageable. Very often, this attribute’s value is something you let users specify on the form they fill out to initiate the search. • username, password—Some data sources are password-protected to keep unauthorized users away from sensitive information. If you establish a password-protected data source, you need to give
Retrieving Information from a Database
107
ColdFusion username and password information so that it can connect to the data source and execute the desired query for you. • timeout—This attribute specifies the number of seconds the query has to run to completion. If the query does not finish within the allocated time, ColdFusion produces a timeout error. If you use the timeout attribute, the value you specify there will override any timeouts set through the ColdFusion Administrator. • cachedwithin—This attribute allows you to cache the results from a query in the server’s memory for a span of time that you specify. This capability can enhance the performance of your server by eliminating the need to keep establishing connections to your data source and repeat the same queries again and again. When query data is cached, the data can be retrieved much more quickly from the cache than it can be retrieved from the database. After a tag is processed, ColdFusion creates several variables and associates them with the name that you gave to the query. These variables include the following: • RecordCount—The number of records returned by the query • CurrentRow—The number of the record that ColdFusion is currently focused on • ExecutionTime—The amount of time in milliseconds that the query took to run • ColumnList—A comma-delimited list of the retrieved database fields. You very often use the RecordCount property immediately after the query to determine how to respond to the user, as shown in the following code excerpt: SELECT ProductName, ProductPrice FROM Products WHERE ProductInStock = 1 ORDER BY ProductName
#qGetProductData.RecordCount# products found!
108
Chapter 4: Interacting with Databases: Retrieving Data
No products found!
The initial uses the value of qGetProductData.RecordCount to determine whether any records exist. If RecordCount is zero, this result is interpreted as a Boolean FALSE and the user is informed that no records were found. Otherwise, RecordCount is some number that is larger than zero, which is interpreted as a Boolean TRUE. In that case, you output the value of RecordCount to tell the user how many records you’ve found. By using combinations of the attributes discussed in this section together with your knowledge of how to compose SQL SELECT statements, you can write commands that retrieve exactly the data you want from any data source. After the data is returned to ColdFusion, you’ll then want to do something with it. The next section shows you how to use data in a query variable to create many different kinds of HTML output.
Outputting Query Results A tag can retrieve data from the database for you, but to get that data out of ColdFusion’s memory and onto a Web page, you have to use the tag you learned about in Chapter 2, “Variables and Variable Scope.” In this case, however, you can add a query attribute to the instruction to tell it to use data from your query to create the output. When you give a set of query results to work with, it will generate one piece of output for each record that was retrieved by the query. This means you can generate a lot of HTML output with a very small amount of CFML code. To illustrate the point, consider the following short example: SELECT ProductName, ProductPrice FROM Products WHERE ProductInStock = 1 ORDER BY ProductName
The instruction outputs each product name and price on its own line in the resulting Web page. If 5 products are retrieved from the database, only 5 lines of output are created. If 500 products are retrieved, ColdFusion generates 500 lines of output. After output is generated for each retrieved record, the instruction is over, and ColdFusion moves on to whatever instruction comes next. Of course, you can generate much more interesting HTML output than just individual product names and prices on their own lines of the document. The next three examples show you how to construct an HTML list, table, and form drop-down list by using with a set of query results.
Example: Creating Bulleted or Numbered Lists Listing 4.1 shows a query that retrieves customer data from a database and how you can generate a bulleted list of customer names from the output. Sample output from the script is shown in Figure 4.1. Listing 4.1
Generating a Bulleted List of Customer Names
SELECT CustLastName,CustFirstName
110
Chapter 4: Interacting with Databases: Retrieving Data
Listing 4.1
continued
FROM Customers ORDER BY CustLastName,CustFirstName Generating a Bulleted List from Query Data
Customer Listing
#CustLastName#, #CustFirstName#
To produce a numbered list, simply change the
and
tags in Listing 4.1 to and tags, respectively. CAUTION Make certain that you put inside only what you want repeated. For bulleted or numbered lists, only the
tags need to be generated for each record retrieved by the query. If you put the
or tags inside , you will get some undesirable results! Figure 4.2 shows what happens if you put the and tags inside . Notice that each customer name appears in its own numbered list, each starting with 1. This numbering occurs because ColdFusion generates multiple tags as well, and each new tag starts a new numbered list.
Outputting Query Results
111
Figure 4.1 The tag repetitively generates output when given data from a query.
Figure 4.2 Putting too much code inside your can produce unintended results in your final page.
112
Chapter 4: Interacting with Databases: Retrieving Data
Example: Creating an HTML Table If you’ve ever coded an HTML table by hand, you know what a tedious chore it can be. ColdFusion can generate HTML code for tables populated with database information by using together with results from a SELECT query. In this case, generates one table row for each record retrieved by the query. Listing 4.2 shows you how to create such a table. Listing 4.2
Generating an HTML Table of Customer Data
SELECT CustLastName,CustFirstName,CustCompany,CustTitle,CustCity,CustState FROM Customers ORDER BY CustLastName,CustFirstName Generating an HTML Table from Query Data
Customer Listing
Name
Title
Company
Outputting Query Results
Listing 4.2
113
continued
Location
#CustLastName#, #CustFirstName#
#CustTitle#
#CustCompany#
#CustCity#, #CustState#
Figure 4.3 shows some sample output from the script. Note that the column headings are automatically bold and centered within their cells. This formatting is handled automatically by the
tag.
Example: Creating a Drop-Down List in a Form As a final example of output you can create using and query data, consider a drop-down list in an HTML form. Often these lists are static because the options in them are unchanging. A good example would be a field in which you indicate your state of residence. In the U.S., such a list would contain all 50 states plus the District of Columbia and would not be likely to change anytime soon. On other occasions, though, your drop-down lists must be dynamically generated. For example, you might offer the user a drop-down list of the customers in your database. The user picks a customer and then sees that customer’s entire record. Listing 4.3 illustrates how you can create this kind of form element.
114
Chapter 4: Interacting with Databases: Retrieving Data
Figure 4.3 ColdFusion enables you to easily build an HTML table that displays your query data. Listing 4.3
Generating an HTML Form Drop-Down List
SELECT CustLastName,CustFirstName FROM Customers ORDER BY CustLastName,CustFirstName
Outputting Query Results
Listing 4.3
115
continued
Generating an HTML Form Drop-Down List from Query Data
Customer Listing
Figure 4.4 shows what the resulting drop-down list might look like. If you pick a customer and click the submit button, the customer’s first and last name will be submitted to the processing script called showcustomerdetail.cfm. However, using this approach can be a problem if you have two customers with the same first and last names. If eight customers are named John Smith and you pick one of them, how can the processing script know which one of the eight you picked?
116
Chapter 4: Interacting with Databases: Retrieving Data
Figure 4.4 A dynamically created drop-down list lets users choose a record from your database for further review. The way around this problem is to use the value attribute of the