MogDB如何兼容Oracle的管道函数

embedded/2024/9/22 11:08:19/

在之前很多数据库国产化改造项目中,我们遇到了很多难题,其中一个难点在于重度使用Oracle的一些用户使用了大量的管道函数(pipeline)。在之前的版本中,由于MogDB还不支持pipeline,因此给我们造成了不小的麻烦。但是凭借团队极强的代码改写和优化能力,我们能够完美的解决这个问题。

实际上主要是因为MogDB 5.0就已经支持了table()函数,因此要解决这个问题,也不算太困难。

这里给大家一些演示例子。

构造测试用例

如下是一段Oracle的测试代码.

CREATE OR REPLACE TYPE type_emp_row AS OBJECT
(
  empno    NUMBER(4),
  ename    VARCHAR2(10),
  job      VARCHAR2(9),
  mgr      NUMBER(4),
  hiredate DATE,
  sal      NUMBER(7,2),
  comm     NUMBER(7,2),
  deptno   NUMBER(2)
)
/
CREATE OR REPLACE TYPE type_emp IS TABLE OF type_emp_row;
/
CREATE OR REPLACE FUNCTION f_get_emp(p_deptno NUMBER) RETURN type_emp
  PIPELINED AS
  v_emp type_emp_row;
BEGIN
  FOR cur IN (SELECT * FROM scott.emp WHERE deptno = p_deptno) LOOP
    v_emp := type_emp_row(cur.empno,
                          cur.ename,
                          cur.job,
                          cur.mgr,
                          cur.hiredate,
                          cur.sal,
                          cur.comm,
                          cur.deptno);
    PIPE ROW(v_emp);
  END LOOP;
END;

调用上述table函数执行的结果如下所示:

SQL> select * From table(f_get_emp(10));

     EMPNO ENAME      JOB              MGR HIREDATE           SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ----------- ---------- ---------- ----------
      7782 CLARK      MANAGER         7839 1981/6/9          2450                    10
      7839 KING       PRESIDENT            1981/11/17        5000                    10
      7934 MILLER     CLERK           7782 1982/1/23         1300                    10

那么上述代码如果要移植到MogDB 有哪些解决方案呢? 这里分享几个。

改写方案1

CREATE OR REPLACE TYPE type_emp_row AS OBJECT
(
  empno    NUMBER(4),
  ename    VARCHAR2(10),
  job      VARCHAR2(9),
  mgr      NUMBER(4),
  hiredate DATE,
  sal      NUMBER(7,2),
  comm     NUMBER(7,2),
  deptno   NUMBER(2)
);
/
CREATE OR REPLACE TYPE type_emp IS TABLE OF type_emp_row;
/
CREATE OR REPLACE FUNCTION f_get_emp(p_deptno NUMBER) RETURN type_emp
   AS
  v_emp type_emp_row;
  res_emp type_emp := type_emp();
BEGIN
  FOR cur IN (SELECT * FROM scott.emp WHERE deptno = p_deptno) LOOP
    v_emp := type_emp_row(cur.empno,
                          cur.ename,
                          cur.job,
                          cur.mgr,
                          cur.hiredate,
                          cur.sal,
                          cur.comm,
                          cur.deptno);
    res_emp.extend;
    res_emp(res_emp.last)=v_emp;
  END LOOP;
  return res_emp;
END;
/

改写完毕之后,我们来看看查询效果。

xxdb=> select * from table(f_get_emp(10));
 empno | ename  |    job    | mgr  |      hiredate       |   sal   | comm | deptno 
-------+--------+-----------+------+---------------------+---------+------+--------
  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 00:00:00 | 2450.00 |      |     10
  7839 | KING   | PRESIDENT |      | 1981-11-17 00:00:00 | 5000.00 |      |     10
  7934 | MILLER | CLERK     | 7782 | 1982-01-23 00:00:00 | 1300.00 |      |     10
(3 rows)

改写方案2

方案2区别不太大,主要是函数部分与上面稍有区别,如下是改写后的代码,以供参考。

CREATE OR REPLACE TYPE type_emp_row AS OBJECT
(
  empno    NUMBER(4),
  ename    VARCHAR2(10),
  job      VARCHAR2(9),
  mgr      NUMBER(4),
  hiredate DATE,
  sal      NUMBER(7,2),
  comm     NUMBER(7,2),
  deptno   NUMBER(2)
);
/
CREATE OR REPLACE TYPE type_emp IS TABLE OF type_emp_row;
/
CREATE OR REPLACE FUNCTION f_get_emp(p_deptno NUMBER) RETURN type_emp
   AS
  res_emp type_emp := type_emp();
BEGIN
  SELECT * bulk collect into res_emp FROM scott.emp WHERE deptno = p_deptno;
  return res_emp;
END;


当然如果这里我们不使用table()函数,是否还有解决方案呢?答案是肯定的,那就是直接改为表函数的方式。针对不使用table()函数的方式,这里我们也提供了2个改写的方法。

不使用table() 改写方案1

drop function if exists scott.f_get_emp;

CREATE OR REPLACE FUNCTION scott.f_get_emp(p_deptno NUMBER) 
RETURNS TABLE (
  empno    INTEGER,
  ename    VARCHAR(10),
  job      VARCHAR(9),
  mgr      INTEGER,
  hiredate DATE,
  sal      NUMERIC(7,2),
  comm     NUMERIC(7,2),
  deptno   INTEGER
) AS $$
BEGIN
  FOR cur IN (SELECT * FROM scott.emp WHERE deptno = p_deptno) LOOP
    empno    :=cur.empno    ;
    ename    :=cur.ename    ;
    job      :=cur.job      ;
    mgr      :=cur.mgr      ;
    hiredate :=cur.hiredate ;
    sal      :=cur.sal      ;
    comm     :=cur.comm     ;
    deptno   :=cur.deptno   ;
    RETURN NEXT;
  END LOOP;
END;
$$ LANGUAGE plpgsql;

这里来看看改写的效果如何。

xxdb=> SELECT * FROM scott.f_get_emp(10);
 empno | ename  |    job    | mgr  |      hiredate       |   sal   | comm | deptno 
-------+--------+-----------+------+---------------------+---------+------+--------
  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 00:00:00 | 2450.00 |      |     10
  7839 | KING   | PRESIDENT |      | 1981-11-17 00:00:00 | 5000.00 |      |     10
  7934 | MILLER | CLERK     | 7782 | 1982-01-23 00:00:00 | 1300.00 |      |     10
(3 rows)

另外还有2种处理方案,这也共享一下改写示例代码,供大家参考,如下所示。

不使用table() 改写方案2

drop function if exists scott.f_get_emp;

CREATE OR REPLACE FUNCTION scott.f_get_emp(p_deptno NUMBER) 
RETURNS setof scott.emp AS $$
BEGIN
  FOR emp_row IN (SELECT * FROM scott.emp WHERE deptno = p_deptno) LOOP
    -- 使用 RETURN NEXT 返回结果集中的一行
    RETURN NEXT emp_row;
  END LOOP;
END;
$$ LANGUAGE plpgsql;

不使用table() 改写方案3

drop function if exists scott.f_get_emp;

CREATE OR REPLACE FUNCTION scott.f_get_emp(p_deptno NUMBER) 
RETURNS setof scott.emp AS $$
BEGIN
  RETURN QUERY SELECT * FROM scott.emp e WHERE deptno = p_deptno;
END;
$$ LANGUAGE plpgsql;

对于前面提到的table()函数的用法说明,大家可以参考: https://docs.mogdb.io/zh/mogdb/v5.0/support-table-function#%E7%89%B9%E6%80%A7%E7%BA%A6%E6%9D%9F

本文由 mdnice 多平台发布


http://www.ppmy.cn/embedded/24878.html

相关文章

python生成随机验证码图片+噪声

参数:图片宽高、验证码个数,文字大小 def check_code(width90, height30, length4, font_size26):code []from PIL import Image, ImageDrawimg Image.new(modeRGB, size(width, height), color(255, 255, 255))draw ImageDraw.Draw(img, modeRGB)def…

react props传参

props是父子传参的常用方法。 一、主要功能 1.传参 定义:父级组件向子级组件传递参数。 2.验证数据类型格式 定义:可以指定父组件传递过来数据为指定类型。 3.设置默认值 定义:在参数未使用时,直接默认为指定值。 二、实例代…

iOS 创建开源库时如何使用图片和xib资源

参考文章 参考文章 使用xib的正确姿势 #define MAIN_BUNDLE [NSBundle bundleForClass:[self class]] //获取bundle [[MAIN_BUNDLE loadNibNamed:itemResuableStr owner:self options:nil] lastObject]; //加载xib [tempCollectionView registerNib:[UINib nibWithNibName…

【JS】找出两个数组中的相同元素与不同元素

一、找出相同元素 &#xff08;1&#xff09;方法一 const filterArr (arr1, arr2) > {let result [];for (let i 0; i < arr1.length; i) {for (let j 0; j < arr2.length; j) {if (arr1[i] arr2[j]) {result.push(arr1[i]);}}}return result; };&#xff08;…

JVM学习

目录 背景步骤是什么由什么构成加载分配内存堆目的构成分代问题 栈方法区 内存空间初始化销毁垃圾 &#xff1a;判断是否还活着引用计数法可达性分析算法 垃圾回收收集收集器垃圾收集算法 逃逸分析 对象出现问题JVM 的常见参数配置JVM调优 总结 背景 JVM和对象分不开&#xff…

Akamai 分布式“云+边缘”,打造下一代数字化基座

当下&#xff0c;数字化基础设施正逐步向分布式部署演化&#xff0c;云计算与边缘计算正在成为两大技术支柱。Gartner 数据显示&#xff0c;云服务占 IT 整体支出比例连年上涨&#xff0c;在过去一年已增长至12.1%&#xff1b;IDC 报告显示&#xff0c;截至2021年已有超过500亿…

密文域可逆信息隐藏技术综述(上)

加密图像可逆信息隐藏是一种加密原始图像后&#xff0c;在密文图像中可逆地隐藏附加数据&#xff0c;并且在数据提取后&#xff0c;原始图像可以被无损重建的技术。RDH-EI的分类如图1所示。 按对图像的加密方法&#xff0c;现有RDH-EI算法可分为对称加密域和非对称(公钥)加密域…

Python中的错误处理与资源管理:try、except、finally与with语句详解

Python中的错误处理与资源管理&#xff1a;try、except、finally与with语句详解 在Python编程中&#xff0c;错误处理和资源管理是两个至关重要的概念。Python提供了try、except、finally和with等语句&#xff0c;帮助我们有效地处理运行时错误&#xff0c;并确保资源的正确释…