#
第二十五章 SQL命令 CREATE VIEW(二)
# 通过视图更新
视图可用于更新视图所基于的表。可以通过视图插入新行,更新通过视图看到的行中的数据,以及删除通过视图看到的行。如果`CREATE VIEW`语句指定了此功能,则可以为视图发出`INSERT`、`UPDATE`和`DELETE`语句。要允许通过视图进行更新,请在定义视图时指定`WITH CHECK`选项(默认值)。
注意:如果视图基于分片表,则不能通过`WITH CHECK OPTION`视图进行`INSERT`、`UPDATE`或`DELETE`操作。
尝试这样做会导致一个`SQLCODE -35`,其中`%msg INSERT/UPDATE/DELETE not allowed for view (sample.myview) based on sharded table with check option conditions`。
若要防止通过视图进行更新,请指定`WITH READ ONLY`。尝试通过使用`READ ONLY`创建的视图执行插入、更新或删除操作会生成`SQLCODE-35`错误。
要通过视图进行更新,必须具有要更新表或视图的适当权限,如`GRANT`命令所指定。
通过视图更新受以下限制:
- 该视图不能是投影为视图的类查询。
- 视图的类不能包含类参数`READONLY=1`。
- 视图的SELECT语句不能包含`DISTINCT`、`TOP`、`GROUP BY`或`HAVING`子句,也不能是`UNION`的一部分。
- 视图的`SELECT`语句不能包含子查询。
- 视图的`SELECT`语句只能列出作为列引用的值表达式。
- 视图的`SELECT`语句只能有一个表引用;它不能在`SELECT-LIST`或`WHERE`子句中包含`FROM`子句、联接语法或箭头语法。表引用必须指定可更新的表或可更新的视图。
`WITH CHECK OPTION`子句导致`INSERT`或`UPDATE`操作根据视图定义的`WHERE`子句验证结果行。这可确保插入或修改的行是派生视图表格的一部分。有两个可用的检查选项:
- `WITH LOCAL CHECK OPTION`-仅检查`INSERT`或`UPDATE`语句中指定的视图的`WHERE`子句。
- `WITH CASCADED CHECK OPTION`-检查`INSERT`或`UPDATE`语句中指定的视图的`WHERE`子句和所有基础视图。这将覆盖这些基础视图中的任何`WITH LOCAL CHECK OPTION`子句。对于所有可更新的视图,建议使用`WITH CASCADED CHECK`选项。
如果指定`WITH CHECK OPTION`,则`CHECK`选项默认为`CASCADED`。关键字`CASCADE`是`CASCADED`的同义词。
如果插入操作因检查选项验证失败(如上所述), IRIS将发出`SQLCODE-136`错误。
如果更新操作因检查选项验证(如上所述)而失败,则 IRIS会发出`SQLCODE-137`错误。
# 示例
下面的示例从`PhoneBook`表中创建了名为`“CityPhoneBook”`的视图:
```sql
CREATE VIEW CityPhoneBook AS
SELECT Name FROM PhoneBook WHERE City='Boston'
```
下面的示例从`Guides`表中创建了一个名为`“GuideHistory”`的视图。
它列出了所有的`Title`以及这个人是否已经退休:
```sql
CREATE VIEW GuideHistory AS
SELECT Guides, Title, Retired, Date_Retired
FROM Guides
```
下面的嵌入式SQL示例创建表`MyTest`,然后为该表创建一个视图`MyTestView`,该视图从`MyTest`中选择一个字段:
```java
ClassMethod CreateView1()
{
d $SYSTEM.Security.Login("_SYSTEM","SYS")
&sql(DROP TABLE Sample.MyTest)
&sql(DROP VIEW Sample.MyTestView)
CreateTable
&sql(CREATE TABLE Sample.MyTest
(
TestNum INT NOT NULL,
FirstWord CHAR (30) NOT NULL,
LastWord CHAR (30) NOT NULL,
CONSTRAINT MyTestPK PRIMARY KEY (TestNum)
)
)
if SQLCODE = 0 {
w !,"创建表"
} else {
w "创建表错误 SQLCODE=",SQLCODE
}
CreateView
&sql(
CREATE VIEW Sample.MyTestView AS
SELECT FirstWord FROM Sample.MyTest
WITH CASCADED CHECK OPTION
)
if SQLCODE = 0 {
w !,"创建视图"
} else {
w "创建视图错误 SQLCODE=",SQLCODE
}
}
```
下面的嵌入式SQL示例创建视图`MyTestView`,该视图从`MyTest`中选择两个字段。此视图的`SELECT`查询包含一个`TOP`子句和一个`ORDER BY`子句:
```java
ClassMethod CreateView2()
{
d $SYSTEM.Security.Login("_SYSTEM","SYS")
&sql(DROP TABLE Sample.MyTest)
&sql(DROP VIEW Sample.MyTestView)
CreateTable
&sql(
CREATE TABLE Sample.MyTest
(
TestNum INT NOT NULL,
FirstWord CHAR (30) NOT NULL,
LastWord CHAR (30) NOT NULL,
CONSTRAINT MyTestPK PRIMARY KEY (TestNum)
)
)
if SQLCODE = 0 {
w !,"创建表"
} else {
w "创建表错误 SQLCODE=",SQLCODE
}
CreateView
&sql(
CREATE VIEW Sample.MyTestView AS
SELECT TOP ALL FirstWord,LastWord FROM Sample.MyTest
ORDER BY LastWord
)
if SQLCODE = 0 {
w !,"创建视图"
} else {
w "创建视图错误 SQLCODE=",SQLCODE
}
}
```
下面的示例从三个表(`Proj`、`Staff`和`Works`)创建了一个名为“`StaffWorksDesign`”的视图。
列`Name`、`Cost`和`Project`提供数据。
```sql
CREATE VIEW StaffWorksDesign (Name,Cost,Project)
AS SELECT EmpName,Hours*2*Grade,PName
FROM Proj,Staff,Works
WHERE Staff.EmpNum=Works.EmpNum
AND Works.PNum=Proj.PNum AND PType='Design'
```
下面的例子通过使用`UNION`从`b.table2`和`a.table1`中选择,创建了一个名为“`v_3`”的视图:
```sql
CREATE VIEW v_3(fvarchar)
AS SELECT DISTINCT *
FROM
(SELECT fVARCHAR2 FROM b.table2
UNION ALL
SELECT fVARCHAR1 FROM a.table1)
```