【问题标题】:Use IN statement on alphanumeric string variable对字母数字字符串变量使用 IN 语句
【发布时间】:2013-11-11 19:57:34
【问题描述】:

我需要进行查询并在其中使用IN 语句。

首先我读入一个txt文件:

filename ticklist '/home/mypath/myfile.txt';
data sp500;
     infile ticklist;
     input smbl $;
     smbl=upcase(smbl);
run;

这给了我变量sp500.smbl 的值AA, HNZ, ...(超过500)。

然后我进行查询:

data result;
     set mydata;
     where also company_symbol IN (sp500.smbl);
run;

我总是遇到众所周知的问题:

语法错误,应为以下之一:带引号的字符串、数字常量、日期时间常量、缺失值、-。

如何在INstatement 中使用字母数字变量?为什么它不能与它一起工作 - 没有引用字母数字字符串? INstatement需要什么样的数据结构?

【问题讨论】:

  • 那里的datastep where 语句没有这么强大。但是,如果您在 proc sql 中设置查询,where 子句几乎可以满足您的需求。
  • @user2161151 你的意思是像where company_symbol = sp500.smbl?

标签: sas


【解决方案1】:

您可以使用 proc sql 来执行此操作。您可能需要向 company_symbol 添加修剪和压缩,以确保空格不会破坏 company_symbol 和 smbl 之间的任何匹配

这将从 mydata 中选择 company_symbol 与表 sp500 中的 smbl 匹配的所有字段

proc sql noprint;

    create table result as
    select *
    from mydata
    where company_symbol in (select distinct smbl from sp500)
    ;
quit;

【讨论】:

  • 感谢您的回答!它运行完美!你知道吗,为什么INstatement 不能用于字母数字字符串变量,如我的示例代码所示?我想更好地了解 SAS 的工作原理。
  • 我建议阅读更多的文档,因为那里有很多解释得很好。 Here 是一个指向文档的链接,该链接可以告诉你在哪里处理比我在评论中所能告诉你的更多
  • 链接也可以。在谷歌搜索SAS IN alphanumeric string 时,我没有找到任何东西。谢谢!
  • 您可以将该表单与列表一起使用,但您无法通过数据步骤访问另一个表,除非您通过 company_symbol 进行合并并仅在 sp500 中保留该变量或创建包含列表的宏变量 - - 您不能在数据步骤中对另一个表进行子查询——它更容易使用 proc sql 将字段与另一个表中的变量进行比较
  • @scott 实际上根本不正确,有很多(深奥的)方法可以直接查询表。您可以使用open 直接访问,您可以使用_point_ 进行迭代,或者使用哈希表(这是我发现唯一真正有用的),就像我的回答一样。
【解决方案2】:

Scott 的答案绝对是一个不错的答案,但这里有一些替代方案。

首先,最接近您实际编写的方法是将术语括在引号中,将它们选择到宏变量中,然后在数据步骤中使用它们:

proc sql;
 select quote(smbl) into :smbllist separated by ' '
 from sp500;
quit;

data result;
set mydata;
where company_symbol in (&smbllist.);
run;

这不是一个特别好的方法,但它确实有效。

替代方案:

数据步合并(或 SQL 连接)通常比比较好,因为它更好地利用了哈希/索引/等。

data result;
merge mydata(in=a) sp500(in=sp);
by company_symbol;
if a and sp;
run;

这需要对它们进行排序,并且两者中的变量名称相同(如果需要,您可以在合并语句中的一个数据集上使用 RENAME)。 SQL 内连接会做同样的事情,而且不需要显式排序,尽管它可能会在不告诉你的情况下为你排序数据(因此不会节省时间)。取决于哈希解决方案是否有效(如果有效,则不必排序)。


如果排序对您来说是一个额外的步骤(即,如果通常不以这种方式排序),格式通常会更快。

_fmts 的数据; 设置sp500; fmtname='$SMBLF'; 开始=smbl; 标签="1"; *或任何你想要的TRUE; 输出; 如果 n=1 则执行; hlo='o'; *这会检查不匹配; 开始=''; 标签='0'; *或任何你想要的FALSE; 输出; 结尾; 运行;

*必须是smbl的NODUPKEY,所以如果有重复,做一个proc sort nodupkey;

proc 格式 cntlin=for_fmts; 退出;

数据结果; 设置我的数据; where put(company_symbol,$SMBLF.)='1'; 运行;


就面向对象的思维而言,哈希表最接近您实际编写的内容。

data result;
if _n_=1 then do;
if 0 then set sp500;
declare hash sp('dataset:sp500');
sp.defineKey('smbl');
sp.defineData('smbl'); *or whatever you want to return when found, if something;
sp.defineDone();
call missing (smbl); *initialize to missing to avoid warning;
end;
set mydata;
rc = sp.find(key:company_symbol);
if rc eq 0 then output; *or you could do this in one statement, skipping the rc, just being clear here;
run;

【讨论】:

  • 嗨,Joe - 您提到与 in 语句相比,连接可以更好地利用索引。你知道我在哪里可以读到这个吗?
  • IN 与一长串值(即数千或其他值)一起使用会计算出一堆OR 语句,这对于其中的很多语句来说可能是一个非常糟糕的主意。当然会使用主表上的索引,但由于值上没有索引,因此您通常不会获得像 JOIN 那样好的性能。当然,这(与所有 SQL 一样)高度受优化器的影响,谁知道会发生什么。带有 select 语句的IN(即WHERE X IN (select X from othertable))通常会解析为JOIN,但并非总是如此。
  • 啊,好吧,我误会了。我正在考虑一个查询,例如select * from table where id in (select id from table2)。感谢您的澄清。
猜你喜欢
  • 1970-01-01
  • 2012-06-04
  • 2017-04-24
  • 2012-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多