{"id":93526,"date":"2022-03-16T19:29:25","date_gmt":"2022-03-16T19:29:25","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=93526"},"modified":"2022-03-16T19:29:25","modified_gmt":"2022-03-16T19:29:25","slug":"working-with-mysql-views","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/working-with-mysql-views\/","title":{"rendered":"Working with MySQL Views"},"content":{"rendered":"<p><strong>This article is part of Robert Sheldon's continuing series on Learning MySQL. To see all of the items in the series, <a href=\"https:\/\/www.red-gate.com\/simple-talk\/mysql-coding-basics\/\">click here<\/a>.<\/strong><\/p>\n\n<p>Like other database management systems, MySQL lets you create views that enable users and applications to retrieve data without providing them direct access to the underlying tables. You can think of a view as a predefined query that MySQL runs when the view is invoked. MySQL stores the view definition as a database object, similar to a table object.<\/p>\n<p>A view offers several advantages. It abstracts the underlying table schema and restricts access to only the data returned by the view. Applications invoking the view cannot see how the tables are structured or what other data the tables contain. In this sense, the view acts as a virtual table, adding another layer of security that hides the structure of the physical tables.<\/p>\n<p>A view also helps simplify queries because it presents a less complex version of the schema. For example, an application developer doesn\u2019t need to create detailed, multi-table joins but can instead invoke the view in a basic <code>SELECT<\/code> statement. In addition, a view\u2019s ability to abstract schema makes it possible to modify the underlying table definitions without breaking the application.<\/p>\n<p>Despite the advantages that a view offers, it also comes with a number of limitations. For instance, MySQL does not let you create an index on a view, define a trigger on a view, or reference a system or user-defined variable in the view\u2019s query.<\/p>\n<p>In addition, it\u2019s possible to drop a table that is referenced by a view without generating an error. It\u2019s not until a user or application tries to invoke the view that MySQL raises the alarm, which could have a severe impact on running workloads. (For a complete rundown on view restrictions and for other information about views, refer to the MySQL documentation on <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/create-view.html\">creating views<\/a>.)<\/p>\n<h2>Preparing your MySQL environment<\/h2>\n<p>A view is a stored query that MySQL runs when the view is invoked. The query is typically a SELECT statement that retrieves data from one or more tables. Starting with MySQL 8.0.19, the query can instead be a <code>VALUES<\/code> or <code>TABLE<\/code> statement, but in most cases, a <code>SELECT<\/code> statement is used, so that\u2019s the approach I take in this article.<\/p>\n<p>Any tables that are referenced by the <code>SELECT<\/code> statement must already exist before you can create the view. Beyond that, there\u2019s not much else you need to have in place to add a view to a database, other than to be sure you have the permissions necessary to create views and query the underlying tables (a topic I\u2019ll be discussing in more detail later in this series).<\/p>\n<p>For the examples in this article, I created the <code>travel<\/code> database and added the <code>manufacturers<\/code> and <code>airplanes<\/code> tables. These are the same tables I created and updated in the <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/working-mysql-tables\/\">previous article<\/a> in this series. To add the database and tables to your MySQL instance, you can run the following SQL code:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">DROP DATABASE IF EXISTS travel;\r\nCREATE DATABASE travel;\r\nUSE travel;\r\nCREATE TABLE manufacturers (\r\n  manufacturer_id INT UNSIGNED NOT NULL AUTO_INCREMENT,\r\n  manufacturer VARCHAR(50) NOT NULL,\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (manufacturer_id) ) \r\nENGINE=InnoDB AUTO_INCREMENT=1001;\r\nCREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL AUTO_INCREMENT,\r\n  plane VARCHAR(50) NOT NULL,\r\n  manufacturer_id INT UNSIGNED NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL,\r\n  engine_count TINYINT NOT NULL,\r\n  max_weight MEDIUMINT UNSIGNED NOT NULL,\r\n  wingspan DECIMAL(5,2) NOT NULL,\r\n  plane_length DECIMAL(5,2) NOT NULL,\r\n  parking_area INT GENERATED ALWAYS AS ((wingspan * plane_length)) STORED,\r\n  icao_code CHAR(4) NOT NULL,\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (plane_id),\r\n  CONSTRAINT fk_manufacturer_id FOREIGN KEY (manufacturer_id) \r\n    REFERENCES manufacturers (manufacturer_id) ) \r\nENGINE=InnoDB AUTO_INCREMENT=101;<\/pre>\n<p>To run these statements, copy the code and paste it into a query tab in Workbench. You can then execute the statements all at once or run them one at a time in the order they\u2019re shown here. You must create the <code>manufacturers<\/code> table before you create the <code>airplanes<\/code> table because the airplanes table includes a foreign key that references the <code>manufacturers<\/code> table.<\/p>\n<p>When you\u2019re creating a view, it\u2019s a good idea to test the view\u2019s <code>SELECT<\/code> statement and then run the view after it\u2019s created. For this, you\u2019ll need some test data. The following two <code>INSERT<\/code> statements will add a small amount of data to the two tables, enough to get you started with creating a view:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO manufacturers (manufacturer)\r\nVALUES ('Airbus'), ('Beechcraft'), ('Piper');\r\nINSERT INTO airplanes \r\n  (plane, manufacturer_id, engine_type, engine_count, \r\n    max_weight, wingspan, plane_length, icao_code)\r\nVALUES \r\n  ('A380-800', 1001, 'jet', 4, 1267658, 261.65, 238.62, 'A388'),\r\n  ('A319neo Sharklet', 1001, 'jet', 2, 166449, 117.45, 111.02, 'A319'),\r\n  ('ACJ320neo (Corporate Jet version)', 1001, 'jet', 2, 174165, 117.45, 123.27, 'A320'),\r\n  ('A300-200 (A300-C4-200, F4-200)', 1001, 'jet', 2, 363760, 147.08, 175.50, 'A30B'),\r\n  ('Beech 390 Premier I, IA, II (Raytheon Premier I)', 1002, 'jet', 2, 12500, 44.50, 46.00, 'PRM1'),\r\n  ('Beechjet 400 (from\/same as MU-300-10 Diamond II)', 1002, 'jet', 2, 15780, 43.50, 48.42, 'BE40'),\r\n  ('1900D', 1002, 'Turboprop', 2,17120,  57.75, 57.67, 'B190'),\r\n  ('PA-24-400 Comanche', 1003, 'piston', 1, 3600, 36.00, 24.79, 'PA24'),\r\n  ('PA-46-600TP Malibu Meridian, M600', 1003, 'Turboprop', 1, 6000, 43.17, 29.60, 'P46T'),\r\n  ('J-3 Cub', 1003, 'piston', 1, 1220, 38.00, 22.42, 'J3');<\/pre>\n<p>I\u2019ll be discussing <code>INSERT<\/code> statements in more detail later in this series, so I won\u2019t spend a lot of time on them here. For now, all you need to know is that the first statement adds three rows to the manufacturers table, and the second statement adds 10 rows to the airplanes table.<\/p>\n<p>You can execute both statements at the same time or one at a time. You must execute them in the order specified here so you don\u2019t violate the foreign key defined on the airplanes table. Because the foreign key is configured on the manufacturer_id column, the values in the column must first exist in the manufacturers table. Again, I\u2019ll be digging deeper into all this later in the series.<\/p>\n<p>That\u2019s the only setup you need to do to prepare your MySQL environment so you can follow along with the examples in this article. As with the first two articles in this series, I used the MySQL Community edition on a Windows computer to build the examples. I created the examples in Workbench, which comes with the Community edition.<\/p>\n<h2>Creating a view in MySQL<\/h2>\n<p>If you reviewed the previous article in this series, you know that the Workbench GUI provides the <em>Table<\/em> tab, a handy tool for building and editing a table definition. However, the one for creating views\u2014the <em>View<\/em> tab\u2014is not nearly so useful. One of the biggest advantages with the <em>Table<\/em> tab, especially for beginners, is that it shows the various options available to a table definition. The <strong>View<\/strong> tab does not provide this advantage. It basically leaves it up to you to build the <code>CREATE<\/code> <code>VIEW<\/code> statement, just like you would on a query tab.<\/p>\n<p>For this article, I used a query tab for all the examples. However, it\u2019s good to know how to access the <em>View<\/em> tab in case you want to use it. To launch the tab, select the database in Navigator and then click the create view button on the Workbench toolbar. (The button is to the right of the create table icon and includes the tooltip <em>Create a new view in the active schema in the connected server<\/em>.) When you click the button, Workbench opens the <em>View<\/em> tab, as shown in Figure 1.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-93527\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/graphical-user-interface-text-application-descr.png\" alt=\"The create view dialog box.\" width=\"694\" height=\"529\" \/><\/p>\n<p class=\"caption\"><strong>Figure 1. Adding a view through the Workbench GUI<\/strong><\/p>\n<p>The only thing you can do in this tab is to write a <code>CREATE<\/code> <code>VIEW<\/code> statement. Although the tab provides a bit of a stub for getting started with the statement, it does not offer much else. You\u2019re on your own to write the actual statement (or copy and paste it from another source). From there, you must then step through a couple more screens, just like you do with the <em>Table<\/em> tab, but without the benefit of an auto-generated statement.<\/p>\n<p>Whether or not you use the <em>View<\/em> tab is up to you. Either way, you must still come up with the <code>CREATE<\/code> <code>VIEW<\/code> statement. With that in mind, consider the following example, which creates a view based on the two tables in the travel database:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE VIEW airbus_info\r\nAS\r\n  SELECT a.plane, a.engine_type, a.engine_count, \r\n    a.wingspan, a.plane_length, a.parking_area\r\n  FROM airplanes a INNER JOIN manufacturers m\r\n  ON a.manufacturer_id = m.manufacturer_id\r\n  WHERE m.manufacturer = 'airbus'\r\n  ORDER BY a.plane;<\/pre>\n<p>At its most basic, the <code>CREATE<\/code> <code>VIEW<\/code> statement requires only that you specify a name for the view, followed by the AS keyword, and then followed by the <code>SELECT<\/code> statement. In this case, I\u2019ve named the view airbus_info.<\/p>\n<p>The <code>SELECT<\/code> statement itself is relatively straightforward. It defines an inner join between the airplanes and manufacturers tables, with the join based on the manufacturer_id column in each table. The <code>WHERE<\/code> clause limits the results to those rows in which the manufacturer value is airbus, and the <code>ORDER<\/code> <code>BY<\/code> clause sorts the results by the plane column.<\/p>\n<p>When you\u2019re creating a view, it\u2019s always a good idea to run the <code>SELECT<\/code> statement on its own to ensure it\u2019s returning the results you\u2019re looking for. I\u2019ve kept the statement relatively simple because I\u2019ll be discussing <code>SELECT<\/code> statements in more detail later in this series. However, the statement I\u2019ve used here does everything we need it to do to demonstrate how to create a view. A view\u2019s <code>SELECT<\/code> statement can be as simple or as complex as you need it to be.<\/p>\n<p>When you execute the <code>CREATE<\/code> <code>VIEW<\/code> statement, MySQL adds the view definition to the active database. You can verify that the view has been created in Navigator. You might need to refresh Navigator to see the listing, but you should find it under the <em>Views<\/em> node, as shown in Figure 2.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-93528\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/graphical-user-interface-text-application-descr-1.png\" alt=\"The Navigator showing the new view airbus_info with the columns\" width=\"329\" height=\"624\" \/><\/p>\n<p class=\"caption\"><strong>Figure 2. Viewing the new view in Navigator<\/strong><\/p>\n<p>From here, you can open the view definition in the <em>View<\/em> tab. When you hover over the view\u2019s name in Navigator, you\u2019ll see several small icons for accessing additional features. One of these looks like a wrench. If you click this, Workbench will launch the <em>View<\/em> tab and display the view\u2019s code, as shown in Figure 3.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-93529\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/graphical-user-interface-text-application-descr-2.png\" alt=\"The airbus_info view dialog showing the code for the view\" width=\"891\" height=\"593\" \/><\/p>\n<p class=\"caption\"><strong>Figure 3. Accessing the view definition through the Workbench GUI<\/strong><\/p>\n<p>MySQL added several options to the view definition that were not included in the original <code>CREATE<\/code> <code>VIEW<\/code> statement. The options are all configured with their default values. We\u2019ll be discussing these options in just a bit.<\/p>\n<p>You can edit the <code>CREATE<\/code> <code>VIEW<\/code> statement directly on the <em>View<\/em> tab. After you make the necessary changes, click <em>Apply<\/em>, review the code, click <em>Apply<\/em> again, and click <em>Finish<\/em>. Then close the <em>View<\/em> tab. We won\u2019t be using this method for this article but know that it\u2019s an option if you ever decide to go this route.<\/p>\n<p>You can also open the <code>CREATE<\/code> <code>VIEW<\/code> statement on a query tab. Right-click the view in Navigator, point to <em>Send to SQL Editor<\/em>, and then click <em>Create Statement<\/em>. The statement is rendered on a single line, which is fairly unreadable. However, you can fix this by clicking the reformat button on the tab\u2019s toolbar. (The button looks like a little broom and includes the tooltip <em>Beautify\/reformat the SQL script<\/em>.)<\/p>\n<h2>Accessing view information through the <strong>INFORMATION_SCHEMA<\/strong> database<\/h2>\n<p>Like other relational database systems, MySQL adheres to many of the SQL standards maintained by the American National Standards Institute (ANSI). One of these standards includes the creation of the INFORMATION_SCHEMA database, which provides read-only access to details about a database system and its databases.<\/p>\n<p>The information available through the INFORMATION_SCHEMA database is exposed though a set of views, one of which is named Views. Through it, you can access information about the views you create in your MySQL database. For example, the following query returns details about the view we just created in the travel database:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT * FROM information_schema.views\r\nWHERE table_schema = 'travel';<\/pre>\n<p>The statement uses the asterisk (*) wildcard to indicate that all columns should be returned. It also qualifies the name of the target view in the FROM clause by including the database name (<code>information_schema<\/code>), followed by a period and the name of the view (<code>views<\/code>). In addition, the statement includes a <code>WHERE<\/code> clause that filters out all views except those in the travel database.<\/p>\n<p>When you run this statement, the results should include a row for the airbus_info view that you created above. The information provides details about how the view has been defined. The meaning of many of the columns in the result set should be apparent, and others I\u2019ll be covering later in the article. But I did want to point out two columns in particular: <code>CHECK_OPTION<\/code> and <code>IS_UPDATEABLE<\/code>.<\/p>\n<p>Both columns have to do with updatable views, a topic I\u2019ll be covering later in this series. For now, just know that MySQL supports updateable views and that a view is considered updateable if it meets a specific set of criteria. MySQL automatically determines whether a view is updateable based on these criteria. If it is updateable, MySQL sets the <code>IS_UPDATEABLE<\/code> column to <code>YES<\/code> (true). Otherwise, the value is <code>NO<\/code> (false).<\/p>\n<p>Another column worth noting is <code>VIEW_DEFINITION<\/code>, which contains the view\u2019s query. If you want to view this query and nothing else, you can define your <code>SELECT<\/code> statement to limit the results:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT view_definition\r\nFROM information_schema.views\r\nWHERE table_schema = 'travel' \r\n  AND table_name = 'airbus_info';<\/pre>\n<p>The <code>SELECT<\/code> clause now specifies that only the <code>view_definition<\/code> column be returned, rather than all columns. However, even with limiting the results, they can still be difficult to read. Fortunately, Workbench provides a handy feature for viewing a column\u2019s value in its entirety. To access this feature, right-click the value directly in the results and click <em>Open Value in Viewer<\/em>. MySQL launches a separate window that displays the value, as shown in Figure 4.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-93530\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/graphical-user-interface-text-email-description.png\" alt=\"A dialog showing the entire contents of the VIEW_DEFINITION field of the airbus_info view\" width=\"808\" height=\"515\" \/><\/p>\n<p class=\"caption\"><strong>Figure 4. Examining the view\u2019s SELECT statement in Viewer<\/strong><\/p>\n<p>Here you can review both the binary and text values. In addition, you can save the statement to a text file by clicking the <em>Save<\/em> button. You cannot save the binary value to a file.<\/p>\n<h2>Querying a MySQL view<\/h2>\n<p>As noted earlier, I\u2019ll be covering the <code>SELECT<\/code> statement in more detail later in this series, but I wanted to give you a quick overview of how you can query a view after it\u2019s been created. For the most part, it works much the same way as querying a table. The following example shows a <code>SELECT<\/code> statement at its most basic, with the <code>airbus_info<\/code> view identified in the FROM clause:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT * FROM airbus_info;<\/pre>\n<p>When you execute this <code>SELECT<\/code> statement, MySQL runs the query in the view definition and returns the results, just like it would if you ran the query directly. Figure 5 shows the results that your <code>SELECT<\/code> statement should return.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-93531\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/graphical-user-interface-table-description-autom.png\" alt=\"A grid showing the results of querying the airbus_info view. There are four rows and six columns.\" width=\"635\" height=\"154\" \/><\/p>\n<p class=\"caption\"><strong>Figure 5. Viewing the query results after invoking the airbus_info view<\/strong><\/p>\n<p>You can also refine your <code>SELECT<\/code> statement as you would when querying a view. For example, the following <code>SELECT<\/code> statement includes a <code>WHERE<\/code> clause that limits the results to those with a <code>parking_area<\/code> value greater than 20000:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT * FROM airbus_info\r\nWHERE parking_area &gt; 20000\r\nORDER BY parking_area DESC;<\/pre>\n<p>The statement also includes an <code>ORDER<\/code> <code>BY<\/code> clause that sorts the results by the <code>parking_area<\/code> column in descending order. When you include an <code>ORDER<\/code> <code>BY<\/code> clause when calling the view, it overrides the <code>ORDER<\/code> BY clause in the view definition itself (if one is included). Figure 6 shows the data that your <code>SELECT<\/code> statement should now return.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-93532\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/graphical-user-interface-application-description.png\" alt=\"The results of running a modified query against the view. In this case, only two rows are returned.\" width=\"636\" height=\"125\" \/><\/p>\n<p class=\"caption\"><strong>Figure 6. Refining the query results when invoking a view<\/strong><\/p>\n<p>As you can see, the results now include only two rows and those rows are sorted by the values in the <code>parking_area<\/code> column, with the highest value first. The <code>ORDER<\/code> <code>BY<\/code> clause in the view definition sorts the data by the <code>plane<\/code> values.<\/p>\n<h2>Updating a MySQL view definition<\/h2>\n<p>MySQL provides several methods for modifying a view definition. One of these is to use a <code>CREATE<\/code> <code>VIEW<\/code> statement that includes the <code>OR<\/code> <code>REPLACE<\/code> clause, as shown in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE OR REPLACE \r\n  ALGORITHM = MERGE \r\n  DEFINER = CURRENT_USER \r\n  SQL SECURITY INVOKER\r\nVIEW airbus_info\r\nAS\r\n  SELECT a.plane, a.engine_type, a.engine_count, \r\n    a.wingspan, a.plane_length, a.parking_area\r\n  FROM airplanes a INNER JOIN manufacturers m\r\n  ON a.manufacturer_id = m.manufacturer_id\r\n  WHERE m.manufacturer = 'airbus'\r\n  ORDER BY a.plane;<\/pre>\n<p>By adding the <code>OR<\/code> <code>REPLACE<\/code> clause after the <code>CREATE<\/code> keyword, you can refine an existing view definition and then run the statement without generating an error, as would be the case if you didn\u2019t include the clause. This is a great tool when you\u2019re actively developing a database and the schema is continuously changing.<\/p>\n<p>In addition to the <code>OR<\/code> <code>REPLACE<\/code> clause, the view definition includes several other elements that weren\u2019t in the original <code>CREATE<\/code> <code>VIEW<\/code> statement that you created. The first is the <code>ALGORITHM<\/code> clause, which tells MySQL to use the <code>MERGE<\/code> algorithm when processing the view. The algorithm merges the calling statement and view definition in a way that can help make processing the view more efficient. The algorithm is also required for a view to be updatable. For more information about algorithms, see the MySQL documentation on <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/view-algorithms.html\">view processing algorithms<\/a>.<\/p>\n<p>The other two new options\u2014<code>DEFINER<\/code> and <code>SQL<\/code> <code>SECURITY<\/code>\u2014control which user account privileges to use when processing the view. The <code>DEFINER<\/code> option specifies which account is designated as the view creator. In this case, the option is set to <code>CURRENT_USER<\/code>, so the definer is the user that who actually runs the <code>CREATE<\/code> <code>VIEW<\/code> statement.<\/p>\n<p>The <code>SQL<\/code> <code>SECURITY<\/code> option can take either the <code>DEFINER<\/code> or <code>INVOKER<\/code> argument. If <code>DEFINER<\/code> is specified, the view will be processed under the account of the specified <code>DEFINER<\/code>. If <code>INVOKER<\/code> is specified, the view will be processed under the account of the user who invokes the view.<\/p>\n<p>After you run the preceding <code>CREATE<\/code> <code>VIEW<\/code> statement, you can verify that the options have been updated by querying the view <code>INFORMATION_SCHEMA.VIEWS<\/code>:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT table_name AS view_name, \r\n  is_updatable, definer, security_type\r\nFROM information_schema.views\r\nWHERE table_schema = 'travel'\r\n  AND table_name = 'airbus_info';<\/pre>\n<p>Figure 7 shows the results I received when I executed the <code>SELECT<\/code> statement on my system. Because I ran the <code>CREATE<\/code> <code>VIEW<\/code> statement as the <code>root<\/code> user, the <code>DEFINER<\/code> column shows my username, with <code>localhost<\/code> as the server instance. The results also show the <code>INVOKER<\/code> value in the <code>SECURITY_TYPE<\/code> column, which corresponds with the <code>SQL<\/code> <code>SECURITY<\/code> option.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-93533\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/graphical-user-interface-application-description-1.png\" alt=\"The results of running a query to find the view properties. The DEFINER is root@localhost and SECURITY_TYPE is INVOKER\" width=\"544\" height=\"117\" \/><\/p>\n<p class=\"caption\"><strong>Figure 7. Viewing results from the INFORMATION_SCHEMA database<\/strong><\/p>\n<p>You might have noticed that <code>INFORMATION_SCHEMA.VIEWS<\/code> does not return details about the specified algorithm. In this case, however, the <code>IS_UPDATABLE<\/code> column is set to <code>YES<\/code>, indicating that the view is updatable, which works only with the <code>MERGE<\/code> algorithm. That said, if the column is set to <code>NO<\/code>, you can\u2019t be certain which algorithm is being used because other factors might affect whether the view is updateable.<\/p>\n<p>Another approach you can take to updating a view definition is to run an <code>ALTER<\/code> <code>VIEW<\/code> statement. The <code>ALTER<\/code> <code>VIEW<\/code> statement syntax is nearly the same the <code>CREATE<\/code> <code>VIEW<\/code> syntax. For example, the following <code>ALTER<\/code> <code>VIEW<\/code> statement is similar to the previous <code>CREATE<\/code> <code>VIEW<\/code> statement except that it also specifies the column names to use for the returned result set:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">ALTER \r\n  ALGORITHM = MERGE \r\n  DEFINER = CURRENT_USER \r\n  SQL SECURITY INVOKER\r\nVIEW airbus_info \r\n  (plane, engine, count, wingspan, length, area)\r\nAS\r\n  SELECT a.plane, a.engine_type, a.engine_count, \r\n    a.wingspan, a.plane_length, a.parking_area\r\n  FROM airplanes a INNER JOIN manufacturers m\r\n  ON a.manufacturer_id = m.manufacturer_id\r\n  WHERE m.manufacturer = 'airbus'\r\n  ORDER BY a.plane;<\/pre>\n<p>In this case, the statement includes a list of column names after the view name. The column names are enclosed in parentheses and separated by commas. These are the column names used for the view\u2019s results, rather than using the column names of the underlying tables.<\/p>\n<p>After you run the <code>ALTER<\/code> <code>VIEW<\/code> statement, you can then query the view as you did before, except that you must use the specified column names. For example, the following <code>SELECT<\/code> statement limits and orders the results, like you saw in a previous example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT plane, wingspan, length, area\r\nFROM airbus_info\r\nWHERE area &gt; 20000\r\nORDER BY area DESC;<\/pre>\n<p>Notice that the <code>SELECT<\/code> statement uses the new column names, which are also reflected in the results, as shown in Figure 8.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-93534\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2022\/03\/table-description-automatically-generated.png\" alt=\"The results of the view using the new column names defined by the new definition.\" width=\"569\" height=\"127\" \/><\/p>\n<p class=\"caption\"><strong>Figure 8. Querying the updated airbus_info view<\/strong><\/p>\n<p>By specifying the returned column names, you can abstract the underlying schema even further, which provides yet another level of security, while making it easier to alter the underlying table schema. For example, if you change a column name in an underlying table, you might need to update the view\u2019s query, but not the returned column names, avoiding any disruptions to a calling application.<\/p>\n<h2>Dropping a MySQL view<\/h2>\n<p>Removing a view is a relatively straightforward process. You can use the Workbench GUI or run a DROP <code>VIEW<\/code> statement. To use the GUI, right-click the view in Navigator and click <em>Drop<\/em> <em>View<\/em>. When the <em>Drop<\/em> <em>View<\/em> dialog box appears, click <em>Drop<\/em> <em>Now<\/em>.<\/p>\n<p>To use a <code>DROP<\/code> <code>VIEW<\/code> statement, you need only specify the view name and, optionally, the <code>IF<\/code> <code>EXISTS<\/code> clause, as shown in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">DROP VIEW IF EXISTS airbus_info;<\/pre>\n<p>You can confirm that the view has been dropped by running the following <code>SELECT<\/code> statement against <code>INFORMATION_SCHEMA.VIEWS<\/code>:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT * FROM information_schema.views\r\nWHERE table_schema = 'travel';<\/pre>\n<p>The results should no longer include a row for the <code>airbus_info<\/code> view.<\/p>\n<h2>Working with views in a MySQL database<\/h2>\n<p>Views can provide an effective tool for presenting data to applications in a way that abstracts the underlying table structure. At the same time, they can help simplify the SQL statements that application developers need to write when retrieving data from a MySQL database. They also add an extra layer of protection by limiting access to the underlying tables.<\/p>\n<p>I\u2019ll be returning to the topic of views later in the series when I discuss querying and modifying data. Until then, the information I\u2019ve provided in this article should give you a good starting point for working with views. As you become more adept at writing <code>SELECT<\/code> statements, you\u2019ll be able to create more effective views that can return an assortment of information.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Views in MySQL allow you to save a predefined SQL query. Robert Sheldon explains the benefits of views and how to create and query them.&hellip;<\/p>\n","protected":false},"author":221841,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[53,145792],"tags":[95506],"coauthors":[6779],"class_list":["post-93526","post","type-post","status-publish","format-standard","hentry","category-featured","category-mysql","tag-automate"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/93526","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221841"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=93526"}],"version-history":[{"count":4,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/93526\/revisions"}],"predecessor-version":[{"id":93538,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/93526\/revisions\/93538"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=93526"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=93526"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=93526"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=93526"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}