【问题标题】:SAS Date Formats Incompatible with SQL Server DateSAS 日期格式与 SQL Server 日期不兼容
【发布时间】:2013-05-23 22:00:55
【问题描述】:

我是 SAS 的新手,最近我们将一些 SAS 数据集迁移到 SQL Server 表中,但我们仍在使用 SAS 进行分析。当 SAS 尝试从 SQL Server 表中引入数据并让 SAS 检查 srv_edt 日期是否在 dos_beg_dt1 和 dos_end_dt1 的 SAS 日期之间时,我遇到了问题。

当 SAS 尝试比较日期时,我收到以下错误:错误:WHERE 子句运算符需要兼容的变量。

dos_beg_dt1、dos_end_dt1 和 srv_edt(SQL 日期格式)都以 yyyy-mm-dd 格式“出现”。当我将 srv_edt 带入 SAS 表时,它会将其读取为字符日期。因此,我尝试更改日期的格式,然后我会收到如下错误:错误:变量 srv_edt 已被定义为字符和数字。我似乎找不到正确的格式或函数来让 SAS 进行比较以查看 srv_edt (SQL) 是否介于 dos_beg_dt1 和 dos_end_dt1 SAS 日期之间。

我使用的代码如下:

libname sql odbc dsn=test schema=dbo;

%let dos_beg_dt1 = %sysfunc(intnx(qtr,&date,-1,beginning),yymmdd10.);
%let dos_end_dt1 = %sysfunc(intnx(qtr,&date,-1,end),yymmdd10.);

data sample;
set sql.table;
where &dos_beg_dt1 <= srv_edt <= &dos_end_dt1;
run;

作为参考,我使用 SAS 9.2 通过 odbc 连接到 SQL Server 2008。

任何帮助或建议将不胜感激。

【问题讨论】:

    标签: sql-server-2008-r2 odbc sas


    【解决方案1】:

    SAS 存储和使用数据作为数值变量。如果您在将数据库迁移到 SQL Server 时没有将 srv_edt 列标识为日期列,那么现在一切都会正确处理。

    我假设当前和将来您只会将表存储在 SQL Server 中,所有处理都将在 SAS 中。

    你有几个选择。

    1/ 重新迁移 SAS 表,但将所有日期、时间和日期时间列标识为数字。它们都可以存储为 8 字节浮点数。日期变量也可能存储(在 SQL Server 中)是长整数。代码需要稍作改动,以便宏变量是数字的。

    %let dos_beg_dt1 = %sysfunc(intnx(qtr,&date,-1,beginning));
    %let dos_end_dt1 = %sysfunc(intnx(qtr,&date,-1,end));
    

    2/ 将日期、时间和日期时间变量保留为SQL Server 格式,并在使用数据时更改列的数据类型。 (请注意,输出需要反向操作)。 SQL Server 会将日期变量显示为字符串(字符),因此您上面的表达式需要是 -

    %let dos_beg_dt1 = %sysfunc(intnx(qtr,&date,-1,beginning));
    %let dos_end_dt1 = %sysfunc(intnx(qtr,&date,-1,end));
    
    data sample;
    set sql.table;
    
    where &dos_beg_dt1 <= (input(srv_edt, yymmdd10.0))  <= &dos_end_dt1;
    

    确保在使用 SAS 处理时类型是数字,这就是输入函数将执行的操作。

    3/ 以 SQL Server 格式保留日期、时间和日期时间变量,并更改您的工作以适应这一事实。也就是说,比较将使用字符数据,输出将需要生成字符。 SQL Server 会将日期变量显示为字符串(字符),因此您上面的表达式需要是 -

    %let dos_beg_dt1 = %sysfunc(intnx(qtr,&date,-1,beginning), yymmdd10.);
    %let dos_end_dt1 = %sysfunc(intnx(qtr,&date,-1,end), yymmdd10.);
    
    data sample;
    set sql.table;
    
    where ("&dos_beg_dt1" <= srv_edt) and
       (srv_edt <= "&dos_end_dt1");`
    

    注意双引号“”需要周围的宏变量,因为这样 比较是数字。

    【讨论】:

    • 感谢您提供的各种选择!由于我无法重新迁移我正在使用的数据,因此我能够根据您的建议在指定的时间范围内提取数据。
    【解决方案2】:

    如果列 srv_edt 在您的 SAS 数据集中显示为字符变量,这意味着它确实是一个字符变量,或者它已被您使用的 ODBC 驱动程序转换为字符(可能因为 ODBC 不支持本机数据类型)。

    如果可能,您最好将其更改为 PROC SQL 直通查询。您需要找出与 SAS intnx 函数对应的本机语法(我无法帮助您)。如所写,必须读取整个表(因为您使用的是 SAS 函数)。如果使用 pass-thru 查询,SAS 将只接收与 whee 子句匹配的行。

    在 ODBC 驱动程序中可能存在控制此行为的设置。我将在您的问题中添加 ODBC 和 SQL Server 标记;你可能会得到更多的“点击”。

    【讨论】:

      【解决方案3】:

      SQL Server 在 SQL Server 2008 中引入了新的日期和日期时间类型(以前,所有日期/日期时间变量只有一种类型)。 This usage note 建议您需要为 SAS 安装一组新的 SQL Server ODBC 驱动程序才能正确读取日期变量。它建议如果您在进行 ODBC 连接的计算机上安装了 SQL Server 2008 工具(如 SQL Server Management Studio),则可以正常安装,但您可能安装了多个驱动程序并且需要确保使用正确的驱动程序。

      也就是说,使用传递 SQL 来拉取数据并不是一个坏主意,因为这可能会使拉取更容易(因为您不必担心 ODBC 驱动程序) .广义的直通连接字符串是

      proc sql;
         connect to odbc (required="driver=sql server native client 10.0;
      Server=server;Trusted_Connection=Yes;DATABASE=database;");
        create table X as select * from connection to odbc(... sql server native code here ...);
      quit;
      

      从您的问题看来,您更像是一个 SQL 人,然后可以自己构建查询;如果不是,请编辑问题以包含该请求(然后 SQL Server 人员或我自己将回答)。您可以在该查询中使用 SAS 宏变量(即传递当前日期),只要您不将它们或查询用单引号括起来。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-20
        • 1970-01-01
        相关资源
        最近更新 更多