2015-02-06 2 views
1

У меня есть данные, что выглядит следующим образом:прок SQL сумма не добавляет правильно

ID Date1   Date2  Paid Amount 
A    1/25/2012 -168.48 
A    1/25/2012 -59.44 
A    1/25/2012 -13.18 
A    1/25/2012 -8.02 
A    1/25/2012 8.02 
A    1/25/2012 13.18 
A    1/25/2012 59.44 
A    1/25/2012 168.48 
A 12/28/2011 1/25/2012 50.00 
A 12/28/2011 1/25/2012 61.00 


Proc sql; 
Create table SUM as 
Select id, date1, date2, sum(paid_amount) as paid_amount 
From SUM_0 
Group by id, date1, date2; 

я получаю что-то вроде этого:

ID Date1  Date2  paid_amount 
A   1/25/2012 4.547474E-13 
A 12/28/2011 1/25/2012 111.00 

Просто Eyeballing, это очевидно, что сумма paid_amount для пустой даты1, но 1/25/2012 date2 должен быть 0. По какой-то причине для этой и других подобных установок я получаю различные суммы с значениями E-13.

+0

выглядит как вопрос с плавающей точкой. Является ли 'paid_amount' валютой или десятичной точкой? – shawnt00

+0

Это числовое значение без определенного формата или информации, с длиной 8. – PinkyL

+0

вы выводите для второго ряда должно быть 111, а не 110.00 .. вы можете проверить здесь, его рабочий тон http://sqlfiddle.com/#!3/8a397 /1........let нам известно, какая у вас структура таблиц – HaveNoDisplayName

ответ

3

Как уже отмечалось, это проблема с плавающей точкой. Так же, как:

2/3 - 1/3 - 1/3 = 0 

но

.6667 - .3333 - .3333 > 0 

Числа с плавающей точкой являются по своей сути неточными.

В SAS вы можете иметь дело с этим несколькими различными способами. Самые простые два:

  • Круглые. round(sum(...),0.01) округляет его до ближайшего 0,01, и вы можете округлить до ближайшего 0.000001, если хотите; обычно E-12 - это то, где вы начинаете видеть проблемы точности с плавающей запятой, поэтому любое количество нулей меньше 10 или около того.
  • Fuzz. Fuzz(...) автоматически округляет числа, близкие к целым, к этому целому числу. Это не округляет иначе, только вещи, близкие к реальному целому числу, становятся единым целым.

Например:

data test; 
    input ID $ Date1 :mmddyy10. Date2 :mmddyy10. Amount; 
    datalines; 
A  .   1/25/2012 -168.48 
A  .   1/25/2012 -59.44 
A  .   1/25/2012 -13.18 
A  .   1/25/2012 -8.02 
A  .   1/25/2012 8.02 
A  .   1/25/2012 13.18 
A  .   1/25/2012 59.44 
A  .   1/25/2012 168.48 
A 12/28/2011 1/25/2012 50.00 
A 12/28/2011 1/25/2012 61.00 
;;;; 
run; 

proc sql; 
    select id, date1, date2, round(sum(amount),.01) 
    from test 
    group by 1,2,3; 
quit; 
+0

Мое впечатление, что значения суммы представляют собой значения валюты, хранящиеся в плавающей запятой. Преобразует ли 'round()' их в новый тип? Если нет, то я думаю, что есть некоторый потенциал для накопления ошибок. Хотя я признаю, что потребуется очень длинный список транзакций, чтобы ошибка переместилась в гроши, стоит ли это рассмотреть? – shawnt00

+0

SAS не имеет других типов: только плавающая точка (по 8 байт по умолчанию, всего 3, если требуется) и символ. Проблема состоит в том, что только две операции могут закончиться тем, что больше не равно точно нулю, что является проблемой, если вы используете 'if x = 0' или подобное в вашем коде. – Joe

+0

Я понимаю, почему округление «исправляет» это, когда сумма должна быть равна нулю. Я просто пытался решить более широкую проблему с помощью float, где предназначен десятичный тип. – shawnt00

0

Возможно, вы добавили отливку, например numeric(10, 2), внутри sum().

sum(cast(paid_amount as decimal(10, 2))) 
+0

Errr Я довольно новичок в sql, вы можете объяснить/разработать? Благодарю. – PinkyL

+0

'PROC SQL' - это только реализация SQL в SAS и не поддерживает функцию' CAST' – mjsqu

+0

Ну, должно быть, есть эквивалент преобразования в десятичный/числовой/валютный тип. Они должны делать это до суммирования. – shawnt00