UPDATE子查询的ORA-1779错误

简介: 在对子查询执行UPDATE时,可能会遇到ORA-1779错误,这里简单讨论一下。     首先构造两个表: SQL> CREATE TABLE T1 (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30), DOC VARCHAR2(30)); 表已创建。

在对子查询执行UPDATE时,可能会遇到ORA-1779错误,这里简单讨论一下。

 

 

首先构造两个表:

SQL> CREATE TABLE T1 (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30), DOC VARCHAR2(30));

表已创建。

SQL> CREATE TABLE T2 (ID NUMBER PRIMARY KEY, FID NUMBER, NAME VARCHAR2(30), DOC VARCHAR2(30));

表已创建。

SQL> INSERT INTO T1 VALUES (1, 'A', 'TEST1');

已创建 1 行。

SQL> INSERT INTO T1 VALUES (2, 'B', 'TEST2');

已创建 1 行。

SQL> INSERT INTO T1 VALUES (3, 'C', 'TEST3');

已创建 1 行。

SQL> INSERT INTO T2 VALUES (1, 1, 'A', 'TESTA');

已创建 1 行。

SQL> INSERT INTO T2 VALUES (2, 2, 'B', 'TESTB');

已创建 1 行。

SQL> INSERT INTO T2 VALUES (3, 3, 'C', 'TESTC');

已创建 1 行。

SQL> INSERT INTO T2 VALUES (4, NULL, 'A', 'TESTD');

已创建 1 行。

SQL> COMMIT;

提交完成。

经常有需求会根据一张表的记录更新另一张表上对于记录的字段,一般这个SQL如下所示:

SQL> UPDATE T2 SET DOC = (SELECT DOC FROM T1 WHERE ID = T2.FID)
  2  WHERE EXISTS (SELECT 1 FROM T1 WHERE ID = T2.FID);

已更新3行。

SQL> SELECT * FROM T2;

        ID        FID NAME                           DOC
---------- ---------- ------------------------------ ---------------------
         1          1 A                              TEST1
         2          2 B                              TEST2
         3          3 C                              TEST3
         4            A                              TESTD

SQL> ROLLBACK;

回退已完成。

其中WHERE条件是为了避免将连接中匹配不到的记录更新为NULL

与此等价的有另外一种写法,直接对子查询进行更新:

SQL> UPDATE (SELECT T1.DOC DOC_1, T2.DOC DOC_2 FROM T1, T2 WHERE T1.ID = T2.FID)
  2  SET DOC_2 = DOC_1;

已更新3行。

SQL> SELECT * FROM T2;

        ID        FID NAME                           DOC
---------- ---------- ------------------------------ ---------------------------
         1          1 A                              TEST1
         2          2 B                              TEST2
         3          3 C                              TEST3
         4            A                              TESTD

SQL> ROLLBACK;

回退已完成。

采用这种方式,SQL显得更加简洁。

不过这种方式使用不当就会造成ORA-1779错误:

SQL> UPDATE (SELECT T1.DOC DOC_1, T2.DOC DOC_2 FROM T1, T2 WHERE T1.ID = T2.FID)
  2  SET DOC_1 = DOC_2;
SET DOC_1 = DOC_2
    *
2 行出现错误:
ORA-01779:
无法修改与非键值保存表对应的列

造成这个错误的原因是更新的列不是事实表的列,而是维度表的列。换句话说,如果两张表关联,其中一张表的关联列是主键,那么另一张表就是事实表,也就是说另一张表中的列就是可更新的;除非另一张表的关联列也是主键,否则这张表就是不可更新的,如果更新语句涉及到了这张表,就会出现ORA-1799错误。

如果是两张表主键关联,那么无论更新那个表的字段都可以:

SQL> UPDATE (SELECT T1.DOC DOC_1, T2.DOC DOC_2 FROM T1, T2 WHERE T1.ID = T2.ID)
  2  SET DOC_1 = DOC_2;

已更新3行。

SQL> ROLLBACK;

回退已完成。

SQL> UPDATE (SELECT T1.DOC DOC_1, T2.DOC DOC_2 FROM T1, T2 WHERE T1.ID = T2.ID)
  2  SET DOC_2 = DOC_1;

已更新3行。

SQL> ROLLBACK;

回退已完成。

如果两张表都不包含主键,那么无论更新那张表的字段都会报错:

SQL> UPDATE (SELECT T1.DOC DOC_1, T2.DOC DOC_2 FROM T1, T2 WHERE T1.NAME = T2.NAME)
  2  SET DOC_1 = DOC_2;
SET DOC_1 = DOC_2
    *
2 行出现错误:
ORA-01779:
无法修改与非键值保存表对应的列


SQL> UPDATE (SELECT T1.DOC DOC_1, T2.DOC DOC_2 FROM T1, T2 WHERE T1.NAME = T2.NAME)
  2  SET DOC_2 = DOC_1;
SET DOC_2 = DOC_1
    *
2 行出现错误:
ORA-01779:
无法修改与非键值保存表对应的列

其实这个限制的真正原因是Oracle要确保连接后更新的内容可以写到一张表中,而这就要求连接方式必须是1N或者11的连接。这样才能确保连接后的结果集数量和事实表一致。从而使得Oracle对连接后子查询的更新可以顺利的更新到事实表中。

 

目录
相关文章
|
5月前
|
SQL Oracle 关系型数据库
|
SQL Oracle 关系型数据库
Oracle 的sql陷阱(1)rownum和order by一起使用
rownum和order by一起使用可能会遇到取数不准确的问题
4854 0
|
5月前
|
SQL 存储 关系型数据库
SQL的基本语法以及SQL语句的关键字的使用,SELECT、INSERT、UPDATE、DELETE、CREATE、ALTER、DROP等。
SQL的基本语法以及SQL语句的关键字的使用,SELECT、INSERT、UPDATE、DELETE、CREATE、ALTER、DROP等。
|
3月前
|
SQL Oracle 关系型数据库
SQL CHECK 约束
【7月更文挑战第19天】SQL CHECK 约束。
37 5
|
4月前
|
SQL 数据库
SQL GROUP BY 语句
SQL GROUP BY 语句
19 0
|
11月前
|
Oracle 关系型数据库 MySQL
MySQL语句执行报错You can‘t specify target table for update in FROM clause
MySQL语句执行报错You can‘t specify target table for update in FROM clause
77 0
|
SQL Oracle 关系型数据库
Oracle中,UPDATE SET子句
Oracle中,UPDATE SET子句
441 1
|
SQL 关系型数据库 MySQL
解决Mysql5.7以上版本, 使用group by抛出Expression #1 of SELECT list is not in GROUP BY clause and contains no异常
解决Mysql5.7以上版本, 使用group by抛出Expression #1 of SELECT list is not in GROUP BY clause and contains no异常
123 0
Zp
|
SQL
在写左关联时SQL语句出现 Duplicate column name 'NAME'名字重复错误解决方法
在写左关联时SQL语句出现 Duplicate column name 'NAME'名字重复错误解决方法
Zp
446 0
|
SQL 关系型数据库 MySQL
mysql操作中 出现You can‘t specify target table for update in FROM clause错误的解决方法
这个错误实际上也不能称之为咱们sql语句写的不行,实际上是我们在一些细节上没有遵循mysql的语法规范。 问题所在:我们一个sql语句中先select这个表,然后再update这个表的内容。 错误示范: UPDATE StuCose SET Grade=60 WHERE Sno IN( SELECT Sno FROM stucose WHERE Grade<=ALL( SELECT MIN(Grade) FROM stucos
318 0
mysql操作中 出现You can‘t specify target table for update in FROM clause错误的解决方法
下一篇
无影云桌面