比较SAS中两个数值时的问题

Problem when comparing two numeric values in SAS

长话短说,我需要比较两个数据集(AB)。 B 应该是 A 的副本,但在 Impala 服务器上。每天我都通过 SQL 传递从 Impala 服务器检索 B 到 SAS。

我正在编写一个每天 运行 的程序,以确保这两个数据集匹配 1:1。 但是,我正在努力解决数值近似值(精度)问题。

下面是A的例子:

ID value
01 0
02 5000
03 978908.69
04 109789503.12
05 49505954.92

为了进行比较,我将两列连接到 conc 列中,然后比较 AB

data want;
set have;
conc=cats(id,value);
run;

这基本上适用于除一个之外的所有观察结果。 观察值 A9128554507.9B9128554507.8。没有格式或信息应用于变量。

但是,当对值变量应用 comma32.30 格式时,我看到 AB 的值相同 9128554507.850000000000000000000。所以他们应该是一样的。

然后我在CATS函数

的文档中看到了以下内容

The CATS function removes leading and trailing blanks from numeric arguments after it formats the numeric value with the BESTw. format.

然后我认为将数字变量转换为字符变量是个好主意。 我是用这个宏做的:

/*macro to convert all numeric to char*/
%macro vars(dsn, outp);
  %let list=;
  %let type=;
  %let dsid=%sysfunc(open(&dsn));
  %let cnt=%sysfunc(attrn(&dsid,nvars));
   %do i = 1 %to &cnt;
    %let list=&list %sysfunc(varname(&dsid,&i));
    %let type=&type %sysfunc(vartype(&dsid,&i));
   %end;
  %let rc=%sysfunc(close(&dsid));
  data &outp(drop=
    %do i = 1 %to &cnt;
     %let temp=%scan(&list,&i);
       _&temp
    %end;);
   set &dsn(rename=(
    %do i = 1 %to &cnt;
     %let temp=%scan(&list,&i);
       &temp=_&temp
    %end;));
    %do j = 1 %to &cnt;
     %let temp=%scan(&list,&j);
   /** Change C to N for numeric to character conversion  **/
     %if %scan(&type,&j) = N %then %do;
   /** Also change INPUT to PUT for numeric to character  **/
      &temp=PUT(_&temp,best.);
     %end;
     %else %do;
      &temp=_&temp;
     %end;
    %end;
  run;
%mend vars;

看到使用了best.格式。不幸的是,我最终得到了与之前相同的值,9128554507.9A9128554507.8B 的值。不知道这两个数据集之间发生了什么? “真实”值似乎是相同的,但是当对两者应用 best. 格式时,SAS 将 A 的值四舍五入为 .9 并将 B 的值四舍五入至 .8.

有什么解决方法吗?尝试在数据线语句中手动输入观察时,我无法重现错误。我不想将值四舍五入为预定义的小数。理想情况下,我想动态地将值 运行 归类到 number of actual decimal - 1(例如 3462829.374 变为 3462829.37 并且 18726347.39 变为 18726347.3)两个表,然后比较它们。

我不知道你的大问题是什么,但要在最后回答问题,只需使用 BEST32 将数字转换为字符串即可。当结果字符串包含小数点时格式化并删除最后一个字符。

data test;
  input number expect . ;
  string=put(number,best32.-l);
  if index(string,'.') then string=substrn(string,1,length(string)-1);
  format number best32. ;
cards;
3462829.374  3462829.37
18726347.39  18726347.3
12345 12345
.
;

结果:

Obs         number    expect        string

 1     3462829.374    3462829.37    3462829.37
 2     18726347.39    18726347.3    18726347.3
 3           12345    12345         12345
 4               .

你能计算模糊并检查它吗?

* retrieve a data from impala;
proc sql;
  create table b as select * from connection to impala (select * from a);

data a_b_fuzz;
  merge a b(rename=number=impala_number);
  by id;
  fuzz = number - impala_number;
run;