To define a view, use the CREATE VIEW statement, which has this syntax: CREATE [OR REPLACE] [ALGORITHM = algorithm_type] VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED | LOCAL] CHECK OPTION] view_name is the name to give the view. It can be unqualified to create the view in the default database, or qualified as db_name.view_name to create it in a specific database. select_statement is a SELECT statement that indicates how to retrieve data when the view is used. The statement can select from base tables or other views. References in the SELECT statement to unqualified table or view names refer to objects in your default database. To select from a table or view in a specific database, refer to it using the db_name.table_name or db_name.view_name syntax. Several parts of the CREATE VIEW statement are optional:
This section discusses most parts of the CREATE VIEW statement. For information about ALGORITHM and WITH CHECK OPTION, see Section 14.2.2, "View Algorithms," and Section 14.2.3, "Updatable Views," respectively. The following CREATE VIEW statement defines a simple view named CityView that selects the ID and Name columns from the City table. The SELECT statement shows an example of how to retrieve from the view: mysql> CREATE VIEW CityView AS SELECT ID, Name FROM City; Query OK, 0 rows affected (0.03 sec) mysql> SELECT * FROM CityView; +------+-----------------------------------+ | ID | Name | +------+-----------------------------------+ | 1 | Kabul | | 2 | Qandahar | | 3 | Herat | | 4 | Mazar-e-Sharif | ... Views and base tables share the same namespace, so CREATE VIEW results in an error if a base table or view with the given name already exists. To create the view if it does not exist, or replace a view of the same name if it does exist, use the OR REPLACE clause: mysql> CREATE VIEW CityView AS SELECT ID, Name FROM City; ERROR 1050 (42S01): Table 'CityView' already exists mysql> CREATE OR REPLACE VIEW CityView AS SELECT ID, Name FROM City; Query OK, 0 rows affected (0.00 sec) The OR REPLACE clause works only if the existing object is a view. You cannot use it to replace a base table. Another way to replace a view is by dropping it with DROP VIEW and re-creating it with CREATE VIEW. By default, the names of the columns in a view are the same as the names of the columns retrieved by the SELECT statement in the view definition. For the CityView view just defined, the SELECT statement retrieves two columns named ID and Name, which also become the view column names. To select data from CityView, select either or both columns by name, or use * to select all view columns: SELECT ID FROM CityView ... ; SELECT Name FROM CityView ... ; SELECT ID, Name FROM CityView ... ; SELECT * FROM CityView ... ; To override the default view column names and provide explicit names, include a column_list clause following the view name in the CREATE VIEW statement. If present, this list must contain one name per column selected by the view, with multiple names separated by commas. There are some important reasons to name view columns explicitly:
Another way to provide names for view columns is by using column aliases in the SELECT statement. This technique is convenient if only some of the view columns need renaming. For example, CountryLangCount could have been created with a definition that uses an AS clause to provide an alias for the second view column: CREATE VIEW CountryLangCount AS SELECT Name, COUNT(Language) AS LangCount FROM Country, CountryLanguage WHERE Code = CountryCode GROUP BY Name; When you use a SELECT statement that refers to a view, it is possible that the statement will contain clauses that are also present in the view definition. Sometimes the corresponding clauses are both used, sometimes one overrides the other, and sometimes the effect is undefined:
14.2.1. Restrictions on ViewsA view definition can include most of the constructs that are allowable in SELECT statements, such as WHERE, GROUP BY, and so forth. However, views in MySQL have some restrictions that do not apply to base tables:
14.2.2. View AlgorithmsA MySQL-specific extension to the CREATE VIEW statement is the ALGORITHM clause, which specifies the algorithm used to process the view. It has this syntax: ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE} For UNDEFINED, MySQL chooses the algorithm itself. This is the default if no ALGORITHM clause is present. For MERGE, MySQL processes a statement that refers to the view by merging parts of the view definition into corresponding parts of the statement and executing the resulting merged statement. For TEMPTABLE, MySQL processes a statement that refers to the view by first retrieving the view contents into an intermediate temporary table, and then using the temporary table to finish executing the statement. If you specify TEMPTABLE, the view becomes non-updatable. That is, the view cannot be used to update the underlying table. (Modifications would be made to the temporary table instead, leaving the base table unchanged.) The MERGE algorithm requires a one-to-one relationship between the rows in a view and the rows in the base table. Suppose that a view v is defined as follows to display changes in GNP per country: CREATE ALGORITHM = UNDEFINED VIEW v AS SELECT Name, GNP - GNPOld AS GNPDiff FROM Country WHERE GNPOld IS NOT NULL; As specified in the CREATE VIEW statement, the algorithm is undefined, so MySQL picks the algorithm. For this view, each row is derived from a single Country table row, so the view can be processed with the MERGE algorithm. Consider the following statement that refers to the view: SELECT Name, GNPDiff FROM v WHERE GNPDiff > 0; The MERGE algorithm merges the view definition into the SELECT statement: MySQL replaces v with Country, replaces the column list by the corresponding view column definitions, and adds the view WHERE conditions to the statement with AND. The resulting transformed SELECT statement that MySQL executes looks something like this: SELECT Name, GNP - GNPOld AS GNPDiff FROM Country WHERE (GNP - GNPOld > 0) AND (GNPOld IS NOT NULL); The MERGE requirement for a one-to-one relationship is not satisfied if the view definition produces a view row from multiple base table rows, or uses constructs such as DISTINCT, aggregate functions, a subquery in the select list, GROUP BY or HAVING. Suppose that a view v is defined as follows to display the number of languages spoken per country: CREATE VIEW v AS SELECT CountryCode, COUNT(*) AS LangCount FROM CountryLanguage GROUP BY CountryCode; Each row in the view is not necessarily derived from a single CountryLanguage table row, so the MERGE algorithm cannot be used to process the view. For example, to find the largest number of languages spoken in a single country, we would select from the view like this: SELECT MAX(LangCount) FROM v; But the MERGE algorithm would treat that statement as equivalent to this one, which is illegal due to the nested aggregate functions: SELECT MAX(COUNT(*)) FROM CountryLanguage GROUP BY CountryCode; Instead, MySQL processes a view such as this by using a temporary table to produce a result that contains the aggregated counts. This is called "materializing" the view (into the temporary table). Then MySQL evaluates SELECT MAX() using the temporary table to get the maximum count. It is as though MySQL does something like this: CREATE TEMPORARY TABLE tmp_table SELECT CountryCode, COUNT(*) AS LangCount FROM CountryLanguage GROUP BY CountryCode; SELECT MAX(LangCount) FROM tmp_table; DROP TABLE tmp_table; When you create a view, should you specify an algorithm explicitly? Generally speaking, it's unnecessary:
For these reasons, there usually is little reason to specify either UNDEFINED or MERGE. On the other hand, you might want to specify TEMPTABLE to influence how MySQL uses locking while it processes the view. Locks used for any underlying tables can be released after the temporary table has been created. This might reduce contention by allowing other clients to access the underlying tables earlier while the temporary table is used to finish processing the view. 14.2.3. Updatable ViewsA view is updatable if it can be used with statements such as UPDATE or DELETE to modify the underlying base table. Not all views are updatable. For example, you might be able to update a table, but you cannot update a view on the table if the view is defined in terms of aggregate values calculated from the table. The reason for this is that each view row need not correspond to a unique base table row, in which case MySQL would not be able to determine which table row to update. The primary conditions for updatability are that there must be a one-to-one relationship between the rows in the view and the rows in the base table, and that the view columns to be updated must be defined as simple table references, not expressions. (There are other conditions as well, but we will not go into them here.) The following example demonstrates updatability. First, use the following statement to create a CountryPop table containing three columns from the Country table. (By modifying this table, we avoid changing the contents of the original world database tables.) mysql> CREATE TABLE CountryPop -> SELECT Name, Population, Continent FROM Country; Query OK, 239 rows affected (0.01 sec) Records: 239 Duplicates: 0 Warnings: 0 Then create a simple view that contains the rows in CountryPop for countries in Europe: mysql> CREATE VIEW EuropePop AS -> SELECT Name, Population FROM CountryPop -> WHERE Continent = 'Europe'; Query OK, 0 rows affected (0.02 sec) The EuropePop view satisfies the one-to-one requirement, and its columns are simple column references, not expressions such as col1+1 or col2/col3. EuropePop is updatable, as demonstrated by the following statements. The example also selects from the base table CountryPop to show that the base table is indeed modified by the UPDATE and DELETE statements that use the view. mysql> SELECT * FROM EuropePop WHERE Name = 'San Marino'; +------------+------------+ | Name | Population | +------------+------------+ | San Marino | 27000 | +------------+------------+ 1 row in set (0.02 sec) mysql> UPDATE EuropePop SET Population = Population + 1 -> WHERE Name = 'San Marino'; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> SELECT * FROM EuropePop WHERE Name = 'San Marino'; +------------+------------+ | Name | Population | +------------+------------+ | San Marino | 27001 | +------------+------------+ 1 row in set (0.00 sec) mysql> SELECT * FROM CountryPop WHERE Name = 'San Marino'; +------------+------------+-----------+ | Name | Population | Continent | +------------+------------+-----------+ | San Marino | 27001 | Europe | +------------+------------+-----------+ 1 row in set (0.00 sec) mysql> DELETE FROM EuropePop WHERE Name = 'San Marino'; Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM EuropePop WHERE Name = 'San Marino'; Empty set (0.00 sec) mysql> SELECT * FROM CountryPop WHERE Name = 'San Marino'; Empty set (0.01 sec) An updatable view might also be insertable (usable with INSERT) if the view columns consist only of simple table column references (not expressions) and if any columns present in the base table but not named in the view or the INSERT have default values. In this case, an INSERT into the view creates a new base table row with each column not named in the INSERT set to its default value. If a view is updatable, you can use the WITH CHECK OPTION clause to place a constraint on allowable modifications. This clause causes the conditions in the WHERE clause of the view definition to be checked when updates are attempted:
In other words, WITH CHECK OPTION ensures that you cannot update a row in such a way that the view no longer selects it, and that you cannot insert a row that the view will not select. Using the CountryPop table created earlier in this section, define the following view that selects countries with a population of at least 100 million: mysql> CREATE VIEW LargePop AS -> SELECT Name, Population FROM CountryPop -> WHERE Population >= 100000000 -> WITH CHECK OPTION; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM LargePop; +--------------------+------------+ | Name | Population | +--------------------+------------+ | Bangladesh | 129155000 | | Brazil | 170115000 | | Indonesia | 212107000 | | India | 1013662000 | | Japan | 126714000 | | China | 1277558000 | | Nigeria | 111506000 | | Pakistan | 156483000 | | Russian Federation | 146934000 | | United States | 278357000 | +--------------------+------------+ 10 rows in set (0.00 sec) The WITH CHECK OPTION clause in the view definition allows some modifications but disallows others. For example, it's possible to increase the population of any country in the view: mysql> UPDATE LargePop SET Population = Population + 1 -> WHERE Name = 'Nigeria'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> SELECT * FROM LargePop WHERE Name = 'Nigeria'; +---------+------------+ | Name | Population | +---------+------------+ | Nigeria | 111506001 | +---------+------------+ 1 row in set (0.01 sec) It is also possible to decrease a population value, but only if it does not drop below the minimum value of 100 million that is required by the view's WHERE clause: mysql> UPDATE LargePop SET Population = 99999999 -> WHERE Name = 'Nigeria'; ERROR 1369 (HY000): CHECK OPTION failed 'world.LargePop' For inserts, a row can be added unless the Population value is less than 100 million: mysql> INSERT INTO LargePop VALUES('some country',100000000); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO LargePop VALUES('some country2',99999999); ERROR 1369 (HY000): CHECK OPTION failed 'world.LargePop' The WITH CHECK OPTION clause takes an optional keyword that controls the extent to which MySQL performs WHERE-checking for updates when a view is defined in terms of other views:
WITH CHECK OPTION is allowed only for updatable views, and an error occurs if you use it for a non-updatable view. This means that ALGORITHM = TEMPTABLE and WITH CHECK OPTION are mutually exclusive, because TEMPTABLE makes a view non-updatable. |