Oracle:加入时更新未按预期工作

时间:2016-05-03 15:17:38

标签: sql oracle oracle11g

编辑:mathguy给出的答案非常有效。但我真的很想理解为什么第一个更新声明不起作用而第二个更新声明起作用。我知道+运算符不建议,但在这种情况下,因为第二个表在子查询中,我不得不使用它。

简短问题。 (详细说明和下面的创建/插入语句)

  

这两个更新语句之间有什么区别,为什么第一个没有按预期工作,而第二个更新。

update d_dim d
set FLAG=
(select case when t.id is null then 'N' else 'Y' end as FLAG
from t_temp t
where d.id=t.id(+) 
);

update d_dim d
set FLAG=
(select case when t.id is null then 'N' else 'Y' end as FLAG
from t_temp t,d_dim d1
where d1.id=t.id(+) 
and d1.id=d.id
);

详细说明

我正在尝试复制工作场景。不幸的是,SQLFiddle for Oracle没有工作,因此无法创建小提琴演示。

我有2个表,d_dim(ID,FLAG)t_temp(ID),如下所示

  

从d_dim中选择*;

+----+------+
| ID | FLAG |
+----+------+
|  1 |      |
|  2 |      |
|  3 |      |
|  4 |      |
+----+------+
  

从t_temp中选择*;

+----+
| ID |
+----+
|  1 |
|  3 |
+----+

现在我需要将FLAG中的d_dim设置为YN。 如果ID中存在t_temp则设置为Y。否则设置它N

所以期望的输出应该是。

+----+------+
| ID | FLAG |
+----+------+
|  1 | Y    |
|  2 | N    |
|  3 | Y    |
|  4 | N    |
+----+------+

这是我正在使用的更新语句(使用(+),因为在这种情况下我需要从d_dimt_temp的左连接

update d_dim d
set FLAG=
(select case when t.id is null then 'N' else 'Y' end as FLAG
from t_temp t
where d.id=t.id(+) 
)

--4 rows updated.

但ID 24更新为NULL。

select * from d_dim;
+----+------+
| ID | FLAG |
+----+------+
|  1 | Y    |
|  2 |      |
|  3 | Y    |
|  4 |      |
+----+------+

如果我在插入d_dim表后只使用select子句,我得到正确的输出。

select d.id,
case when t.id is null then 'N' else 'Y' end as FLAG
from t_temp t,d_dim d
where d.id=t.id(+)
order by id

+----+------+
| ID | FLAG |
+----+------+
|  1 | Y    |
|  2 | N    |
|  3 | Y    |
|  4 | N    |
+----+------+

我做了一些点击和试用,并提出了这个查询,这似乎正在运作

update d_dim d
set FLAG=(select case when t.id is null then 'N' else 'Y' end as FLAG
from t_temp t,d_dim d1
where d1.id=t.id(+) 
and d1.id=d.id);

select * from d_dim;

+----+------+
| ID | FLAG |
+----+------+
|  1 | Y    |
|  2 | N    |
|  3 | Y    |
|  4 | N    |
+----+------+

所以我的问题是

  

为什么初始更新语句不能正常工作,为什么会这样   正在更新null id2的{​​{1}}。

请找到下面的创建和插入语句

4

2 个答案:

答案 0 :(得分:3)

在第二个查询中,您有一个外部联接。在第一个查询中,您没有任何类型的连接;你只需要从t中选择一个where子句,其中t.id之后有一个(+)。我不知道为什么语法不会返回错误;但是当t中不存在d.id时,该子查询不返回任何行,这就是当更新值应该是标量子查询的输出时更新的工作方式:如果子查询没有返回任何行,则update语句将更新字段为NULL。

您没有要求使用其他方式使更新正常工作,但如果您想查看更新,则可以使用。毫无疑问你知道怎么做;为其他论坛成员的利益提供。

update d_dim 
    set FLAG = case when id in (select id from t_temp) then 'Y' else 'N' end;

编辑:OP似乎并不完全理解我的观点,所以这里有更多细节。

Oracle文档明确声明:

•如果在外部查询中指定一个表而在内部查询中指定另一个表,则(+)运算符不会生成外部联接。

https://docs.oracle.com/cd/B28359_01/server.111/b28286/queries006.htm

(在“外部联接”标题下,在“另请参阅”框之后)

答案 1 :(得分:1)

更新语句将根据subselect子句中指定的更新是否满足条件进行更新。

当你提到 更新d_dim d 设置FLAG = (选择t.id为空时的情况,然后' N'其他' Y'以FLAG结尾 来自t_temp t 其中d.id = t.id(+) );

仅当d.id等于t.id时才会执行此语句。在您的情况下,对于id = 2,d.id为2,t.id为null。 2不等于null,因此更新对id 2没有影响。