如何用固定宽度的字符列替换数字列?

时间:2016-06-15 13:42:30

标签: sql sas

我有一个包含邮政编码字段(数字类型)的表格,有些邮政编码只包含4位数字。我需要用前导空格填充4位邮政编码。 我创建了一个字符如下:

proc sql;
create table myTable as
select * , put(Zip,5.) as ZipChar
from Mytable;

create table myTable as
select *, case when Zip<10000 then " "||ZipChar else ZipChar end as Zip_Fixed
from Mytable;
quit;

现在我的困难是如何找到Zip_Fixed而不是Zip列。 Zip是数字类型,Zip_Fixed是字符类型。必须更换,因为必须保留列的顺序。我对所有其他创造性解决方案都很感兴趣。

谢谢, 阿迪

3 个答案:

答案 0 :(得分:3)

我写了一个宏,它在几个月前重新排序变量。它可能不是最短的方式,但它应该可以解决你的问题。

假设您有一个数据集,并希望在move_me

之前移动v1
data temp;
   input v1 v2 v3 v4 v5 move_me;
   datalines;
    1 2 3 4 5 0
    1 2 3 4 5 0
    1 2 3 4 5 0
    ;
run;

运行下面的%order宏:

%macro order(dsn, var1, before_or_after, var2);

/*  get list of variables in your dataset from dictionary.columns*/
    proc sql;
        create table vars as select 
            varnum, name
            from dictionary.columns
            where memname = upcase("&dsn.");
    quit;

/*  assign the final position of the variable that you want to move*/
    proc sql;
        create table vars2 as select
            a.*,
            case when a.name = "&var1." then max(b.varnum) else . end as varnum_want
            from vars as a
            left join vars (where = (name = "&var2.")) as b
            on a.varnum = b.varnum;
    quit;

/*  move the variable to that location*/
    data vars3 (drop = varnum_want);
        set vars2;

        %if &before_or_after. = before %then %do;
            if name = "&var1." then varnum = varnum_want - 0.5;
        %end;

            %else %if &before_or_after. = after %then %do;
                if name = "&var1." then varnum = varnum_want + 0.5;
            %end;

            %else %do;
                putlog "ERROR: Pick 'before' or 'after'";
            %end;

        proc sort; by varnum;

    run;

/*  select variables into a macro variable in correct order*/
    proc sql noprint;
        select name into: ordered_vars separated by " " from vars3 order by varnum;
    quit;

/*  reorder variables*/
    data &dsn._reordered;
        retain &ordered_vars.;
        set &dsn.;
    run;

%mend order;

然后,您可以使用语法%order(temp, move_me, before, v1);创建名为temp_reordered的数据集,该数据集在move_me之前已插入v1。在您的情况下,听起来您希望运行%order(myTable, zipFixed, before, [your 8th variable's name])然后删除任何无关的变量以保持变量的正确排序。

答案 1 :(得分:2)

您对PUT()函数的使用将创建一个带前导空格的字符字段。你的第二步将增加另一个领先空间。

为什么不直接使用前导零?然后,这些值看起来更像数字,仍然可以正确排序。

put(zip,Z5.)

如果最终目标是创建一个具有固定宽度字段的文本文件(作为您提及的其他注释之一),那么您只需使用用于编写文本文件的PUT语句中的格式。

data _null_;
  set mytable ;
  file 'myfile.txt'; 
  put ... zip 5. ... ;
run;

答案 2 :(得分:0)

如Tom所说,邮政编码通常用零填充,而不是空格。在少数情况下它们也可以是三位数(例如波多黎各),所以要注意这一点。

此外,根据您的需要,格式化列可能就足够了。它不会更改数字列的内容,但会改变它的显示方式。

proc datasets;
  modify have;
  format zip z5.;
quit;

同样,对于某些用例,这不会有所帮助,但对于其他用户而言,它可能优于转换为角色。