2011-07-06 2 views
2

У меня есть серия вычислений в DB DB2 SQL, которые хранятся как float со значением по умолчанию 0.0.Почему эта сумма процентов не составляет до 100%?

таблица обновляется следующим образом:

CREATE TABLE MY_CALC_DATA_TABLE 
(
    CALCDATE     TIMESTAMP, 
    INDIV_CALC_DURATION_IN_S FLOAT WITH DEFAULT 0.0, 
    CALC_TIME_PERCENTAGE  FLOAT WITH DEFAULT 0.0 
) 

Использование sproc. Я расчет суммы следующим образом:

CREATE OR REPLACE PROCEDURE MY_SCHEMA.MY_SPROC (IN P_DATE TIMESTAMP) 
    LANGUAGE SQL 
    NO EXTERNAL ACTION 
BEGIN 
    DECLARE V_TOTAL_CALC_TIME_IN_S FLOAT DEFAULT 0.0; 

    -- other stuff setting up and joining data 

    -- Calculate the total time taken to perform the 
    -- individual calculations 

    SET V_TOTAL_CALC_TIME_IN_S = 
     (
      SELECT 
       SUM(C.INDIV_CALC_DURATION_IN_S) 
      FROM 
       MY_SCHEMA.MY_CALC_DATA_TABLE C 
      WHERE 
       C.CALCDATE = P_DATE 
     ) 

    -- Now calculate each individual calculation's percentage 
    -- of the toal time. 

    UPDATE 
     MY_SCHEMA.MY_CALC_DATA_TABLE C 
    SET 
     C.CALC_TIME_PERCENTAGE = 
      (C.INDIV_CALC_DURATION_IN_S/V_TOTAL_CALC_TIME_IN_S) * 100 
    WHERE 
     C.CALCDATE = P_DATE; 

[email protected] 

Проблема, когда я сумма всех значений CALC_TIME_PERCENTAGE для указанного CALC_DATE всегда меньше, чем 100% с суммой быть такими значениями, как 80% или 70% для разных CALC_DATES.

Мы говорим о расчетах между 35k и 55k с максимальным процентом индивидуального расчета от общего количества, рассчитанного выше, равным 11% и лотов расчетов в диапазоне 0.00000N%.

Чтобы рассчитать общий процент Я использую простой запрос:

SELECT 
    SUM(C.CALC_TIME_PERCENTAGE) 
FROM 
    MY_SCHEMA.MY_CALC_DATA_TABLE C 
WHERE 
    C.CALCDATE = P_DATE; 

Любые предложения?

Обновление: Реорганизация выписки. как предполагалось, исправили проблему. Благодарю. BTW В DB2 FLOAT и DOUBLE используются те же типы. И теперь, чтобы прочитать эту предложенную бумагу по поплавкам.

+0

(Возможно) Глупый вопрос: что произойдет, если вы умножаетесь с 100.0 insead 100? –

+0

Вместо обновления запустите SELECT, включая номер столбца и функцию, и проверьте, является ли округление вашей проблемой. – niktrs

+0

Обычно он должен давать тот же результат. – niktrs

ответ

3

Если поле C.INDIV_CALC_DURATION_IN_S было Integer, я бы предположил, что это ошибка округления. Снова читайте, это не проблема, так как тип данных: FLOAT.

Вы все еще можете попробовать использовать это. Я не удивлюсь, если это yileded (slighly) иные результаты, чем предыдущий метод:

SET 
    C.CALC_TIME_PERCENTAGE = 
     (C.INDIV_CALC_DURATION_IN_S * 100.0/V_TOTAL_CALC_TIME_IN_S) 

Но вы говорите, что есть много строк в расчете на определенную дату, так что это может быть Из-за этого возникает ошибка округления. Попробуйте с типом данных DOUBLE в обоих полях (или, по крайней мере, поле CALC_TIME_PERCENTAGE) и посмотрите, уменьшается ли разница с 100%.

Я не уверен, что DB2 имеет DECIMAL(x,y) Тип данных. В этом случае это может быть более уместным.


Другая проблема заключается в том, как вы находите сумму CALC_TIME_PERCENTAGE. Я полагаю, вы (и все остальные) будете использовать:

 SELECT 
      P_DATE, SUM(CALC_TIME_PERCENTAGE) 
     FROM 
      MY_SCHEMA.MY_CALC_DATA_TABLE C 
     GROUP BY P_DATE 

Таким образом, у вас нет способа определить, в каком порядке суммирование будет сделано. Оно не может быть даже можно определить, что, но вы можете попробовать:

 SELECT 
      P_DATE, SUM(CALC_TIME_PERCENTAGE) 
     FROM 
      (SELECT 
       P_DATE, CALC_TIME_PERCENTAGE 
      FROM 
       MY_SCHEMA.MY_CALC_DATA_TABLE C 
      ORDER BY P_DATE 
        , CALC_TIME_PERCENTAGE ASC 
     ) AS tmp 
     GROUP BY P_DATE 

оптимизатор может игнорировать интерьер ORDER BY, но это стоит выстрел.


Другая возможность для этой большой разницы в том, что строки удаляются из таблицы между UPDATE и SHOW percent SUM операций.

Вы можете проверить, если это произойдет, выполнив вычисления (без UPDATE) и суммируя:

 SELECT 
      P_DATE 
      , SUM(INDIV_CALC_DURATION_IN_S * 100.0/T.TOTAL)     
      AS PERCENT_SUM 
     FROM 
      MY_SCHEMA.MY_CALC_DATA_TABLE C 
      , (SELECT SUM(INDIV_CALC_DURATION_IN_S) AS TOTAL 
       FROM MY_SCHEMA.MY_CALC_DATA_TABLE 
      ) AS TMP 
     GROUP BY P_DATE 
+1

Почему вы считаете, что это сработает? Умножьте на 100 сначала, чтобы свести к минимуму ошибки округления или умножить на 100.0, чтобы избежать неявного литья вычисления в INT? – MatBailie

+1

@Dems: второй. К сожалению, я пропустил чтение части «FLOAT». –

+3

Примечание: Я полагаю, что причина использования порядка зависит от поведения FLOAT (хорошо хранить огромные или крошечные числа, но не огромные числа с микроскопической точностью). Если вы начинаете с 11%, а затем добавляете 0,000000000000000001%, результирующий поплавок может не иметь возможности для (относительно большого) количества с такой небольшой долей и начинать вводить ошибки округления. Сначала скомбинировавшись с наименьшим, вы с меньшей вероятностью столкнетесь с сценарием, где меньшая фракция «потеряна». (Но я не уверен, что ORDER BY справится с этим.) – MatBailie

2

Может быть проблемой округления. Попробуйте вместо этого C.INDIV_CALC_DURATION_IN_S * 100/V_TOTAL_CALC_TIME_IN_S.

+1

+1. Одна и та же проблема была однажды с преобразованием единиц. Первое умножение, а затем деление решало проблему. – niktrs

1

Если C.INDIV_CALC_DURATION_IN_S очень мало, но у вас есть большое количество строк (и, таким образом, V_TOTAL_CALC_TIME_IN_S становится большим по сравнению), то

(C.INDIV_CALC_DURATION_IN_S/V_TOTAL_CALC_TIME_IN_S) * 100 

может привести к потере точности, особенно если вы используете FLOAT с.

Если это так, то изменение расчет (как уже упоминалось в другом месте), чтобы

(C.INDIV_CALC_DURATION_IN_S * 100)/V_TOTAL_CALC_TIME_IN_S 

должен увеличить сумму, хотя он не может получить вас вплоть до 100%

Если это случай и много измерений - это небольшие доли секунды, я бы рассмотрел возможность выходить за рамки этой процедуры: могли ли времена записываться, скажем, в милли- или микросекундах? Либо вы получите некоторый запас за дополнительные значащие цифры.

+1

Действительно ли это (переход на милли или микросекунды) действительно имеет значение? Полученный процент (или отношение) даст тот же результат с тем же числом значимых цифр, которые необходимы для хранения значения. – MatBailie

+0

@Dems Um. Да. Я сбиваю с толку точность исходного измерения с точностью рассчитанного выхода. Меня часто путают ... ;-) –

Смежные вопросы