【问题标题】:SAS - Programatically Identifying Numeric Variables that represent Date/Time/DatetimesSAS - 以编程方式识别表示日期/时间/日期时间的数值变量
【发布时间】:2016-07-20 00:14:32
【问题描述】:

我正在尝试找到一种方法来识别代表日期、时间或日期时间的数字变量子集,该数据集包含许多数字或字符类型的变量。目标是拥有一个可以针对任何给定数据集运行的宏或模板。我相信这些变量的 SAS 格式应该正确地表示变量是什么,但我想看看我是否可以避免创建一些代码来解析任何适用的格式名称的 SAS 格式的文本。

我最初认为应该可以执行以下操作来获取数据集的 SAS 格式,然后根据作为日期/时间/日期时间返回的列执行各种操作。

PROC SQL;
   CREATE TABLE lib_X.Dataset_A AS
   SELECT tbl_CL.LIBNAME
         ,tbl_CL.MEMNAME AS TABLE_NAME
         ,tbl_CL.NAME    AS COLUMN_NAME
         ,tbl_CL.FORMAT  AS SAS_Format
         ,tbl_CL.TYPE    AS SAS_Type
         ,tbl_CL.varnum
         ,tbl_CL.LENGTH
   FROM DICTIONARY.COLUMNS AS tbl_CL
   WHERE tbl_CL.MEMNAME = %UPCASE("&SAS_DatasetNm")
     AND tbl_CL.LIBNAME = %UPCASE("&SAS_LibNm");
QUIT;

接着是:

DATA lib_X.Dataset_A;
   SET lib_X.Dataset_A;
   IF FCN_FORMAT_TYPE(SAS_Format) = "DATETIME" 
   THEN ...;
RUN;

FCN_FORMAT_TYPE 函数是检查 SAS 格式并返回变量是 4 categories of SAS Format(字符、数字、日期/时间或 ISO 8601)中的哪一个的函数,但似乎没有我可以找到执行此操作的现有功能。也许还有另一种可行的方法?

目前在 Linux 服务器上的 SAS 9.4 M2 上运行。该代码将主要通过批处理文件使用,但也可能通过企业指南(EG 7.1 或 6.1)

【问题讨论】:

    标签: sas


    【解决方案1】:

    没有开箱即用的解决方案,但这是一个可行的解决方案。

    为简单起见,我们只使用日期,不包括时间和日期时间格式。该解决方案可以很容易地推广到包括这些。

    作为第一步,您需要制定过滤器,以选择您可以预期的合理日期格式。这是一个将匹配大约 100 种 SAS 日期格式的查询示例。

    proc sql;
      create table fmts as
      select fmtname
        from sashelp.vformat
       where fmttype = "F"
             and fmtname not like '$%'
             and prxmatch("/(DATE|YY|YEAR)/",fmtname)
             and not prxmatch("/(DT|TIME)/",fmtname)
       order by fmtname;
    quit;
    

    一旦您微调了 WHERE 过滤器,您就可以在宏例程中使用它,如下所示,其中第三个参数 vmname 是您希望在其中存储日期列名称的全局宏变量的名称.

    %macro getDateCols(libname, dataset, vmname);
    
      %global &vmname;
    
      proc sql noprint;
        select name
          into :&vmname separated by ", " /* Use ", " or " " depending on your needs */
          from dictionary.columns
         where libname = upcase("&libname")
               and memname = upcase("&dataset")
               and format not like '$%'
               and prxmatch("/(DATE|YY|YEAR|MONTH|DAY|WEEK)/", format)
               and not prxmatch("/(DT|TIME)/", format);
      quit;
    
    %mend getDateCols;
    

    调用宏后,你应该得到存储在&dsdates中的列名HireDate

    %getDateCols(sasuser, empdata, dsdates);
    %put &dsdates;
    

    那么就可以在proc sql中使用宏变量了,例如...

    proc sql;
      select &dsdates 
       from sasuser.empdata;
    quit;
    

    【讨论】:

      【解决方案2】:

      Dominic 的回答让我知道了如何解决它,使用相同的通用方法,但将其放在 PROC FCMP 函数而不是宏中。

      PROC FCMP OUTLIB=LIB_X.FCMP_FUNCS.Format_Category_ID;
         FUNCTION Format_Category(VAR_Format $, VAR_Type $) $ 16
              GROUP = 'Format Category ID'
              LABEL = 'Pass SAS variable type and format as CHAR and it will return what sort of variable it is. 
                       Breaks down date/time/dt formats into independent categories.';
              LENGTH FORMAT_CATEGORY $16;
              SELECT;
                  WHEN        (MISSING(VAR_Format))                                                   FORMAT_CATEGORY = 'MISSING_FORMAT';
                  WHEN        (VAR_Type = 'CHAR')                                                     FORMAT_CATEGORY = 'CHARACTER_FORMAT';
                  WHEN        (PRXMATCH("/S370FZDT/", VAR_Format))                                    FORMAT_CATEGORY = 'NUMERIC_FORMAT';
                  WHEN        (PRXMATCH("/8601/", VAR_Format))                                        FORMAT_CATEGORY = 'ISO_8601_FORMAT';
                  WHEN        (PRXMATCH("/(DT|DATEAMPM|DATETIME)/", VAR_Format))                      FORMAT_CATEGORY = 'DATETIME_FORMAT';
                  WHEN        (PRXMATCH("/(HHMM|HOUR|MMSS|TIME|TOD)/", VAR_Format))                   FORMAT_CATEGORY = 'TIME_FORMAT';
                  WHEN        (PRXMATCH("/(DAT|DAY|YY|DOW|JUL|MON|QTR|WEEK|YEAR)/", VAR_Format))      FORMAT_CATEGORY = 'DATE_FORMAT';
                  WHEN        (VAR_Type = 'NUM')                                                      FORMAT_CATEGORY = 'NUMERIC_FORMAT';
                  OTHERWISE                                                                           FORMAT_CATEGORY = 'UNKNOWN';
              END;
              RETURN(FORMAT_CATEGORY);
         ENDSUB;
      

      它绝对不是万无一失的,但它适用于我的目的,并希望对其他人有用。我要补充的最大警告是,处理用户定义的格式将是一触即发,因为它只是解析作为字符变量传递的 SAS 格式,所以如果名称与我正在使用的正则表达式重叠,所有的赌注关闭。

      【讨论】:

        【解决方案3】:

        我们编写了一个 fcmp 函数来执行此操作,它采用 SAS 文档中的所有 DATE / DATETIME / TIME 格式。

        来源在 github,因此您可以轻松添加任何缺少的格式:https://github.com/sasjs/core/blob/main/fcmp/mcf_getfmttype.sas

        文档:https://core.sasjs.io/mcf__getfmttype_8sas.html

        宏调用示例:

        %put fmt_type=%sysfunc(mcf_getfmttype(TIME9.));
        

        【讨论】:

          猜你喜欢
          • 2013-06-15
          • 2016-09-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-16
          • 1970-01-01
          • 2015-10-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多