Oracle中没有 if exists(...)

2023-11-04

对于Oracle中没有 if exists(...) 的语法,目前有许多种解决方法,这里先分析常用的三种,推荐使用最后一种


第一种是最常用的,判断count(*)的值是否为零,如下
declare
  v_cnt number;
begin
  select count(*) into v_cnt from T_VIP where col=1;
  if v_cnt = 0 then
    dbms_output.put_line('无记录');
  end if;
end;
首先这种写法让人感觉很奇怪,明明只需要知道表里有没有记录,却去统计了全表的记录数。
这种方式对于小表而言可以接受,一旦表记录很多的时候,性能问题就非常严重
因此有人就作了些修改,改成 select count(*) into v_cnt from T_VIP where col=1 and rownum=1
看起来似乎解决了性能问题,但是分析执行计划可以知道,实际上是一样的,不推荐使用。


第二种是所谓进攻式编程,不作预先判断,而是直接默认通过判断,然后使用 exception 来捕获异常
比如我这里不判断表中是否有满足条件的记录,默认它有,如果没有就在异常中进行处理
declare
  v_1 number;
begin
  select vip_level into v_1 from T_VIP where 1=0;
exception
  when no_data_found then
    dbms_output.put_line('无记录');
end;
这种方式从性能上讲比第一种要好得多
不过首先它没办法适应所有的情况,如第一段代码它就没办法改造
其次这种代码看起来让人觉得好像是发生了异常,而不是正常运行,从而造成混乱,不推荐使用。


第三种是利用 Oracle 原有的 Exists 语法,如下
declare
  v_cnt number;
begin
  select count(*)
    into v_cnt
    from dual
   where exists (select * from t_vip where col=1);
  if v_cnt = 0 then
    dbms_output.put_line('无记录');
  end if;
end;
通过在语句的外面套上一层dual,来使用oracle原有的exists语法
虽然和第一种看起来类似,但分析执行计划可以知道,性能比以上两种都要好得多,与MSSQL的 if exists 最接近,推荐使用。


可以把判断封装成一个函数以方便使用,代码如下

CREATE OR REPLACE FUNCTION EXISTS2 (IN_SQL IN VARCHAR2)
  RETURN NUMBER
IS
  /**********************************************************
  * 使用示例
  * begin
  *   if EXISTS2('select * from dual where 1=1')=1 then
  *     dbms_output.put_line('有记录');
  *   else
  *     dbms_output.put_line('无记录');
  *   end if;
  * end;
  *****************************************************************/
  V_SQL VARCHAR2(4000);
  V_CNT NUMBER(1);
BEGIN
  V_SQL := 'SELECT COUNT(*) FROM DUAL WHERE EXISTS (' || IN_SQL || ')';
  EXECUTE IMMEDIATE V_SQL INTO V_CNT;
  RETURN(V_CNT);
END;

-

对于常用的insert判断还有更简单的写法,比如以下代码
if not exists(select * from table1 where id=1)
   insert into table1 values(1,'a');
可以改写成
insert
  when (not exists(select * from table1 where id=1)) then
into table1
select 1 as id, 'a' as data from dual;

-

再比如以下的代码
if not exists(select * from table1 where id=2)
   insert into table1 values(2,'b')
else
   update table1 set data='b' where id=2;
可以改写成
merge into table1 his
using
(
  select 2 as id, 'b' as data from dual
) src
on (his.id=src.id)
when matched then
  update set his.data=src.data where id=src.id
when not matched then
  insert values(src.id,src.data);

-

这里附带说下,有人喜欢把count(*)写成count(列名),不推荐后一种,因为列名是需要额外的操作,去查询系统表来定位列信息

另外count(1)和count(*)没有差别,推荐使用count(*)直观明了


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Oracle中没有 if exists(...) 的相关文章

  • Presto 数组包含一个喜欢某种模式的元素

    例如 我的表中的一列是一个数组 我想检查该列是否包含包含子字符串 denied 的元素 因此 在中午 12 00 拒绝 被管理员拒绝 等元素都将计数 我相信我将不得不使用 like 来识别模式 这个sql该怎么写呢 使用急板数组函数 htt
  • Oracle中表的列重新排序

    我有一个包含 50 多列的表 我需要交换前两列的顺序 使用 Oracle 实现此目的的最佳方法是什么 假设表名是 ORDERDETAILS 前两列是 ITEM ID 和 ORDER ID 重命名完成后 表名仍应为 ORDERDETAILS
  • SQL Fiddle 输出错误

    其实我对 PL SQL 还很陌生 我在 SQL Fiddle 中使用 oracle pl sql 创建了下表 create table Employee name varchar2 100 id integer salary integer
  • Oracle 事务在 C++ 和 Java 之间的传播

    我们有一个现有的 C 应用程序 我们将逐步将其替换为新的基于 Java 的系统 在我们用 Java 完全重新实现所有内容之前 我们期望 C 和 Java 必须相互通信 RMI SOAP 消息传递等 我们尚未决定 现在我的经理认为我们需要 J
  • 分组依据检索 3 个值

    我有以下查询 SELECT Cod MIN Id AS id Min MAX Id AS id Max retrieve value in the middle COUNT AS Tot FROM Table a NOLOCK GROUP
  • 为什么我无法从多处理队列中捕获 Queue.Empty 异常?

    我试图捕获 multiprocessing Queue 为空时引发的 Queue Empty 异常 以下不起作用 import multiprocessing f multiprocessing Queue try f get True 0
  • 如何获取共同好友列表

    你好 我想知道如何才能找到共同的朋友 我目前在思考这个问题时遇到问题 我有一个名为 users 的表 它是这样的 id name 1 Kenny 2 Jack 3 Jimmy 4 Chris 5 Meg 6 Jake 7 Micheal 8
  • 在 AppEngine 项目之外使用 Google AppEngine 数据存储区

    对于我的小框架Pyxer http code google com p pyxer 我希望能够在 AppEngine 项目之外使用 Google AppEngine 数据存储 因为我现在已经习惯了这种 ORM 模式 对于一些快速的黑客来说
  • EF4 和 SQL Server 2000

    我使用 EF4 和 SQL Server 2005 开发了我的网站 但当转移到临时站点时 发现他们使用 SQL Server 2000 现在我收到此错误 我认为该错误与 SQL Server 2000 有关 Incorrect syntax
  • MySQL 中有“connect by”替代方案吗?

    如果我使用 Oracle 有connect by可用于创建分层查询的关键字 目前我正在一个项目中使用MySQL 我想知道是否有替代方案connect by在 MySQL 中 我尝试过谷歌 但到目前为止还没有结果 我想要实现的是通过一个查询从
  • 检测 404 而不捕获异常

    简单功能 检查网络服务器是否返回非 200 HTTP 状态 Private Function RemoteFileOk ByVal Url As String As Boolean Dim req As HttpWebRequest Try
  • 将 c++ 异常传播到 cython - python 异常

    我的 Cython 0 17 1 有问题 我的函数抛出一个std runtime error如果文件不存在 我想以某种方式将此异常传播到我的 Cython 代码 void loadFile const string filename som
  • Postgres 上的 C 语言环境和 Posix 语言环境有什么区别?

    我知道 Postgres 上的数据库区域设置负责国家字符的正确顺序 正确的小写 大写等 但为什么有两种语言中立的语言环境 posix and c 它们之间有什么区别 还是只是一个中立的语言环境有两个不同的名称 UPDATE正如 Magnus
  • 如何手动设置auto_increment的下一个值?

    我手动向表中添加了一些行 并且还手动设置了 ID 自动增量 现在 当我尝试通过我的应用程序将新行添加到数据库表中时 我收到错误 创建的 ID 值已存在 如何手动设置下一个ID值 例如 在表中我必须有ID 那么如何告诉PostgreSQL 下
  • 使用sqlbulkcopy之前如何创建表

    我有一个 DBF 文件 我正在尝试导入该文件 然后将其写入 SQL 表 我遇到的问题是 如果我使用 SqlBulkCopy 它需要我提前创建表 但在我的场景中这是不可能的 因为 dbf 文件不断变化 到目前为止 这是我的代码 public
  • 将 Python 列表(JSON 或其他)插入 MySQL 数据库

    所以我在Python中有一堆数组数据 嗯 相反 我有一个清单 我试图将此数组存储到 MySQL 数据库中的单个单元格中 我尝试使用 JSON 来序列化我的数据 但也许我不明白 JSON 是如何工作的 因此 在连接到我的数据库后 我尝试了上游
  • sql查询中case语句中的布尔值

    我在选择查询中使用 case 语句 类似这样 Select col1 col2 isActive case when col3 abc then 1 else 0 end col4 from
  • 我想从 Crystal Report .rpt 文件中提取 SQL 查询,有办法做到这一点吗?

    我想从 Crystal Report rpt 文件中提取 SQL 查询 有办法做到这一点吗 我没有任何 Crystal Reports 产品 只有 rpt 文件 下面是一个 Net 代码示例 它从给定目录中的所有 Crystal Repor
  • 查询从同一表中的另一条记录获取值并按大于间隙阈值的差异进行过滤

    我将数据导入到 MS Access 中的临时表中 如下所示 我添加了需要使用 SQL 查询计算的 Gap 和 Previous Current 列 间隙阈值 是用户输入或范围提供给查询和例如是 300 GlobalID 对 ItemID 进
  • max()、分组依据和排序依据

    我有以下 SQL 语句 SELECT t client id max t points AS max FROM sessions GROUP BY t client id 它只是列出了客户 ID 以及他们所获得的最大积分 现在我想按 max

随机推荐