Как использовать агрегатную функцию для строковых значений столбцов? - PullRequest
2 голосов
/ 07 июля 2011

Я использую PostgreSQL, у меня есть один столбец с именем Result в Job таблице, он содержит значения типа 2/3, 1/3, 2/3.

Например: Job строк таблицы:

job_id result
------ ------
1      2/3
2      1/3
3      2/3

Я хочу применить статистическую функцию к столбцу result таким образом, чтобы Я могу получить результат как: 5/9

Но Result имеет столбец текстового типа, и мы не можем напрямую применить функцию sum / avg / min / max и т. Д. К этому столбцу.

Кто-нибудь может предложить какой-либо другой подход для достижения этого результата с помощью самого запроса?

Все предложения приветствуются.

Спасибо.

Ответы [ 2 ]

3 голосов
/ 07 июля 2011
SELECT SUM( dividend ) || '/' || SUM( divisor )
       AS FractionOfSums
     , AVG( dividend / divisor )        
       AS AverageOfFractions
FROM
  ( SELECT CAST(substr(result, 1, position('/' in result)-1 ) AS int)
           AS dividend
         , CAST(substr(result, position('/' in result)+1 ) AS int)
           AS divisor
    FROM rows
  ) AS division
1 голос
/ 07 июля 2011

В дополнение к отличному ответу ypercube, если вы хотите упростить дробь, вам нужно найти наибольший общий делитель.

Вот псевдокод для хранимой функции, которая может сгенерировать это:

CREATE FUNCTION gcd(x int, y int) RETURNS int DETERMINISTIC
BEGIN
  DECLARE dividend int;
  DECLARE divisor int;
  DECLARE remainder int;

  SET dividend := GREATEST(x, y);
  SET remainder := LEAST(x, y);

  WHILE remainder != 0 DO
    SET divisor = remainder;
    SET remainder = MOD(dividend, divisor);
    SET dividend = divisor;
  END WHILE;

  RETURN divisor;
END

Теперь вы можете переписать запрос в:

SELECT (dividend/MyGCD) || '/' || (divisor/MyGCD) as FractionOfSums
  , AverageOfFractions 
FROM ( 
  SELECT 
    SUM( dividend ) as dividend
    , SUM( divisor ) AS divisor      
    , gcd(SUM( dividend ),SUM( divisor )) as MyGCD 
    , AVG( dividend / divisor ) AS AverageOfFractions 
  FROM ( 
    SELECT CAST(substr(result, 1, position('/', result)-1 ) AS int) AS dividend
        , CAST(substr(result, position('/', result)+1 ) AS int) AS divisor    
    FROM rows ) AS division 
) as Elements 

Обратите внимание, что GCD - очень медленная функция.

...