UNIT 7 – “MYSQL” – ESSAYS INTRODUCTION TO MYSQL MySQL is an open-source relational database, which means that the source code is available on the internet. Once installed and started, the software responds to requests to create a new database, build tables in the database, and respond to queries about information stored in the tables. MySQL also includes provisions to create and authenticate users and allocate permissions among the users so that only some users can access some databases, and some users could read data, others can read and insert data and still others can create and delete tables and databases, for example. MySQL is one example of a relational database server. There are a variety of other products that provide effectively the same facilities. They differ in how quickly they can store and retrieve information and how they can manage data and how that data can be distributed across different machines (clusters of computers), among other features. In the next three essays you will learn enough that you know more about databases and their capabilities than most engineers, computer scientists and business people, but an awful lot less than the people who manage databases for a living. MySQL is a server responding to requests on port 3306 (by default) on a computer, just like HTTP responds to requests for web pages on port 80. There are several ways to establish a connection with the server. For example, when MySQL is installed in comes with several programs to connect and work with the database. You can also download programs from the internet to interact with a MySQL database. Each program is designed to make a particular type of interaction more convenient. The two that we will focus on are: 1) an integrated development environment called MySQL Workbench, and 2) the mysql function calls available in the PHP language. All of the programs that interact with MySQL ultimately send a series of commands in the SQL programming language. THE SQL LANGUAGE SQL stands for “Structured Query Language.” There is no complete standard for this language, which is used by many popular databases, including Oracle products, Microsoft Access, Sybase and several others. MySQL is a well-known variant of this popular relational database programming language. The portions we will cover are generally standard across all of the variants for other SQL databases. Regardless of the connection that is being used to communicate with the MySQL server, ultimately the commands sent to the MySQL server are strings in MySQL. Thus, if you understand what the language does, you will understand what different packages can do with your database. SQL is a rich language which can express very complicated actions on the database. The Data Definition portion of the language provides for define how the database is structured and what type of information can be stored. The Data Manipulation portion of the language defines what information should be added, retrieved, updated or deleted from the database. In a large 172 database, such as the one used by the University Registrar, very few of the user community ever interacts with the data definition portion of the language; most are trying to add and select information from the database rather than reorganizing it. MySQL sentences begin with a single-word command. The principle ones that we’ll use are USE, SHOW, CREATE, DROP, ALTER, SELECT, INSERT, UPDATE, and DELETE. MySQL is not case sensitive, but traditionally the MySQL keywords are typed in all uppercase characters. The MySQL 5.5 Manual is available online. The MySQL server maintains several databases simultaneously. The USE command selects which database you want to work with. The CREATE, SHOW, DROP and ALTER command permits the creation of new tables and users for the database. These are the main commands for the Data Definition Language. Generally these are followed by the names or tables, users, and columns, permitting the creation or modification of the structure of the database. The SELECT, INSERT, UPDATE and DELETE are the main commands for the Data Manipulation Language. Typically these are used to access or modify database rows. The commands facilitate complex specifications of exactly what data is required and which columns of the rows are affected. In most cases, the SELECT command, which provides information from the database, is used most frequently. It returns a table of information, including all the columns of data for the rows that match the query search criteria. The MySQL workspace will provide an interface to practice with SQL. THE MYSQL WORKSPACE Use the VMWare View Client to connect to vdi-beta.engineering.uiowa.edu. WAMP (Windows Apache, MySQL and PHP) has been installed on this machine, and with it came the MySQL Workspace. Open the Workspace by opening the program menu and looking for the MySQL directory. Launch MySQL Workspace. The workspace facilitates three types of operations: SQL Development, Data Modelling and Server Management. You may find the Data Modelling facility useful for developing your entity relationship diagrams. To practice SQL commands, however, the SQL development area will be the most useful. First, connect to the database. Since our MySQL server is running on the same machine as the workspace, we can connect to it through the special IP address localhost, or 127.0.0.1. Our username will be root, which provides complete control over the database. The password is ‘isdmysql’. If you wanted to connect to a remote server (perhaps one for your company), you could enter in its IP address and your account name on that server. If you have already created a connection in an earlier session, you can double-click on it to create the connection. Once you are connected to your server, new display should be visible. 173 The region on the left lists the tables that are currently in the database. The largest region in the upper middle of the screen will allow us to send MySQL commands. The region at the bottom provides feedback and error messages. Begin by exploring the world database listed on the right. This is a standard database used to teach and test database skills. Clicking on the arrow next to world reveals three new options: Tables, Views and Routines. Tables are the database elements that hold information in a database. Views are alternative representations of the basic tables provided to facilitate common searches. Routines are stored procedures used when interacting with databases. Click on the tables to reveal the three tables that have been defined for this database: city, country and countrylanguage. Clicking on the arrow next to the city table reveals options for columns, indexes, foreign keys and triggers. The columns will include the definition of each of the columns in the city table. Indexes refers to columns that are well suited for identifying individual rows. Foreign keys refer to columns that reference other tables (that’s not been set up for this table, even though we’ll see that CountryCode refers to rows in the Country table). Triggers refer to procedures that should run automatically whenever a change has been made to the table. Click on the Columns box to reveal that the City table has five columns: ID, Name, CountryCode, District and Population. The details for how each column is defined can be viewed in the Information Box below the Object Browser. For example, the CountryCode column is defined to hold 3 characters (“char(3)”). The image below shows how your screen might look at this point. 174 So far this exploration of the world database has been facilitated through the workspace interaction facilities, which have hidden the SQL commands used to communicate our intentions. The central box facilitates direct interaction through the SQL facilities. PRACTICING WITH MYSQL The MySQL server will supply the names of the databases available with the command: SHOW Databases; After you type this command into the query panel, press control and enter together or select the lightning bolt on the toolbar at the top of the frame. This command returns a list of databases available on the server. Like many SQL commands, the result of the command is a table of information. In this case the table has just one column called Database. The workspace tool shows this result in a new tab below the main box. The USE command selects one of the databases to work with. To work with the world database, type USE world Next, list the tables in the world database with the SHOW command again: SHOW Tables; 175 This should reveal the table’s three tables: city, country and countrylanguage. SELECT The SELECT command displays the information within a table. To get a list of all the rows in the city table, for example, type: SELECT * FROM `city`; The asterisk in the SELECT command on the city table indicates that the command should return all the columns in the table. The table has five columns: ID, Name, CountryCode, District and Population. By scrolling down in the results tab, we can see that there are 1000 rows in the city table. There are actually 4079 rows, but the workspace is quietly limiting the result to a reasonable number of 1000. In most cases, only some columns and some rows will be needed from a table. To modify the select query to provide just some rows, replace the asterisk with a comma-separated list of columns. It is good form to distinguish column and table names by surrounding them with grave accent. On most keyboards, the grave accent is found to the left of the one key. Don’t confuse this with an apostrophe, which on the double quote key. The use of the grave accent avoids potential confusion between table and column names and SQL keywords. To select just the Name and District columns, for example, type: SELECT `Name`, `District` FROM `City`; 176 There are several options to avoid returning all 1000 rows from the City table. One is to use a where statement to refine the search to rows that meet a particular criterion, such as: SELECT `Name`, `District` FROM `City` WHERE `Population` > 1000000; which returns just 237 rows, or SELECT `Name`, `District` FROM `City` WHERE `Name` LIKE 'H%'; which returns just 159 rows, each of which represent a city whose name begins with the letter H. Combining both of these conditions: SELECT `Name`, `District` FROM `City` WHERE `Name` LIKE 'H%' AND `Population` > 1000000; returns just 12 cities whose names start with an "H" and have a population greater than one million, including Houston, Ho Chi Minh City and Hiroshima, to name a few. INSERT The INSERT statement permits additions to a table. The command specifies the table accepting the new data and the columns in which the data will be placed: INSERT INTO `City` (`Name`, `District`, `Population`, `CountryCode`) VALUES ('My Town', 'Nirvana', 123456, 'NON'); This adds a new city with the name "My Town" in the district "Nirvana" with a population of 12345 to the City table. The ID is automatically generated in this case. Primary keys don't have to be automatically generated, but it is often convenient to do so. The CountryCode is "NON" which is a problem, because the Country Code is supposed to correspond to a Code in the Country table as a foreign key. However there is no country with that code, so the database is now broken, with a bad reference. It is possible to set up the database to prevent a row with a bad reference being added by mistake, but it can get complicated. DELETE The DELETE command will allow us to remove the offending rows from the table. First let's find out what the ID is of the offending line: 177 SELECT * FROM `City` WHERE `CountryCode` = 'NON'; returns a row with ID 4080. DELETE FROM `City` WHERE `ID` = 4080; removes the row. Be careful with deletions. It is best to confirm that you have the correct primary key with a separate select statement. Running the select query again confirms that the row is gone. JOIN STATEMENTS A relational database would not be very useful unless it was possible to combine information from multiple tables. The Join statement is designed to make this task relatively easy. The fundamental idea is to combine two tables into a single large table, rows or portions of rows as necessary in order to make a complete table. As an example, consider combining the city table with the country table. Each city has a countryCode which corresponds to a unique row in the country table. The country table has the following columns: Code, Name, Continent, Region, SurfaceArea, and many more. A join between the city and country table would have columns for all the city table (i.e., ID, Name, CountryCode, District and Population) plus all the columns for the country table (i.e., Code, Name, Continent, Region, SurfaceArea, etc.). Each row for a city in the US will contain country information that is redundant with the other rows for US cities. To make the join work, we need to specify the names of the two tables and which columns should correspond between the two tables (typically a primary key for one and a foreign key for the other). For example: SELECT * FROM `City` JOIN `Country` ON `City`.`CountryCode` = `Country`.`Code`; returns a table with 1000 rows (limited by MySQL Workbench). Each row has 20 columns. A WHERE statement can refer to any of these columns. Often it is necessary to completely specify the source table and name when referring to columns, such as `Country`.`Population` in order to avoid confusion with, for example, `City`.`Population`. CONCLUSION MySQL is a rich language for interacting with databases. Some professionals focus their entire career on databases, particularly how to modify and optimize database queries. While this lecture only scratches the surface of the language's full capability it should have provided you with a functional idea of the main factors that are involved and how those pieces fit together. 178 MYSQL QUERIES The success of any database user depends on their mastery of the query. This depends in turn on the quality of the design of the database, the depth of the user's understanding of that design, and his or her ability to intelligently employ the rich options available in the query language. A talented worker can extract impressive insights from a complex database. A query has five major parts: 1. the definition of the columns to return, including functions used to process columns grouped together 2. the definition of the table to select from, including temporary tables created by complex join and nested queries 3. the where clause which restricts the rows that will be returned, 4. the group by statement, that can cluster multiple rows into a single row, and 5. the order by statement, which can be used to prioritize the result. DEFINING THE RETURN COLUMNS The columns of the resulting table will be returned in the same order in which they are declared in the SELECT statement. As we saw in the introduction an asterisk specifies that all of the table's columns should be returned. If multiple tables are joined in the query, it may be necessary to specify table and column names with a period between to avoid ambiguity. For example if products and vendors both have a column called ID it is necessary to specify either `product`.`id` or `vendor`.`id` in the column list. Sometimes it is convenient to rename a column, particularly when a specification becomes unwieldy. The AS designator is useful in this case. For example: SELECT `product`.`id` AS `productID`, `vendor`.`id` AS `vendorID` FROM `product` JOIN `vendor`; The DISTINCT modifier, placed before the list of desired columns, restricts the result so that only unique rows will be returned, duplicate rows will be ignored. For example, in the world database, a query to find the country code of all the countries that have a city with a population larger than 5,000,000 could be written thus: SELECT DISTINCT `CountryCode` FROM `City` WHERE `Population` > 5000000; Without the distinct specification, the query returns 24 rows, because six of the rows are repeated for countries that have more than one mega-cities (e.g., for India and China). With the DISTINCT keyword, only 18 rows are returned. 179 AGGREGATE FUNCTIONS The select statement can perform calculations on a column. For example, the following statement calculates the combined population of the large cities mentioned in the last example: SELECT SUM(`Population`) FROM `City` WHERE `Population` >5000000; yields a one-column, one-row table with the value 182,700,153, the total population of the 24 largest cities in the world. A similar query provides the total world population: SELECT SUM(`Population`) FROM `Country`; yields 6,078,749,450. If we wanted to get the percent of the residents of small cities as a fraction of the total population, we could embed one query in the other, like this: SELECT SUM(`Population`)/(SELECT SUM(`Population`) FROM `Country`) FROM `City` WHERE `Population` >5000000; Note the the world population query is placed inside parentheses and embedded inside the large city query. The forward slash indicates division. The resulting query is again a single oneby-one table with the value 0.0301, which equals 182,700,153 / 6,078,749,450. SQL provides a variety of aggregating functions, which are listed in the table below: Name Description AVG() Return the average value of the argument COUNT(DISTINCT) Return the count of a number of different values COUNT() Return a count of the number of rows returned MAX() Return the maximum value MIN() Return the minimum value STD() Return the population standard deviation STDDEV() Return the population standard deviation SUM() Return the sum VARIANCE() Return the population standard variance The usual mathematical operations are also supported, as well as many numerical functions, including SIN, POWER, SORT and the like. 180 TABLES, JOINING AND OTHER DATA SOURCES The select statement must refer to a data source. The simplest source is a table. Other sources include several tables joined together or the result of another query enclosed in parentheses. The JOIN command combines tables, typically through foreign key to primary key relationships. The resulting combination includes columns from both of the joined tables. For example, SELECT * FROM `address` JOIN `customer` ON `address`.`customerID` = `customer`.`customerID`; creates a table with all the columns from the address table and all the columns in the customer table. This example presumes that each address has a customerID field that corresponds to a customerID field in the customer table. The resulting table includes one row for each address. In each row in the resulting table, the information from the address is copied into the address columns. The rest of the row is filled with the corresponding information from the customer table. There are several types of joins. They differ in how they handle references where a value in one table has no corresponding value in the other, such as a foreign key that has no corresponding primary key in the joined table, or a primary key that has no matching foreign key in the corresponding table. The basic JOIN statement is properly an inner join. This means that only rows that match the criteria are created. If there is a foreign key with no matching primary key or a primary key with no matching foreign key, for example, the orphaned information is not included in the resulting table. The other types of such as LEFT JOIN and RIGHT JOIN provide extra rows that include the orphaned information from either the left or right tables, with NULLs in the columns from the other table when no match is found. NESTED JOINS Often the JOIN statement is nested so that the results of one JOIN is used as a table for another. For example, consider three entities: Order, Ordered Product and Product, as illustrated below. 181 Consider the problem of producing a list of all the products ordered by a particular customer. The Order and Ordered Products table can be joined thus: SELECT * FROM `Order` JOIN `OrdreredProduct` ON `Order`.`OrderID` = `OrderedProduct`.`OrderID`; This produces a complete list of all the CustomerID's, Dates, OrderID's from the Order table with the corresponding OrdProdID, ProductID and Quantity from the `OrderedProduct` table. The following statement extends this to include the corresponding name and price from the Product table by using the result as the first table in a subsequent JOIN: SELECT * FROM (`Order` JOIN `OrderedProduct` ON `Order`.`OrderID` = `OrderedProduct`.`OrderID`) JOIN `Product` ON `OrderedProduct`.`ProductID` = `Product`.`ProductID`; Assuming that all the keys have been properly set, this yields a table listing one row for every row in the ordered product table augmented with the details of the order and the product. The whole select might then be augmented to select individual rows with a WHILE statement, for example. THE WHERE STATEMENT The WHERE statement determines which rows will be returned. The conditional statement following the WHERE keyword can be a complex logical expression combining the following logical operators: OR, AND, XOR, NOT, &&, ||, ! each with their usual meanings inherited introduced in C and PHP. The IS operator can be used to determine whether or not a value is set to NULL, for example: SELECT * FROM `myTable` WHERE `col1` IS NULL; 182 or SELECT * FROM `myTable` WHERE `col1` IS NOT NULL; Comparison operators allow variables to be compared, again following the patterns introduced for PHP: =, >=, >, <=, <, <>, != The IN operator allows variables to be compared against a comma separated list: SELECT * FROM `Customer` WHERE `Customer`.`lname` IN ("Smith", "Thomas", "Zoolander"); or, with the NOT operator: SELECT * FROM `Customer` WHERE `Customer`.`lname` NOT IN ("Smith", "Thomas", "Zoolander"); The BETWEEN operator works similarly, except identifying values that are alphabetically between two values: SELECT * FROM `Customer` WHERE `Customer`.`lname` "Thomas"; BETWEEN "Smith" AND Among the most powerful operators is LIKE, which finds alphabetical matches. LIKE supports various wildcards. The '%' wildcard matches zero or more characters of any type. The '_' wildcard (underscore) matches one character. Enclosing a series of characters in square brackets will match with any character inside the brackets. If a '^' or '!' character is the first in the list, then the square bracket term matches any character not in the list. For example: SELECT * FROM `Customer` WHERE `Customer`.`lname` LIKE "[TS]%"; will match any row in the Customer table where the lname column holds a value beginning with T or S, but not match any of the other rows. 183 SELECT * FROM `Customer` WHERE `Customer`.`lname` LIKE "[!T]_%"; matches any row in which the lname column holds a string with at least two characters, the first of which is anything except 'T'. GROUP BY Columns selected for output can be listed after the GROUP BY operator. All the rows with matching columns will be combined, which is sometimes helpful with the aggregation operators. For example: SELECT customerID, SUM(`totalPrice`) FROM `invoice` GROUP BY `customerID`; would provide a list of each customerID that appears in the invoice table, followed by the sum of all the totalPrice values corresponding to that customerID. If several columns are designated in the GROUP BY list, then the result will be sorted by both columns. ORDER BY The ORDER BY operator allows rows to be sorted in either ascending or descending order. For example: SELECT customerID, product FROM `invoice` ORDER BY `customerID`, product DESC; will list all the customerID and products from the invoice table by customerID and products in descending order. CONCLUSION The SELECT operator is a powerful tool for exploring the information in a database and calculating nearly any value or set of information from the data. It is surprising how few engineers and researchers have mastered this technology, given the relative importance of information and our access to information in the modern world. Hopefully this introduction has given you a small taste of what can be accomplished. This is also the last essay for the course. You have now been introduced to all the technology that is necessary to make an interactive website that combines the power of a database with an open-ended interface that can be accessed from nearly any computer in the modern business world. There is a virtually unlimited array of things that you might accomplish with these technologies. Use your newfound power to accomplish good things and to improve the human condition. 184 Happy programming. 185 CREATING A DATABASE Creating and altering tables and columns in a database is handled by SQL's Data Definition functions. The CREATE DATABASE command creates a new database. For example: CREATE DATABASE `myTest`; Creates a new database called myTest. There are no tables in the database when it is first created. Likewise, the CREATE TABLE creates a new table: CREATE TABLE `myTable`; However, a table without any columns will not be of much use. Generally the table and columns are defined together, in a parentheses-enclosed list following the table name. The column definitions are separated by commas. For each column, list the name of the column, the type of data to be stored in the column, then any modifiers. For example, to create a table with three integers, you could use the following statement: CREATE TABLE `myTable` ( `col1` INT, `col2` INT, `col3` INT ); Note that the Object Browser in the MySQL Workbench will not recognize that modifications have been made to the table until the refresh button is pressed in the upper righthand corner of the display. DATA TYPES MySQL has a rich array of different data types because it is important with a large database to pack as much information into as few bytes as possible. We'll focus attention on a few basic types: INT, DOUBLE, DATE, TIME, DATETIME Among the numeric types, integers (INT) can range from -2147483648 to 2147483647. Doubles are floating-point number. Permissible values are 1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and 2.2250738585072014E308 to 1.7976931348623157E+308. The date and time types include DATE, TIME and DATETIME. MySQL's native representation of date is 'yyyy-mm-dd', but it can convert from many other types. It may be most convenient to 186 do the format conversions within PHP, however. The native representation of time is in terms 'HHH:MM:SS'. The DATETIME field contains both the date and time in a single location. Normally a website tracks times and dates in terms of universal time and converts these to local time, but this is more complex than we will worry about for our projects. The string types include CHAR(N) for fixed-length strings and VARCHAR(N) for variable length strings. The N in each specifies the maximum length of the string. The limit is 255 for CHAR and 65,535 for VARCHAR. The TEXT type allows effectively unlimited size, but adds overhead. It is unlikely that this will be required in our projects. COLUMN MODIFIERS There are several optional modifiers that can be added after the data type for a column. The optional modifier "NOT NULL" specifies that a column cannot have the value of NULL. This feature prevents a row from being added without setting a value for the column. Using "NULL" instead allows the value to be empty, which is the default condition. The "DEFAULT" option followed by a number, date or string allows a default value to be set. When a row is added, if the column is not specifically set, then the default value will be used. The "AUTO_INCREMENT" option indicates that if no value is selected when a new row is added, then an integer one larger than the last integer will be used as the value. Typically an auto_imcremented column is not set when adding a new row. The UNIQUE modifier specifies that every row will have a different value in this column. The PRIMARY KEY modifier has its own row following the column definitions. This term designates the column that will serve as the primary key for the table. You should have at least one of these for each table. The PRIMARY KEY should also be UNIQUE and NOT NULL. It is also possible to specify that a column is a FOREIGN KEY followed by the name of the table.column that it references. This allows the database to check whether or not a foreign key exists. This feature can add complications in the order in which data must be added to the database and requires the specification of a particular table storage approach, so we will not use this feature. EXAMPLE CREATE TABLE The following code fragment is what MySQL uses to create the city table in the world database. Note that each column has its own line. CREATE TABLE `city` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `Name` char(35) NOT NULL DEFAULT ' ', `CountryCode` char(20) NOT NULL DEFAULT ' ', `Population` int(11) NOT NULL DEFAULT ' ', PRIMARY KEY (`ID`) ) 187 DROPPING DATABASES AND TABLES You can remove a database with the command: DROP name where name is the name of the database. In a similar manner, you can drop a table with the command: DROP TABLE Name Obviously you can cause a lot of mischief by dropping the wrong database or table, so be careful. With awesome power comes awesome responsibility. BACKING UP YOUR DATABASE Given your newfound awesome power, you may want to learn how to backup and restore your database. This will also be helpful when sharing your database with other group members. To do so, return to the MySQL Workbench, but choose the righthand column for server administration. Create a connection to your database, then double click to administer that database. Then select Data Export from the left side of the menu. Your screen should looks something like this: 188 Select the database you want to backup, then choose the "Export to self-contained file" option in the lower part of the screen and choose the name and location of the backup file you want to create. Name it with a ".sql" extension, because it will be written as an SQL script. The start export button on the lower right creates the backup. You can open the file with any text editor to see the result, which should look familiar to you now that have learned how to create tables. To import the database, select Data Import/Restore option on the lower left of the screen, select the import from self-contained file option, then click Start Import. It may be a wise idea to backup and restore regularly and to store your backup file in the subversion repository with your other project files. WORKING WITHIN PHP The manual for mysqli is here. There are two versions for practically every action, one which uses objects and one which doesn't. We’ve avoided using objects to this point, because most of you have not encountered object-oriented programming before. However, since the version of the library that uses the C-style function calls is deprecated, we need to introduce the objectoriented style. The heart of this style is the connection object that is returned with your first call to the mysqli library. The first step is to make a connection between your PHP script and a mysql server with the mysqli_connect() function, which returns a connection object. The function can take four string arguments: 1) the URL of the mysql server, 2) the login name for the connection, 3) the password, and 4) the name of the database. We will use the “root” password, which generally provides complete access to the database. In a real development environment, care is usually taken to employ user names with access restricted to just what is needed. We’ve also set up the virtual machines with the root password “isdmysql”. $db = mysqli_connect("localhost","root","isdmysql","world"); The mysqli object stored in $db contains not only the information about the connection, but also a suite of methods, or algorithmic procedures, that can act on the object. Thus the connection object, like most objects in object-oriented programs, represents both information and actions that can be performed on that information. To access the methods of the connection object, you can use the pointer arrow, provide the name of the method you want, and provide any parameters the method needs in parentheses. To access elements of information stored in the object (similar to the way that a C-structure stores several pieces of information within a structure), you can use the pointer arrow and name the information you want. For example, the mysqli object stores a parameter called connect_errno, which, if not zero, designates a particular kind of error that the library encountered when opening the connction. It also stores a parameter called connect_error that describes the error as a string. We can use these to figure out what when wrong when opening the connection: if ($db->connect_errno) { printf("Connect failed: %s\n", $mysqli->connect_error); exit(); } 189 Assuming that the connection works, the query method is a method you will use quite often. It sends a query to the database. For example: $result = $db->query("SHOW Tables"); In this case the database response is used to create a new object called result. Since the database generally responds with an array of information, the $result object can be fairly complex. If you send a bad query, the response is set to false, meaning that no object is created at all. In that case, we can test the database object to find out what the error was. SHOW tables is an appropriate query, so it is created. One of the result object's attributes is its number of rows. Here's a code fragment that will test whether the query was successful and provides the number of rows in the answer: if ($result == FALSE) { echo "Error. Bummer. $db->error"; } else { echo "The result has $result->num_rows rows"; } There are many ways to access the rows and columns in the returned table, but the least complicated is the fetch_all() method, which returns an array of the results. By default the columns of the array will be indexed from zero to the number of columns. The SHOW Tables query has only one column (indexed by the value 0), which a foreach loop can easily print: $table = $result->fetch_all(); foreach ($tab as $row) { echo "<li>$row[0]</li>"; } Here's a more complex example: $result = $db->query("SELECT * FROM `City` JOIN `Country` ON `City`.`CountryCode` = `Country`.`Code`"); if (!$result) { echo "Error. Bummer. $db->error"; } else { echo "The result has $result->num_rows rows"; } $table = $result->fetch_all(); echo "<table>"; 190 foreach ($tab as $row) { echo "<tr>"; foreach ($row as $col) { echo "<td>$col</td>"; } echo "</tr>"; } echo "</table>"; In many websites it is desirable to allow user input to become part of the search query, such as allowing the user to search for products beginning with a particular series of letters. Such an interface provides and opportunity for mischief on the part of the user, who might, rather than using a typical series of letter to search for, intentionally use SQL commands in their text, in order to fool the website into revealing information it did not intend to reveal, for example. On way to avoid this type of attack is to use prepared mysql statements. These statements set up the form of the query, for example finding customer id and address based on the first few letters of the last name, but leaving the actual search term value, in this case the actual letters of the name, undefined until the moment the query is called. Thus the technique “prepares” the query before it is actually ready to be run. A happy advantage of this approach is that it is much less susceptible to the mischief mentioned above. The sample below demonstrates a prepared query as part of a class called posts. Note that the example makes use of another library available in PHP for accessing databases called PDO. It is provided here as an example of a more advanced programming technique that the reader might encounter in the wild. 191 192 UNIT 7 – “MYSQL” – ASSIGNMENTS INTRODUCTION TO MYSQL – INDIVIDUAL ASSIGNMENT Objective: Learn how to make queries in MySQL Methods: Use the SQL Editor in the MySQL Workspace to practice MySQL. Write a multiline script that performs the following actions. 1. Select the world database. 2. Read all the rows and columns of the city table (the workspace will limit this to 1000 by default). 3. Read just three columns of country table. Choose the columns yourself. Be creative – don’t just choose the first three. 4. Read all the columns of the country table, but apply a where constraint that is a logical combination (e.g., using AND or OR) of both a numeric value and a string value. Again, be creative -- everyone’s constraints should be different. 5. Add a row to the city table 6. Delete the row that you just added to the city table. Be careful not to delete any rows that you did not intend to delete. Submission Requirements: Save the file with the MySQL commands as a .sql file extension and submit the file to the dropbox. Include in your submission screen shots of the results from each command. Submit a word document with the screen shots from the MySQL commands in addition to the MySQL file. Rubric: Ability of script to complete actions Poor Fair Good Excellent An attempt has been made but file only completes three actions or less Submitted script only fulfills four actions MySQL file completes all 6 actions Queries written with proper syntax in a concise manner 193 Quality of Submission MySQL Syntax and quality of code No screenshots of results included Confusing and hard to read Screenshots missing for two or more tasks Screenshots missing for one task Reasonably consistent, one or two minor syntax errors Easy to follow formatting Submission includes screenshots of all task results Elegant use, well commented code. 194 MYSQL QUERIES – INDIVIDUAL ASSIGNMENT Objective: Practice making more complex MySQL queries Methods: Write queries for the World database that accomplish the following. Save these in a single SQL file and submit them to the drop box. 1. Create all the languages, with a list of the number of people who speak each language, with the most frequently spoken language first. Count only official languages spoken in each country and account for the percentage of people in each country that actually speak the language. Assume that the percentage value in the countryLanguage field expresses the percentage of people in the country who speak that language. For example: Chinese 1191843539.22187 Hindi 405633085.47466 Spanish 355029461.90782 2. List the percentage of urban residents (e.g., the sum of a country's population in cities listed in the database divided by the population of the country) in order of the most urban countries first. 3. Create a list of all the cities in which Chinese, Hindi or Spanish is spoken by at least 50% of the residents of the country in which the city is located. If in City A, 25% of the residents of the country speak Hindi and 35% of the residents speak Urdu, assume that City A should be on the list. Submission Requirements: For this assignment please upload two files to the appropriate dropbox. Save your first file, with all of your MySQL queries with a .sql extension. Include with your submission a word document with screenshots of results from each task. Rubric: Ability of script to complete actions Poor Fair Good Excellent An attempt has been made but file only completes three actions Submitted script only fulfills two actions MySQL file completes all three actions Queries written with proper syntax in a concise manner 195 Quality of Submission MySQL Syntax and quality of code or less No screenshots of results included Confusing and hard to read Screenshots missing for two or more tasks Screenshots of results missing for one task Reasonably consistent, one or two minor syntax errors Easy to follow formatting Submission includes screenshots of results from all tasks Elegant use, well commented code. 196 CREATE A TABLE – INDIVIDUAL ASSIGNMENT Objective: Practice creating an ERD and MySQL database Methods: Create an ERD with two tables: contacts and addresses. Include a minimum of 8 fields. Make sure that the ERD has properly specified keys and is of third normal form. This portion of the assignment will be graded on whether or not the keys are correctly defined, the attributes are in the correct place, whether there are enough and the correct attributes to store all of the information you will need for your project, and whether the relationships between the entities are correctly formed. Once you have your tables diagramed, create an SQL script that will generate the tables in a database. You can use the automatic script creation features in the Workbench to do this, or create it on your own. This portion of the assignment will be graded based on whether or not the entities have been created correctly to perform the roles indicated in your diagram. Submission Requriements: Submit both the .mwb file from the MySQL Workbench editor and the .sql file with the creation script to the dropbox. Rubric: Poor Fair Good Excellent Scale of database Too few fields or a redundant number of fields, irrelevant names Database consists of 8 or more unique fields Concise table structure allowing useful queries Normal Form Database is not first normal form Good design but one or two minor changes would improve structure Database follows first normal form (all occurrences of a record type contain the same number of fields) Database follows second normal form (all non-key fields are facts about the primary key) Database follows third normal form (non-key fields are independent of each other) 197 Fully specified attributes Missing primary keys, foreign keys, or cardinality One or two errors such as a many to many relationship Primary and foreign keys as well as cardinality specified Attribute names make sense MySQL Syntax and quality of code Confusing and hard to read Reasonably consistent, one or two minor syntax errors Easy to follow formatting Elegant use, well commented code. 198 MYSQL TABLES & QUERIES – GROUP PROJECT Objective: Develop the first draft of your databases and queries for your group project. Methods: PART 1: TABLES 1.1 Use MySQL Workbench to create the tables for your final group project. Fill these tables with the information they require. For example, my table below is labeled “Books” several instances of products have been filled in for this table. Repeat this for all of your tables. You must have sufficient information in these tables to have a functional site. After you have filled your tables with information, create these tables using the tools in Workbench. Save this query you have created as an .sql file and submit it into the drop box. PART 2: QUERIES 2.1 After you have created your tables, it is time to consider how they will be used in your project. Hopefully you have been planning throughout the project so this part will be simple. 1. Write 1 query which will display all of the products (or entities) that you have inserted into your database 2. Write 3 examples of queries you will utilize in your search function. 3. Write 1 query that shows the first and last name of your users, alphabetized by last name. Copy these 5 queries to a text document and submit this to the dropbox. 2.2 List each query along with a written description you will be using in your website. These must be robust queries and utilize a JOIN statement. Be thorough. Describe which page each query will be used on. 199 2.3 Implement at least one of the queries you listed in 2.2 on your website. NOTE: For the final project you will be utilizing all of the queries you listed and, possibly, several more. Submission Requirements: Submit a zip file with the following: 1. An sql script called createTables.sql with a series of sql commands that create your database tables and fill them with data. 2. An sql script called sampleQueries.sql that contains a series of five queries that can be run on your that tables created in part 1. 3. A text file called plannedQueries.sql that contains a list of the queries you will need to finish in order for your website to work. 4. An sql script called completedQuery.sql that contains one of the queries described in 3. This example must include at least one join. Rubric: Poor Fair Good Excellent Coherent table design Not in 1st normal form or confused/ incomplete 2nd normal form, but not 3rd. Would probably work for project as is. 3rd normal form. Query structure The queries don’t work. In 1st normal form, but not 2nd. Possibly incomplete, but heading in good direction Most of the queries work, but one or two problems. Query plans The planned queries can’t work with the current table design. The problem is not recognized. The queries work, but could be made more concise or robust. The ideas are sound, though not completely specified or with one or two small flaws. Everything works well. No obvious improvements needed. Well structured plan that can be implemented on the tables. Sample query Doesn’t work or no join. Works, but has extraneous elements or is imprecise. Will work, as is, for the project. Joins are reasonable, but there are several important limitations that need to be resolved. Works, but only for one cherry-picked example. 200 MYSQL OPEN-ENDED MODIFICATIONS – EXTRA-CREDIT ASSIGNMENT Some of the MySQL topics that we needed to skip over because of the available time are views, procedures, functions and triggers. For your last open-ended assignment, learn about these capabilities and think about how they might have been helpful for your project. Finally, modify your project database to demonstrate how these techniques might have been used. Submit the exported version of your database. In the dropbox comments, include a description of how you used each of these techniques. 201