underlying base relations, whereas the user performing
the update does not need any permissions on the underlying base relations
(see <xref linkend="rules-privileges"/>). However, if the view has
<literal>security_invoker</literal> set to <literal>true</literal>, the
user performing the update, rather than the view owner, must have the
relevant privileges on the underlying base relations.
</para>
</refsect2>
</refsect1>
<refsect1>
<title>Examples</title>
<para>
Create a view consisting of all comedy films:
<programlisting>
CREATE VIEW comedies AS
SELECT *
FROM films
WHERE kind = 'Comedy';
</programlisting>
This will create a view containing the columns that are in the
<literal>film</literal> table at the time of view creation. Though
<literal>*</literal> was used to create the view, columns added later to
the table will not be part of the view.
</para>
<para>
Create a view with <literal>LOCAL CHECK OPTION</literal>:
<programlisting>
CREATE VIEW universal_comedies AS
SELECT *
FROM comedies
WHERE classification = 'U'
WITH LOCAL CHECK OPTION;
</programlisting>
This will create a view based on the <literal>comedies</literal> view, showing
only films with <literal>kind = 'Comedy'</literal> and
<literal>classification = 'U'</literal>. Any attempt to <command>INSERT</command> or
<command>UPDATE</command> a row in the view will be rejected if the new row
doesn't have <literal>classification = 'U'</literal>, but the film
<literal>kind</literal> will not be checked.
</para>
<para>
Create a view with <literal>CASCADED CHECK OPTION</literal>:
<programlisting>
CREATE VIEW pg_comedies AS
SELECT *
FROM comedies
WHERE classification = 'PG'
WITH CASCADED CHECK OPTION;
</programlisting>
This will create a view that checks both the <literal>kind</literal> and
<literal>classification</literal> of new rows.
</para>
<para>
Create a view with a mix of updatable and non-updatable columns:
<programlisting>
CREATE VIEW comedies AS
SELECT f.*,
country_code_to_name(f.country_code) AS country,
(SELECT avg(r.rating)
FROM user_ratings r
WHERE r.film_id = f.id) AS avg_rating
FROM films f
WHERE f.kind = 'Comedy';
</programlisting>
This view will support <command>INSERT</command>, <command>UPDATE</command> and
<command>DELETE</command>. All the columns from the <literal>films</literal> table will
be updatable, whereas the computed columns <literal>country</literal> and
<literal>avg_rating</literal> will be read-only.
</para>
<para>
Create a recursive view consisting of the numbers from 1 to 100:
<programlisting>
CREATE RECURSIVE VIEW public.nums_1_100 (n) AS
VALUES (1)
UNION ALL
SELECT n+1 FROM nums_1_100 WHERE n < 100;
</programlisting>
Notice that although the recursive view's name is schema-qualified in this
<command>CREATE</command>, its internal self-reference is not schema-qualified.
This is because the implicitly-created CTE's name cannot be
schema-qualified.
</para>
</refsect1>
<refsect1>
<title>Compatibility</title>
<para>
<command>CREATE OR REPLACE VIEW</command> is a
<productname>PostgreSQL</productname> language extension.
So is the concept of a temporary view.
The <literal>WITH ( ... )</literal> clause is an extension as well, as are
security barrier views and security invoker views.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-alterview"/></member>
<member><xref linkend="sql-dropview"/></member>
<member><xref linkend="sql-creatematerializedview"/></member>
</simplelist>
</refsect1>
</refentry>