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对连接后子查询的更新可以顺利的更新到事实表中。

 

目录
相关文章
|
canal Kubernetes 网络架构
K8s CNI 网络最强对比:Flannel、Calico、Canal 和 Weave
Kubernetes 采用的 CNI 标准,让 Kubernetes 生态系统中的网络解决方案百花齐放。更多样的选择,意味着大多数用户将能够找到适合其当前需求和部署环境的 CNI 插件,同时还可以在环境发生变化时也能找到新的解决方案。
3611 1
|
数据采集 存储 安全
利用爬虫技术自动化采集汽车之家的车型参数数据
汽车之家是一个专业的汽车网站,提供了丰富的汽车信息,包括车型参数、图片、视频、评测、报价等。如果我们想要获取这些信息,我们可以通过浏览器手动访问网站,或者利用爬虫技术自动化采集数据。本文将介绍如何使用Python编写一个简单的爬虫程序,实现对汽车之家的车型参数数据的自动化采集,并使用亿牛云爬虫代理服务来提高爬虫的稳定性和效率。
799 0
利用爬虫技术自动化采集汽车之家的车型参数数据
|
SQL 关系型数据库 MySQL
mybatis学习(21):MySQL 字符串 转换 CAST与CONVERT 函数的用法
mybatis学习(21):MySQL 字符串 转换 CAST与CONVERT 函数的用法
1395 0
|
存储 弹性计算 对象存储
ECS快照问题之查看ECS快照容量失败如何解决
阿里云ECS用户可以创建的一个虚拟机实例或硬盘的数据备份,用于数据恢复和克隆新实例;本合集将指导用户如何有效地创建和管理ECS快照,以及解决快照过程中可能遇到的问题,确保数据的安全性和可靠性。
|
缓存 Java API
#7,Android开发 控件 ProgressBar 进度条
#7,Android开发 控件 ProgressBar 进度条
|
Java uml 开发者
Spring中的IOC是什么?
IOC准确的说是一种思想,它能将你从繁琐的代码中解脱出来并专注于对象本身。进一步突出面向对象。
86 0
|
SQL 关系型数据库 MySQL
一文解决所有MySQL分类排名问题
对数据库中的记录依据某个字段进行排序是一种常见需求,虽然简单的Order by可以胜任,但如果想要输出具体的排名却难以直接实现。如果再考虑重复排名或者分类排名,那么情况就更为复杂。 本文介绍4种分类排名方式:子查询、自连接、自定义变量以及MySQL8.0窗口函数。
637 0
一文解决所有MySQL分类排名问题
|
网络协议 Linux Go
4个实验,彻底搞懂TCP连接的断开
看到这个标题你可能会说,TCP 连接的建立与断开,这个我熟,不就是三次握手与四次挥手嘛。且慢,脑海中可以先尝试回答这几个问题: 四次挥手是谁发起的? 如果断电/断网了连接会断开吗? 什么情况下没有四次挥手连接也会断开?
956 0
4个实验,彻底搞懂TCP连接的断开
|
关系型数据库 MySQL OLTP
使用pt-archiver工具进行MySQL数据库迁移
pt-archiver是Percona-Toolkit工具集中的一个组件,可以用于对MySQL表数据进行归档和清除。
1137 0
使用pt-archiver工具进行MySQL数据库迁移
|
机器学习/深度学习 数据可视化 Python
Python:利用python语言绘制多个子图经典案例、代码实现之详细攻略
Python:利用python语言绘制多个子图经典案例、代码实现之详细攻略
Python:利用python语言绘制多个子图经典案例、代码实现之详细攻略