Oracle表中分母最小公倍数的计算

Emr*_*una 3 sql oracle plsql lcm oracle11g

我想创建一个表格来更好地说明我的问题

这是我在 oracle 数据库中的数据示例

在此处输入图片说明

我想做的工作是按以下步骤一步一步来的

1-按 group_id 列将分母列中的值分组并计算最小公倍数。对于此操作,我创建了 lcm(最小公倍数)和 gcd(最大公约数)函数。添加到这里。

CREATE OR REPLACE function SAMPLE.lcm(a number, b number) return number is begin return (a*b)/gcd(a,b); 结尾;

CREATE OR REPLACE function SAMPLE.gcd(a number, b number)
return number is
begin if b = 0 then return a; 否则返回 gcd(b,mod(a,b)); 万一; 结尾;

在此处输入图片说明

2-按分母列的值按比例增加分子值。像这样的数学公式:

(lcm(values of denominator(1..to -n)) / values of denominator ) * 分子的值

在此处输入图片说明

3-通过 group_id 值对新计算值进行分组来求和

在此处输入图片说明

使这项工作完成的所有项目,如 sql、function、view 都适合我。

我能为此做什么。

在此处输入图片说明

MT0*_*MT0 6

[TL;DR] 编写您自己的自定义聚合函数。


鉴于您的GCDLCM功能:

CREATE FUNCTION GCD(
  a IN NUMBER,
  b IN NUMBER
) RETURN NUMBER DETERMINISTIC
IS
BEGIN
  IF b = 0 THEN
    RETURN a;
  ELSE
    RETURN GCD(b,MOD(a,b));
  END IF;
END;
/

CREATE FUNCTION LCM(
  a IN NUMBER,
  b IN NUMBER
) RETURN NUMBER DETERMINISTIC
IS
BEGIN
  RETURN (a*b)/GCD(a,b);
END;
/
Run Code Online (Sandbox Code Playgroud)

然后,您可以为要在自定义聚合中使用的类型创建规范:

CREATE TYPE LCMAggregationType AS OBJECT(
  value NUMBER,

  STATIC FUNCTION ODCIAggregateInitialize(
    ctx         IN OUT LCMAggregationType
  ) RETURN NUMBER,

  MEMBER FUNCTION ODCIAggregateIterate(
    self        IN OUT LCMAggregationType,
    value       IN     NUMBER
  ) RETURN NUMBER,

  MEMBER FUNCTION ODCIAggregateTerminate(
    self        IN OUT LCMAggregationType,
    returnValue    OUT NUMBER,
    flags       IN     NUMBER
  ) RETURN NUMBER,

  MEMBER FUNCTION ODCIAggregateMerge(
    self        IN OUT LCMAggregationType,
    ctx         IN OUT LCMAggregationType
  ) RETURN NUMBER
);
/
Run Code Online (Sandbox Code Playgroud)

与身体:

CREATE OR REPLACE TYPE BODY LCMAggregationType
IS
  STATIC FUNCTION ODCIAggregateInitialize(
    ctx         IN OUT LCMAggregationType
  ) RETURN NUMBER
  IS
  BEGIN
    ctx := LCMAggregationType( 1 );
    RETURN ODCIConst.SUCCESS;
  END;

  MEMBER FUNCTION ODCIAggregateIterate(
    self        IN OUT LCMAggregationType,
    value       IN     NUMBER
  ) RETURN NUMBER
  IS
  BEGIN
    IF value IS NOT NULL THEN
      self.value := LCM( self.value, value );
    END IF;
    RETURN ODCIConst.SUCCESS;
  END;

  MEMBER FUNCTION ODCIAggregateTerminate(
    self        IN OUT LCMAggregationType,
    returnValue    OUT NUMBER,
    flags       IN     NUMBER
  ) RETURN NUMBER
  IS
  BEGIN
    returnValue := self.value;
    RETURN ODCIConst.SUCCESS;
  END;

  MEMBER FUNCTION ODCIAggregateMerge(
    self        IN OUT LCMAggregationType,
    ctx         IN OUT LCMAggregationType
  ) RETURN NUMBER
  IS
  BEGIN
    self.value := LCM( self.value, ctx.value );
    RETURN ODCIConst.SUCCESS;
  END;
END;
/
Run Code Online (Sandbox Code Playgroud)

然后,您可以创建自定义聚合函数:

CREATE FUNCTION LCM_AGG( value NUMBER )
RETURN NUMBER
PARALLEL_ENABLE AGGREGATE USING LCMAggregationType;
/
Run Code Online (Sandbox Code Playgroud)

然后,如果您有示例数据:

CREATE TABLE table_name ( id, group_id, numerator, denominator ) AS
SELECT 1, 13,  4,  12 FROM DUAL UNION ALL
SELECT 2, 13, 33, 126 FROM DUAL UNION ALL
SELECT 3, 13,  8,  45 FROM DUAL UNION ALL
SELECT 4, 28, 56, 137 FROM DUAL UNION ALL
SELECT 5, 28, 13, 236 FROM DUAL UNION ALL
SELECT 6, 28, 69, 145 FROM DUAL;
Run Code Online (Sandbox Code Playgroud)

您可以使用查询:

SELECT group_id,
       SUM( numerator ) AS numerator,
       MAX( denominator ) AS denominator
FROM   (
  SELECT group_id,
         numerator * LCM_AGG( denominator ) OVER ( PARTITION BY group_id ) / denominator
           AS numerator,
         LCM_AGG( denominator ) OVER ( PARTITION BY group_id ) as denominator
  FROM   table_name
)
GROUP BY group_id;
Run Code Online (Sandbox Code Playgroud)

哪些输出:

GROUP_ID | 数字 | 分母
-------: | --------: | ----------:
      13 | 974 | 1260
      28 | 4405473 | 4688140

db<>在这里摆弄