November 11 to 18 - ndgriffeth/Class-Notes-and-Lectures GitHub Wiki
Reading: Chapter 11: Accessing your MySQL Database from the Web with PHP
- Data types
- Updating tables
- Joins and subqueries
- Sorting, aggregating, and grouping
There are many different numeric data types. As a general rule, use the smallest that can represent all values needed.
- BIT [ (M) ]: a bit-type field; M is the number of bits, from 1 to 64 (default 1).
- TINYINT [ (M) ]: an integer that can be stored in a byte (8 bits). Signed range is -128 to 127. Unsigned range is 0 to 255. M is the number of bits.
- SMALLINT: an integer in the range -32768 to 32767 or 0 to 65535. Can be stored in two bytes.
- MEDIUMINT: an integer in the range -8388608 to 8388607 or 0 to 16777215. Can be stored in three bytes.
- INT: an integer in the range -2147483648 to 2147483647 or 0 to 4294967295. Can be stored in four bytes.
- BIGINT: an integer in the range -9223372036854775808 to 9223372036854775807 or 0 to 18446744073709551615. Can be stored in eight bytes.
- DECIMAL [ (M [,D]) ]: a number with M digits and D after the decimal place. Defaults to M=10 and D=0.
- FLOAT [ (M, D) ]: A small (single-precision) floating-point number. Permissible values are -3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to 3.402823466E+38. M is the total number of digits and D the number following the decimal point. Accurate to about 7 decimal places.
- DOUBLE [ (M, D) ]: A normal-size (double-precision) floating-point number. Permissible values are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and 2.2250738585072014E-308 to 1.7976931348623157E+308. Accurate to about 15 decimal places.
Except for BIT, all of the above types can be followed by the work "UNSIGNED" to specify that they will not have a sign, and thus have about twice as many positive values.
Exercises:
- How would you store a two-valued field? A 10-valued field? A 1000-valued field?
- How would you store a price?
- How would you store the population of a state?
- How would you store the temperature in Fahrenheit? Celsius? Kelvin?
Important data types:
- CHAR (M): up to M characters, with 0 ≤ M ≤ 255 (length can be represented in 1 byte). Strings are padded with blanks to the right to bring them up to M characters.
- VARCHAR (M): up to M characters, with 0 ≤ M ≤ 65535 (length can be represented in 2 bytes). These are stored as variable-length strings. Creating or changing a value will be slower as a result.
Exercises:
- Would you store first name and last name fields as CHAR or VARCHAR?
- Would you store a description field that could contain multiple paragraphs as CHAR or VARCHAR?
List of subtypes (see tables 9.7-9.8 in text):
- DATE: YYYY-MM-DD
- TIME: HH:MM:SS
- DATETIME: YYYY-MM-DD HH:MM:SS
- TIMESTAMP(M): YYYYMMDDHHMMSS for M=14 or first M characters of YYMMDDHHMMSS for M even
- YEAR[(2|4)]: YYYY or YY
A selection of functions on dates:
- CURDATE(): returns the current date.
- CURTIME(): returns the current time.
- NOW(): returns the current date and time.
- DATE_FORMAT(<date>,<format-string>): format date for printing, e.g., '%m/%d/%Y'
- STR_TO_DATE(<string>,<format-string>): convert a string in the given format to a date or date-time expression. If the <format-string> includes the date part only, the conversion is to a date; if it includes a time specification, the conversion is to a date-time.
- %m for numeric month.
- %d for numeric day
- %y for 2-digit year
- %Y for 4-digit year
- DATE(<date>), TIME(<date-time>): extract the date (time) part of a date or date-time expression.
- DAY(<date>), MONTH(<date>), YEAR(<date>): extract the specified parts of the date.
- HOUR(<date-time>), MINUTE(<date-time>), SECOND(<date-time>): extract the specified parts of the date-time or time expression.
You can also do arithmetic on dates:
- DATE_ADD(<date>, INTERVAL <num> <unit>): add <num> <unit>'s to <date>.
- DATE_SUB(<date>, INTERVAL <num> <unit>): subtract <num> <unit>'s from <date>.
Examples:
- Compare
mysql> SELECT DATE_FORMAT(CURDATE(),'%m/%d/%Y'); +-----------------------------------+ | DATE_FORMAT(CURDATE(),'%m/%d/%Y') | +-----------------------------------+ | 11/08/2013 | +-----------------------------------+ 1 row in set (0.00 sec)
andmysql> SELECT CURDATE(); +------------+ | CURDATE() | +------------+ | 2013-11-08 | +------------+ 1 row in set (0.00 sec)
mysql> SELECT CURDATE(), DATE_ADD(CURDATE(), INTERVAL 50 DAY); +------------+--------------------------------------+ | CURDATE() | DATE_ADD(CURDATE(), INTERVAL 50 DAY) | +------------+--------------------------------------+ | 2013-11-08 | 2013-12-28 | +------------+--------------------------------------+ 1 row in set (0.01 sec)
mysql> SELECT NOW(), DATE_ADD(NOW(), INTERVAL 50 HOUR); +---------------------+-----------------------------------+ | NOW() | DATE_ADD(NOW(), INTERVAL 50 HOUR) | +---------------------+-----------------------------------+ | 2013-11-08 16:11:58 | 2013-11-10 18:11:58 | +---------------------+-----------------------------------+ 1 row in set (0.00 sec)
Exercises:
- Format a date-time string to look like: November 10, 2013 06:00:00. You can test it using the NOW() function.
SELECT DATE_FORMAT(NOW(), <format>);
- Add 1,000,000 seconds to the current date and time.
- Convert the string '1/1/9999' to a date-time value.
The command to create a new database is:
CREATE ( DATABASE | SCHEMA ) [IF NOT EXISTS] <name>
If it exists, you get an error unless you specify "IF NOT EXISTS".
DATABASE and SCHEMA are synonymous.
The command to create a new table is:
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] <tbl_name> (<col1> <type1>, ..., <coln> <typen>)
For each table in the database, you have to pick a name, columns, and types for the columns. There are additional options for performance and integrity constraints, but the required choices are the table name, the columns, and the data types.
Exercises:
- Define a table Person with fields Birthdate (date type), Name (string type), and Age (numeric type). How long will you make the name? What string type will you use? What numeric type should you use for the Age? What is the command that defines the table?
- Define a table Order with fields OrderID (numeric type), CustomerID (numeric type), OrderDate (date type), ShippingDate (date type), and Amount (numeric type).
The insert command requires the table name, the column names, and the values. There are two options:
INSERT [INTO] <tablename> [<col1>, ..., <coln>] VALUES (<val1>, ..., <valn>]
or
INSERT [INTO] <tablename> SET <col1>=<val1>, ..., <coln>=<valn>
Exercises:
- Add the following rows to the Person relation:
Birthdate Name Age 1/6/1982 George Facello 31 2/24/1978 Parto Bamford 35 - Add a row to the employees table in the employees database, with the gender unspecified (you'll have to give the values for all of the other fields) and birth_date='1959-01-01'.
- Add a new row to the department table, for department "d010" named "Something".
The DELETE command specifies the table name and a condition that rows to be removed must satisfy:
DELETE FROM <tablename> WHERE <condition>
You can add a limit to the rows to reduce the risk you run if you make a mistake!
Exercises:
- Remove the row that you added to the employees table above.
- Remove all rows for employees over 65 (try computing this using the DATE_SUB function).
Like the DELETE, the UPDATE command lets you specify a condition. You could select a row having a given primary key, which will limit the update to a single row, or you can change a value throughout the database to another value. The actual uses are limited only by your imagination!
UPDATE <tablename> SET <col1>=<val1>, ..., <coln>=<valn> WHERE <condition>
Exercises: Change the to_date from '9999-01-01' to '9999-12-31'.
Example:
- Here is a query that finds the largest salary:
SELECT salary FROM salaries WHERE salary >= ALL (SELECT salary FROM salaries);
We'll find an easier way to do this later. - Here is a query that prints the name and salary of the employee with the largest salary:
SELECT first_name, last_name, salary FROM employees JOIN salaries USING (emp_no) WHERE salary >= ALL (SELECT salary FROM salaries);
The above is a pretty straightforward way of doing it -- the subquery selects the largest salary, and the WHERE clause in the outer query checks that the employee's salary is equal to the maximum. -
List employees that used to work for the company but are not working for it now.
SELECT first_name, last_name FROM employees WHERE emp_no NOT IN (SELECT emp_no FROM dept_emp WHERE to_date='9999-01-01');
There are several kinds of joins:
- INNER JOIN: We've already seen inner joins, which happen when two tables are "pasted together" on some columns -- often a foreign key in one table matched to a primary key in another.
Example: To list departments with their employees, you can use
SELECT dept_no, first_name, last_name FROM dept_emp JOIN employees WHERE employees.emp_no=dept_emp.emp_no and to_date='9999-01-01';
or
SELECT dept_no, first_name, last_name FROM dept_emp JOIN employees USING (emp_no) WHERE to_date='9999-01-01';
Exercises:
- List employees of department d001 that started on 1/1/1985.
- List employees that began in department d001 on 1/1/1990.
- List employees that transferred from another department to d001 on 1/1/1990.
- LEFT OUTER JOIN: An inner join can only return values if there are matching rows in the two relations. This is not always quite what you want. Consider this example: you want to print a list of departments with their current employees, but there are some new departments that don't have any employees. You still want them listed. Here is the query:
SELECT emp_no, dept_no FROM departments LEFT OUTER JOIN dept_emp USING (dept_no);
Note that all the rows of the left-most table (departments) appear in the result set.
- RIGHT OUTER JOIN: The same as left outer join, except all the rows of the right-most table appear in the result set.
Exercises: Try both left and right outer join. How do you manipulate the order of the relations to make this work?
- List employees born on 1/1/1959, together with their departments.
- List departments, together with a history of their managers.
Use the ORDER BY clause and list the columns you want used to sort.
Example: List departments ordered by current manager's last name.
SELECT dept_no, first_name, last_name FROM departments JOIN (dept_manager JOIN employees USING (emp_no)) USING (dept_no) WHERE to_date>curdate() ORDER BY last_name;
Aggregation operators:
- AVG(<column>)
- COUNT
- COUNT(*): row count
- COUNT(<column>): number of rows with non-null values in column
- COUNT(DISTINCT <column>): number of distinct values in column
- MIN(<column>): minimum value in column
- MAX(<column>): maximum value in column
- STD(<column>): standard deviation of column
- SUM(<column>): sum of values in column
Example: Total current monthly payroll for department d001.
SELECT SUM(salary/12) FROM dept_emp JOIN (employees JOIN salaries USING (emp_no)) USING (emp_no) WHERE salaries.to_date>curdate() AND dept_emp.to_date>curdate() AND dept_no="d001";
- What data type would you use for, and why:
- True/False answers to a series of questions.
- People's ages
- People's salaries
- Astronomical distances
- Currency
- Concentration of a protein in a cell
- Numbers of cells in various animal or plant species
- A name
- A description
- The time of day
- The date
- When a shipment was put on a truck
- Review all the exercises and examples above.