0

我需要向一组人提供一份报告,总结每个人的信息,但只透露每个报告的对象的姓名。我所拥有的是:

爱丽丝 4 15% 8 20%
鲍勃 8 30% 6 15%
卡罗尔 4 15% 8 20%
戴夫 4 15% 8 20%
艾琳 4 15% 8 20%

我想要的是:

Alice 的总结
Alice 4 15% 8 20%
Person2 8 30% 6 15%
Person3 4 15% 8 20%
Person4 4 15% 8 20%
Person5 4 15% 8 20%

Bob 的摘要
Person1 4 15% 8 20%
Bob 8 30% 6 15%
Person3 4 15% 8 20%
Person4 4 15% 8 20%
Person5 4 15% 8 20%

等等。

我已经尝试了几件事,放弃了一个接一个的数字,我最近的尝试如下:

proc sql;
create table Distinct_People
as select distinct(Name)
from have;
quit;

data People;
set Distinct_People end=no_more;
call symputx('Person'||left(_n_), Name);
if no_more then call symputx('NumPeople', _n_);
run;
quit;

%macro Loop;
%do j=1 %to &NumPeople;
%let Person=Person&j;
data want;
set have;
if Name="&&Person&j" then "&&Person&j";
else "Person";
run;
%end;
%mend Loop;
%Loop;

我知道我可能已经破坏了上述内容,但真的需要弄清楚如何在 proc sql 或数据步骤中使用 SAS/SQL 来做到这一点。

谢谢!

4

2 回答 2

0

不确定您在宏中到底尝试做什么,也不知道结果出了什么问题,我可以在您的代码中发现 3 个错误:

1.

data person;

在您的循环中,每次执行循环时,都会覆盖数据集人员。在下一个循环中,您再次访问被覆盖的数据集。所以最后你只有一个数据集,因为你每次都覆盖它,只剩下 personx 作为名字。因此,您必须编写data person&j;以获取每个人的单个数据集。

2.

 set person;

什么是数据集人?您之前没有在示例中定义它。据我了解您要做什么,您必须set have;在此处使用。

3.

您忘记覆盖姓名

 if Name="&&Person&j" then 
 name ="&&Person&j";
 else 
 name ="&Person";

或更简单的版本:

if Name ne "&&Person&j" then 
   name ="&Person";

4.

不是错误,但你应该使用data _null_;而不是data people;,因为你使用这个数据步只是为了生成一些宏变量并且不再使用输出,所以不需要在这里创建一个新的数据集。数据步之后的退出已经过时了......


编辑:

我今天测试了,这段代码肯定对我有用,如果你仍然收到错误,我猜你有错字或你的环境有问题:

data have;

input name $ nr1 nr2 $ nr3 n4 $;
 datalines;
 Alice 4 15% 8 20%
Bob 8 30% 6 15%
Carol 4 15% 8 20%
Dave 4 15% 8 20%
Erin 4 15% 8 20% 
;
run;

proc sql;
create table Distinct_People
as select distinct(Name)
from have;
quit;

data _null_;
set Distinct_People end=no_more;
call symputx('Person'||left(_n_), Name);
if no_more then call symputx('NumPeople', _n_);
run;
quit;

%macro Loop;
%do j=1 %to &NumPeople;
data want&j;
set have;
if Name ne "&&Person&j" then name = cat("Person",_n_);
run;
%end;
%do j=1 %to &NumPeople;
proc print data=want&j; 
title1 " &&Person&j.'s Summary";
run;
%end;
%mend Loop;
%Loop;

结果:

在此处输入图像描述

于 2015-10-06T20:45:19.833 回答
0

我部分地有一个使用联合查询的解决方案,proc sql其中包含子查询来实现匿名人员的姓名和号码。

但是正如您所注意到的,每个人都是手动输入到每个选择查询中的。您不愿意为数据集中的 200 人而不是示例中显示的 5 人执行此操作。一种可能性是运行插入查询以反映联合的选择查询:

proc sql;

create table AnonymousReport As
    SELECT CASE WHEN t1.name = 'Alice' THEN t1.name ELSE CATS('Person',
           (SELECT count(name) + 1 From have t2 
            WHERE t2.name <= t1.name AND t1.name ne t2.name)) END As RptName, 
           t1.Col1Number, t1.Col1Pct, t1.Col2Number, t1.Col2Pct, 'Alice' As ReportToWhom
    FROM have t1

    UNION ALL

    SELECT CASE WHEN t1.name = 'Bob' THEN t1.name ELSE CATS('Person',
           (SELECT count(name) + 1 From have t2 
            WHERE t2.name < t1.name AND t1.name ne t2.name)) END As RptName, 
            t1.Col1Number, t1.Col1Pct, t1.Col2Number, t1.Col2Pct, 'Bob' As ReportToWhom
    FROM have t1

    UNION ALL

    SELECT CASE WHEN t1.name = 'Carol' THEN t1.name ELSE CATS('Person',
           (SELECT count(name) + 1 From have t2 
            WHERE t2.name < t1.name AND t1.name ne t2.name)) END As RptName, 
            t1.Col1Number, t1.Col1Pct, t1.Col2Number, t1.Col2Pct, 'Carol' As ReportToWhom
    FROM have t1

    UNION ALL

    SELECT CASE WHEN t1.name = 'Dave' THEN t1.name ELSE CATS('Person',
           (SELECT count(name) + 1 From have t2 
            WHERE t2.name < t1.name AND t1.name ne t2.name)) END As RptName, 
    t1.Col1Number, t1.Col1Pct, t1.Col2Number, t1.Col2Pct, 'Dave' As ReportToWhom
    FROM have t1

    UNION ALL

    SELECT CASE WHEN t1.name = 'Erin' THEN t1.name ELSE CATS('Person', 
           (SELECT count(name) + 1 From have t2 
            WHERE t2.name < t1.name AND t1.name ne t2.name)) END As RptName, 
    t1.Col1Number, t1.Col1Pct, t1.Col2Number, t1.Col2Pct, 'Erin' As ReportToWhom
    FROM have t1;

quit;

输出数据集。从这里按最后一列 ReportToWhom 导出每个人的个人报告

RptName     Col1Number  Col1Pct Col2Number  Col2Pct    ReportToWhom
Alice       4           15%              8      20%    Alice
Person2     8           30%              6      15%    Alice
Person3     4           15%              8      20%    Alice
Person4     4           15%              8      20%    Alice
Person5     4           15%              8      20%    Alice
Person1     4           15%              8      20%    Bob
Bob         8           30%              6      15%    Bob
Person3     4           15%              8      20%    Bob
Person4     4           15%              8      20%    Bob
Person5     4           15%              8      20%    Bob
...

一种可能的解决方案是在数据集的所有行中使用连接的插入 SQL 查询:

data concat;
    set have;
    length reptAll $3200;
    by name;
    retain reptAll;

    if first.name then reptAll = "";
    unionSQL = "INSERT INTO AnonymousReport (RptName, Col1Number, Col1Pct, Col2Number, Col2Pct, ReportToWhom)
        SELECT CASE WHEN t1.name = '" || name || "' THEN t1.name 
        ELSE CATS('Person', (SELECT count(name) + 1 From have t2 
        WHERE t2.name <= t1.name AND t1.name ne t2.name)) END As RptName, 
        t1.Col1Number, t1.Col1Pct, t1.Col2Number, t1.Col2Pct, '" || name || "' As ReportToWhom
        FROM have t1";

    reptAll =  catx('; ', reptAll, unionSQL) ;

    call symput('query', reptAll);
    if last.name then output;
run;

然后将字符串传递给proc sql宏:

%macro runsql;
    proc sql;   
        &query; 
    quit;
%mend runsql;

%runsql;

在 R 中,我可以使用它的paste/ forloop/apply函数在几秒钟内完成此操作,但 SAS 语法是另一个世界!

于 2015-10-06T23:43:23.843 回答