Home » SQL & PL/SQL » SQL & PL/SQL » How to calculate Highest common factor in SQL
How to calculate Highest common factor in SQL [message #140835] Wed, 05 October 2005 17:34 Go to next message
rtripath
Messages: 3
Registered: October 2005
Location: USA
Junior Member
Hi

Is there any function avaialble in SQL that can return the highest common factor among a bunch of numbers. For example
10,20,25 have a highest common factor of 5.Thanks
Re: How to calculate Highest common factor in SQL [message #140896 is a reply to message #140835] Thu, 06 October 2005 01:34 Go to previous messageGo to next message
tarundua
Messages: 1072
Registered: June 2005
Location: India
Senior Member


I suppose NO , you need to write your own function to do that.

Or else read this link and if you find some then do post back.

http://www.lc.leidenuniv.nl/awcourse/oracle/server.920/a96540/toc.htm

Re: How to calculate Highest common factor in SQL [message #141015 is a reply to message #140835] Thu, 06 October 2005 11:09 Go to previous messageGo to next message
Art Metzer
Messages: 2477
Registered: December 2002
Senior Member
"A bunch"? How about "two"?
SQL> CREATE OR REPLACE FUNCTION find_gcd (
  2      p_n1    IN  POSITIVE
  3  ,   p_n2    IN  POSITIVE
  4  )
  5  RETURN POSITIVE
  6  IS
  7      l_n1    POSITIVE := p_n1;
  8      l_n2    POSITIVE := p_n2;
  9  BEGIN
 10      WHILE NOT (l_n1 = l_n2)
 11      LOOP
 12          CASE SIGN(l_n1 - l_n2)
 13          WHEN +1
 14          THEN l_n1 := l_n1 - l_n2;
 15          ELSE l_n2 := l_n2 - l_n1;
 16          END CASE;
 17      END LOOP;
 18      RETURN (l_n1);
 19  END find_gcd;
 20  /
 
Function created.
 
SQL> SELECT find_gcd(find_gcd(10,15),25) gcd
  2  FROM   DUAL
  3  /
 
       GCD
----------
         5
 
SQL>
Re: How to calculate Highest common factor in SQL [message #141017 is a reply to message #140835] Thu, 06 October 2005 11:33 Go to previous messageGo to next message
edwardstoever
Messages: 12
Registered: February 2005
Location: Pasadena, CA
Junior Member
This is one of the best questions I have seen. Mr Metzer's answer is fantastic.

Is it possible to create an aggregate function to do the same thing? I am not asking you to do it... that would be a big job. I am just curious if it can be done. Does PL/SQL lend itself to creating aggregate functions such as sum(columnn) or count(columnn)?

Thanks for that question and answer!

Edward
Re: How to calculate Highest common factor in SQL [message #141023 is a reply to message #141017] Thu, 06 October 2005 12:39 Go to previous messageGo to next message
Art Metzer
Messages: 2477
Registered: December 2002
Senior Member
Yes, it can be done, usings Oracle's user-defined aggregate functions capabilities.

Here's an example of a custom GCD aggregate function. Note, it's not production safe; anyone implementing this solution would have to determine how to handle negatives, zeroes and non-integers in their particular situation.
SQL> CREATE OR REPLACE TYPE gcd_agg AS OBJECT (
  2      factor  NUMBER
  3  ,   STATIC FUNCTION odciaggregateinitialize (
  4                          sctx IN OUT gcd_agg)
  5      RETURN NUMBER
  6  ,   MEMBER FUNCTION odciaggregateiterate (
  7                          SELF    IN OUT  gcd_agg
  8                      ,   value   IN      NUMBER)
  9      RETURN NUMBER
 10  ,   MEMBER FUNCTION odciaggregateterminate (
 11                          SELF        IN  gcd_agg
 12                      ,   returnvalue OUT NUMBER
 13                      ,   flags       IN  NUMBER)
 14      RETURN NUMBER
 15  ,   MEMBER FUNCTION odciaggregatemerge (
 16                          SELF    IN OUT  gcd_agg
 17                      ,   ctx2    IN      gcd_agg)
 18      RETURN NUMBER
 19  );
 20  /
 
Type created.
 
SQL> CREATE OR REPLACE TYPE BODY gcd_agg AS
  2      STATIC FUNCTION odciaggregateinitialize (
  3                              sctx IN OUT gcd_agg)
  4      RETURN NUMBER
  5      IS
  6      BEGIN
  7          sctx := gcd_agg(TO_NUMBER(NULL));
  8          RETURN (odciconst.success);
  9      END odciaggregateinitialize;
 10
 11      MEMBER FUNCTION odciaggregateiterate (
 12                          SELF    IN OUT  gcd_agg
 13                      ,   value   IN      NUMBER)
 14      RETURN NUMBER
 15      IS
 16          l_value         POSITIVE;
 17          l_return_value  NUMBER;
 18      BEGIN
 19          BEGIN
 20              l_value := ABS(TRUNC(value));
 21              IF (SELF.factor IS NULL
 22              OR SELF.factor <= 0) THEN
 23                  SELF.factor := l_value;
 24              ELSE
 25                  WHILE NOT (SELF.factor = l_value)
 26                  LOOP
 27                      CASE SIGN(SELF.factor - l_value)
 28                      WHEN +1
 29                      THEN SELF.factor := SELF.factor - l_value;
 30                      ELSE l_value := l_value - SELF.factor;
 31                      END CASE;
 32                  END LOOP;
 33              END IF;
 34              l_return_value := odciconst.success;
 35          EXCEPTION
 36              WHEN VALUE_ERROR THEN
 37                  l_return_value := odciconst.error;
 38          END;
 39          RETURN (l_return_value);
 40      END odciaggregateiterate;
 41
 42      MEMBER FUNCTION odciaggregateterminate (
 43                          SELF        IN  gcd_agg
 44                      ,   returnvalue OUT NUMBER
 45                      ,   flags       IN  NUMBER)
 46      RETURN NUMBER
 47      IS
 48      BEGIN
 49          returnvalue := SELF.factor;
 50          RETURN (odciconst.success);
 51      END odciaggregateterminate;
 52
 53      MEMBER FUNCTION odciaggregatemerge (
 54                          SELF    IN OUT  gcd_agg
 55                      ,   ctx2    IN      gcd_agg)
 56      RETURN NUMBER
 57      IS
 58          l_value_1   POSITIVE := SELF.factor;
 59          l_value_2   POSITIVE := ctx2.factor;
 60      BEGIN
 61          IF (l_value_1 IS NULL
 62          OR l_value_1 <= 0) THEN
 63              l_value_1 := l_value_2;
 64          ELSE
 65              WHILE NOT (l_value_1 = l_value_2)
 66              LOOP
 67                  CASE SIGN(l_value_1 - l_value_2)
 68                  WHEN +1
 69                  THEN l_value_1 := l_value_1 - l_value_2;
 70                  ELSE l_value_2 := l_value_2 - l_value_1;
 71                  END CASE;
 72              END LOOP;
 73          END IF;
 74          RETURN (odciconst.success);
 75      END odciaggregatemerge;
 76  END;
 77  /
 
Type body created.
 
SQL> CREATE OR REPLACE FUNCTION gcd (input NUMBER)
  2  RETURN NUMBER
  3  PARALLEL_ENABLE AGGREGATE USING gcd_agg;
  4  /
 
Function created.
 
SQL> CREATE TABLE t (id VARCHAR2(2), n INT)
  2  /
 
Table created.
 
SQL> INSERT INTO t VALUES ('A',25);
SQL> INSERT INTO t VALUES ('A',30);
SQL> INSERT INTO t VALUES ('A',55);
SQL> INSERT INTO t VALUES ('B',77);
SQL> INSERT INTO t VALUES ('C',7176);
SQL> INSERT INTO t VALUES ('C',5428);
SQL> INSERT INTO t VALUES ('C',7820);
 
SQL> SELECT id, gcd(t.n) FROM t GROUP BY id
  2  /
 
ID   GCD(T.N)
-- ----------
A           5
B          77
C          92
 
SQL>
Re: How to calculate Highest common factor in SQL [message #141026 is a reply to message #141015] Thu, 06 October 2005 12:47 Go to previous messageGo to next message
rtripath
Messages: 3
Registered: October 2005
Location: USA
Junior Member
Appreciate the reply. But how we can expand to do for n numbers. I can see it might be useful for others.
Re: How to calculate Highest common factor in SQL [message #141030 is a reply to message #140835] Thu, 06 October 2005 13:06 Go to previous message
edwardstoever
Messages: 12
Registered: February 2005
Location: Pasadena, CA
Junior Member
Well, as far as I am concerned, you have answered the question beautifully. I hope you don't mind if I post a copy of your code on my website as an example - I will give you credit - contact me here: http://www.database-expert.com/contact.asp. I have never heard of user-defined aggregate functions, but the thought has crossed my mind from time to time, so this is welcome "news".

Regarding using his function for n numbers (an unknown quantity of numbers), you can use it to get the results of two numbers and compare the results with a third number, which could then be done again for a fourth, fifth, sixth, and so on. Modifying it to handle a table of numbers should not be too difficult.

Well done!

Edward
Cool
Previous Topic:inserting from col to row , data order problem in desitnation table
Next Topic:Oracle Table partition
Goto Forum:
  


Current Time: Thu Sep 02 20:24:51 CDT 2010

Total time taken to generate the page: 0.09155 seconds
.:: Forum Home :: Blogger Home :: Wiki Home :: Contact :: Privacy ::.