Oracle中分母的最小公倍数计算Table
Calculation of Least Common Multiple of the Denominator in Oracle Table
我想创建一个 table 来更好地说明我的问题
这是我在 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);
end;
CREATE OR REPLACE function SAMPLE.gcd(a number, b number)
return number is
begin
if b = 0 then
return a;
else
return gcd(b,mod(a,b)); end
if; end;
2-增加分子值与分母列的值成比例。像这样的数学公式:
(lcm(values of denominator(1..to -n)) / values of denominator ) *
values of the numerator
3-通过按 group_id 值
分组对新计算值求和
对我来说,sql、函数、视图等所有将使这项工作完整的项目都是 suitable。
我能为此做些什么。
[TL;DR] 编写您自己的自定义聚合函数。
鉴于您的 GCD
和 LCM
功能:
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;
/
然后您可以为要在自定义聚合中使用的类型创建规范:
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
);
/
配正文:
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;
/
然后您可以创建自定义聚合函数:
CREATE FUNCTION LCM_AGG( value NUMBER )
RETURN NUMBER
PARALLEL_ENABLE AGGREGATE USING LCMAggregationType;
/
那么如果你有样本数据:
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;
您可以使用查询:
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;
输出:
GROUP_ID | NUMERATOR | DENOMINATOR
-------: | --------: | ----------:
13 | 974 | 1260
28 | 4405473 | 4688140
db<>fiddle here
我想创建一个 table 来更好地说明我的问题
这是我在 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); end;
CREATE OR REPLACE function SAMPLE.gcd(a number, b number)
return number is
begin if b = 0 then return a; else return gcd(b,mod(a,b)); end if; end;
2-增加分子值与分母列的值成比例。像这样的数学公式:
(lcm(values of denominator(1..to -n)) / values of denominator ) * values of the numerator
3-通过按 group_id 值
分组对新计算值求和对我来说,sql、函数、视图等所有将使这项工作完整的项目都是 suitable。
我能为此做些什么。
[TL;DR] 编写您自己的自定义聚合函数。
鉴于您的 GCD
和 LCM
功能:
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;
/
然后您可以为要在自定义聚合中使用的类型创建规范:
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
);
/
配正文:
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;
/
然后您可以创建自定义聚合函数:
CREATE FUNCTION LCM_AGG( value NUMBER )
RETURN NUMBER
PARALLEL_ENABLE AGGREGATE USING LCMAggregationType;
/
那么如果你有样本数据:
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;
您可以使用查询:
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;
输出:
GROUP_ID | NUMERATOR | DENOMINATOR -------: | --------: | ----------: 13 | 974 | 1260 28 | 4405473 | 4688140
db<>fiddle here