Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/84.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用于根据特定条件更新列值的Oracle SQL语句_Sql_Oracle - Fatal编程技术网

用于根据特定条件更新列值的Oracle SQL语句

用于根据特定条件更新列值的Oracle SQL语句,sql,oracle,Sql,Oracle,我有一个表,它有3列PID、LOCID、ISMGR。现在在现有场景中,对于某些人,基于位置ID,他被设置为ISMGR=true。 但根据新的要求,我们必须使所有ISMGR=true适用于至少有一个ISMGR=true的任何人。也就是说,如果他是任何一个地点的经理,他应该是所有地点的经理 运行脚本之前的表数据: PID|LOCID|ISMGR 1 1 1 1 2 0 1 3 0 2 1 0 2 2 1 PID|LOCID|I

我有一个表,它有3列PID、LOCID、ISMGR。现在在现有场景中,对于某些人,基于位置ID,他被设置为ISMGR=true。 但根据新的要求,我们必须使所有ISMGR=true适用于至少有一个ISMGR=true的任何人。也就是说,如果他是任何一个地点的经理,他应该是所有地点的经理

运行脚本之前的表数据:

PID|LOCID|ISMGR
1    1     1
1    2     0
1    3     0
2    1     0
2    2     1 
PID|LOCID|ISMGR
1    1     1
1    2     1
1    3     1
2    1     1
2    2     1
运行脚本后的表数据:

PID|LOCID|ISMGR
1    1     1
1    2     0
1    3     0
2    1     0
2    2     1 
PID|LOCID|ISMGR
1    1     1
1    2     1
1    3     1
2    1     1
2    2     1
任何帮助都将不胜感激


提前感谢。

为什么使用PL/SQL?您只需要一条简单的SQL语句。例如:

update your_table t  -- enter your actual table name here
set    ismgr = 1
where  ismgr = 0
  and  pid in ( select   pid
                from     your_table 
                group by pid 
                having   max(ismgr) = 1)
;

为什么使用PL/SQL?您只需要一条简单的SQL语句。例如:

update your_table t  -- enter your actual table name here
set    ismgr = 1
where  ismgr = 0
  and  pid in ( select   pid
                from     your_table 
                group by pid 
                having   max(ismgr) = 1)
;

我倾向于使用以下方法编写此文档:

exists应该比使用聚合执行子查询更有效


这对于tpid、ismgr和tismgr上的索引最为有效。

我倾向于使用exists编写这篇文章:

exists应该比使用聚合执行子查询更有效

这对于tpid、ismgr和tismgr上的索引最为有效。

这不是答案,而是对迄今为止提供的两种解决方案的测试-我将它们称为EXISTS和聚合解决方案或方法

测试详情如下,但以下是两个总体结论:

两种方法的执行时间相当;平均而言,聚合方法的运行速度略快于现有方法,但比从一次试验到下一次试验的运行时间差小得多。如果没有任何列上的索引,则运行时间为:第一个数字用于EXISTS方法,第二个数字用于聚合。试用版1:8.19s 8.08s试用版2:8.98s 8.22s试用版3:9.46s 9.55s注-估算的优化器成本应仅用于比较同一语句的不同执行计划,而不用于使用不同方法的不同解决方案。即便如此,也难免会有人问;因此,对于EXISTS方法,优化器发现的最低成本为4766;合计为2665。不过,这也是毫无意义的

如果需要更新大量行,索引对性能的影响将远远大于对性能的帮助。事实上,当更新行时,索引也必须更新。如果只需要更新少量行,那么索引将有所帮助,因为大部分时间都花在查找必须更新的行上,而更新本身所花的时间很少。在我的示例中,几乎25%的行必须更新。。。因此,聚合溶液耗时51.2秒,现有溶液耗时59.3秒!建议:如果您预计可能需要更新大量行,并且表上已经有索引,那么最好删除它们,并在更新后重新创建它们!或者,也许有其他办法解决这个问题;我不是专家记住这一点

为了正确地进行测试,在创建测试表并提交后,我单独运行每个解决方案,然后回滚,并在不同的会话中以SYS身份登录,运行alter system flush buffer_cache,以确保性能不会因缓存命中而随机提高或因未命中而受损。在所有情况下,一切都是从磁盘存储完成的

我创建了一个id在1到120万之间、随机整数在1到3之间的表,概率分别为40%、40%和20%,请参见下面dbms_random的使用。然后根据这些准备数据,我创建了测试表:每个pid根据这个随机整数包含一次、两次或三次;每行随机添加0或1作为ismgr,概率为50-50。我还添加了一个介于1和4之间的随机整数作为locid,以模拟实际数据;我不担心重复的locid,因为该列在问题中不起作用

在120万个PID中,约480000个40%的PID仅在测试表中出现一次,另外约480000个PID出现两次,约240000个PID出现三次。总行数应约为2160000。这是基表的基数,实际上它最终是2160546。然后:具有唯一pid的~480000行无需更改;计数为2的480000个PID中,有一半将具有相同的ismgr,因此没有更改,另一半将被拆分,因此我们需要从这些PID中更改240000行;一个简单的组合参数表明,表中出现三次的PID的720000行中,有3/8行(即270000行)必须更改。因此,我们预计应更改510000行。事实上,update语句导致两个解决方案更新了510132行。这些健全性检查表明测试可能设置正确。下面我还展示了来自基表的一个小样本,也是一个健全性检查

CREATE TABLE语句:

create table tbl as
  with prep ( pid, dup ) as (
          select level,
                 round( dbms_random.value(0.5, 3) ) as dup
          from   dual
          connect by level <= 1200000
       )
  select pid,
         round( dbms_random.value(0.5, 4.5) ) as locid,
         round( dbms_random.value(0, 1) )     as ismgr
  from   prep
  connect by level <= dup
      and prior pid = pid
      and prior sys_guid() is not null
;

commit;
更新声明:

update tbl t
    set ismgr = 1
    where ismgr = 0 and
          exists (select 1 from tbl t2 where t2.pid = t.pid and t2.ismgr = 1);

rollback;

update tbl
set    ismgr = 1
where  ismgr = 0
  and  pid in ( select   pid
                from     tbl 
                group by pid 
                having   max(ismgr) = 1);

rollback;

-- statements to create indexes, used in separate testing:
create index pid_ismgr_idx on tbl(pid, ismgr);
create index ismgr_ids on tbl(ismgr);
这不是一个答案,而是对迄今为止提供的两种解决方案的测试——我将它们称为EXISTS和AGGREGATE solutions或 接近

测试详情如下,但以下是两个总体结论:

两种方法的执行时间相当;平均而言,聚合方法的运行速度略快于现有方法,但比从一次试验到下一次试验的运行时间差小得多。如果没有任何列上的索引,则运行时间为:第一个数字用于EXISTS方法,第二个数字用于聚合。试用版1:8.19s 8.08s试用版2:8.98s 8.22s试用版3:9.46s 9.55s注-估算的优化器成本应仅用于比较同一语句的不同执行计划,而不用于使用不同方法的不同解决方案。即便如此,也难免会有人问;因此,对于EXISTS方法,优化器发现的最低成本为4766;合计为2665。不过,这也是毫无意义的

如果需要更新大量行,索引对性能的影响将远远大于对性能的帮助。事实上,当更新行时,索引也必须更新。如果只需要更新少量行,那么索引将有所帮助,因为大部分时间都花在查找必须更新的行上,而更新本身所花的时间很少。在我的示例中,几乎25%的行必须更新。。。因此,聚合溶液耗时51.2秒,现有溶液耗时59.3秒!建议:如果您预计可能需要更新大量行,并且表上已经有索引,那么最好删除它们,并在更新后重新创建它们!或者,也许有其他办法解决这个问题;我不是专家记住这一点

为了正确地进行测试,在创建测试表并提交后,我单独运行每个解决方案,然后回滚,并在不同的会话中以SYS身份登录,运行alter system flush buffer_cache,以确保性能不会因缓存命中而随机提高或因未命中而受损。在所有情况下,一切都是从磁盘存储完成的

我创建了一个id在1到120万之间、随机整数在1到3之间的表,概率分别为40%、40%和20%,请参见下面dbms_random的使用。然后根据这些准备数据,我创建了测试表:每个pid根据这个随机整数包含一次、两次或三次;每行随机添加0或1作为ismgr,概率为50-50。我还添加了一个介于1和4之间的随机整数作为locid,以模拟实际数据;我不担心重复的locid,因为该列在问题中不起作用

在120万个PID中,约480000个40%的PID仅在测试表中出现一次,另外约480000个PID出现两次,约240000个PID出现三次。总行数应约为2160000。这是基表的基数,实际上它最终是2160546。然后:具有唯一pid的~480000行无需更改;计数为2的480000个PID中,有一半将具有相同的ismgr,因此没有更改,另一半将被拆分,因此我们需要从这些PID中更改240000行;一个简单的组合参数表明,表中出现三次的PID的720000行中,有3/8行(即270000行)必须更改。因此,我们预计应更改510000行。事实上,update语句导致两个解决方案更新了510132行。这些健全性检查表明测试可能设置正确。下面我还展示了来自基表的一个小样本,也是一个健全性检查

CREATE TABLE语句:

create table tbl as
  with prep ( pid, dup ) as (
          select level,
                 round( dbms_random.value(0.5, 3) ) as dup
          from   dual
          connect by level <= 1200000
       )
  select pid,
         round( dbms_random.value(0.5, 4.5) ) as locid,
         round( dbms_random.value(0, 1) )     as ismgr
  from   prep
  connect by level <= dup
      and prior pid = pid
      and prior sys_guid() is not null
;

commit;
更新声明:

update tbl t
    set ismgr = 1
    where ismgr = 0 and
          exists (select 1 from tbl t2 where t2.pid = t.pid and t2.ismgr = 1);

rollback;

update tbl
set    ismgr = 1
where  ismgr = 0
  and  pid in ( select   pid
                from     tbl 
                group by pid 
                having   max(ismgr) = 1);

rollback;

-- statements to create indexes, used in separate testing:
create index pid_ismgr_idx on tbl(pid, ismgr);
create index ismgr_ids on tbl(ismgr);

现有的解决方案非常好,但我更喜欢在任何时候更新相关子查询中的行时使用merge。我发现它更具可读性,而且性能通常与现有方法相当

正如@mathguy指出的,在本例中,使用GROUPBY和HAVE比distinct更有效。要将其用于合并,只需更改子查询:

MERGE INTO t
USING      (SELECT   pid
            FROM     t
            GROUP BY pid
            HAVING   MAX(ismgr) = 1) src
ON         (t.pid = src.pid)
WHEN MATCHED THEN
   UPDATE SET ismgr = 1
      WHERE      ismgr = 0;

现有的解决方案非常好,但我更喜欢在任何时候更新相关子查询中的行时使用merge。我发现它更具可读性,而且性能通常与现有方法相当

正如@mathguy指出的,在本例中,使用GROUPBY和HAVE比distinct更有效。要将其用于合并,只需更改子查询:

MERGE INTO t
USING      (SELECT   pid
            FROM     t
            GROUP BY pid
            HAVING   MAX(ismgr) = 1) src
ON         (t.pid = src.pid)
WHEN MATCHED THEN
   UPDATE SET ismgr = 1
      WHERE      ismgr = 0;

您实际上是指Oracle的PL/SQL过程语言,还是仅仅指Oracle SQL?实际上我没有看到任何问题。你是指PL/SQL Oracle的过程语言,还是仅仅指Oracle SQL?实际上我没有看到任何问题。谢谢Mathguy。看起来Gordon的回答在性能上稍微好一点,因此接受了他的回答。无论如何,谢谢你@user2948533-别担心,戈登给了你一个完美的答案。谢谢Mathguy。看起来戈登的回答在性能上稍好一点,因此接受了他的回答。无论如何,谢谢你@用户2948533-不用担心,戈登给了你一个完美的答案。谢谢戈登!答对 了是

信息技术在我看来,对于外部查询中的每一行,在相关子查询中都会一次又一次地读取基表。聚合子查询只计算一次。如果我有几分钟的时间,我可能会做一些测试,这是一个有趣的问题。@mathguy。一点也不。exists应该是一个简单的索引查找。外部查询可能使用索引来查找与第一个条件匹配的行,也可能不使用索引。关于索引,有一点很好,我将尝试两种方法,不管是否使用索引。当然,一个指数也会有助于分组。说得清楚一点,你的答案非常好,我不是在质疑它,也不是在质疑你对绩效的观察,只是在过去,我听到过很多这样的声明,结果都是不正确的。我在OTN上发布了很多这样的性能比较,还有一些就在这里。我将在这里发布我的测试结果,以及完整的脚本,以便它们可以重复。即使exists解决方案速度更快,看看它的速度有多快也会很有趣。谢谢戈登!答对 了它是?在我看来,对于外部查询中的每一行,在相关子查询中都会一次又一次地读取基表。聚合子查询只计算一次。如果我有几分钟的时间,我可能会做一些测试,这是一个有趣的问题。@mathguy。一点也不。exists应该是一个简单的索引查找。外部查询可能使用索引来查找与第一个条件匹配的行,也可能不使用索引。关于索引,有一点很好,我将尝试两种方法,不管是否使用索引。当然,一个指数也会有助于分组。说得清楚一点,你的答案非常好,我不是在质疑它,也不是在质疑你对绩效的观察,只是在过去,我听到过很多这样的声明,结果都是不正确的。我在OTN上发布了很多这样的性能比较,还有一些就在这里。我将在这里发布我的测试结果,以及完整的脚本,以便它们可以重复。即使exists解决方案速度更快,看看速度有多快也会很有趣。通常我也更喜欢合并。在这种情况下,您需要选择DISTINCT,否则MERGE将无法工作,这会增加开销。我刚刚在同一个表上进行了测试,得到了略高的执行时间9.27s、10.73s、9.62s,但这是一天中的不同时间,谁知道我的机器后台运行的是什么进程呢。另外,我不确定与SELECT DISTINCT相比,GROUP BY和HAVE子查询的执行时间是否会减少几分之一秒——不确定哪一个更有效,这可能取决于可能的情况。@mathguy:一点实验表明GROUP BY/HAVE公式的执行速度更快,但这可以很容易地添加到合并中。事实上,您提供的更新和使用group by/having的合并实际上有相同的计划。对,这就是我的意思,在这两个方面。干杯一般来说,我也喜欢合并。在这种情况下,您需要选择DISTINCT,否则MERGE将无法工作,这会增加开销。我刚刚在同一个表上进行了测试,得到了略高的执行时间9.27s、10.73s、9.62s,但这是一天中的不同时间,谁知道我的机器后台运行的是什么进程呢。另外,我不确定与SELECT DISTINCT相比,GROUP BY和HAVE子查询的执行时间是否会减少几分之一秒——不确定哪一个更有效,这可能取决于可能的情况。@mathguy:一点实验表明GROUP BY/HAVE公式的执行速度更快,但这可以很容易地添加到合并中。事实上,您提供的更新和使用group by/having的合并实际上有相同的计划。对,这就是我的意思,在这两个方面。干杯你很彻底。如果有25%的行需要更新,我会很惊讶。实际上,一旦每个数据页都有了更新,使用索引可能不会有多大帮助。我想知道你提到的时间安排是否仅仅是加载索引和数据页的额外时间。你做得很彻底。如果有25%的行需要更新,我会很惊讶。实际上,一旦每个数据页都有了更新,使用索引可能不会有多大帮助。我想知道您提到的时间安排是否只是加载索引和数据页的额外时间。