SAS-用程序识别表示日期/时间/日期时间的数字变量



我正试图找到一种方法,从包含许多数字或字符类型变量的任意数据集中识别表示日期、时间或日期时间的数字变量子集。目标是有一个宏或模板,我可以在任何给定的数据集上运行。我相信这些变量的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格式并返回变量是SAS格式的四类(字符、数字、日期/时间或ISO 8601)中的哪一类的函数,但我似乎找不到现有的函数可以做到这一点。也许还有另一种方法可行?

当前在Linux服务器上的SAS 9.4 M2上运行。该代码将主要通过批处理文件使用,但也可能通过企业指南(EG 7.1或6.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;

调用宏后,应该将列名HireDate存储在&dsdates:中

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

然后可以在proc-sql中使用宏变量,例如。。。

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

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格式,所以如果名称与我使用的正则表达式重叠,所有的赌注都会被取消

我们编写了一个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.));

最新更新