需要为一个变量隐藏一些字段,SAS/SQL
Need to hide some fields for one variable, SAS/SQL
我需要向一组人提交一份报告,总结每个人的信息,但只透露每份报告的收件人姓名。
我有的是:
爱丽丝 4 15% 8 20%
鲍勃 8 30% 6 15%
卡罗尔 4 15% 8 20%
戴夫 4 15% 8 20%
艾琳 4 15% 8 20%
我想要的是:
爱丽丝的总结
爱丽丝 4 15% 8 20%
人 2 8 30% 6 15%
人 3 4 15% 8 20%
人 4 4 15% 8 20%
人 5 4 15% 8 20%
鲍勃的总结
人 1 4 15% 8 20%
鲍勃 8 30% 6 15%
人 3 4 15% 8 20%
人 4 4 15% 8 20%
人 5 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 来做到这一点。
谢谢!
不确定您在宏中到底想做什么,也不知道您的结果出了什么问题,我可以在您的代码中发现 3 个错误:
1.
data person;
在你的循环中,每次执行循环时,你都会覆盖数据集 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;
,因为您使用此数据步只是为了生成一些宏变量并且不再使用输出,因此无需创建新数据集 here.And 数据步过时后退出...
编辑:
我今天测试过,这段代码对我来说绝对有效,如果你仍然得到错误,我猜你有错字或者你的环境有问题:
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;
结果:
我有部分解决方案使用 proc sql
中的联合查询,其中包含实现匿名人员姓名和号码的子查询。
但是正如您所注意到的,每个人都是手动输入到每个 select 查询中的。对于数据集中的 200 人而不是示例中显示的 5 人,您可能不愿意这样做。一种可能性是 运行 插入反映联合 select 查询的查询:
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 00;
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
/for
循环/apply
函数在几秒钟内完成此操作,但 SAS 语法是另一个世界!
我需要向一组人提交一份报告,总结每个人的信息,但只透露每份报告的收件人姓名。 我有的是:
爱丽丝 4 15% 8 20%
鲍勃 8 30% 6 15%
卡罗尔 4 15% 8 20%
戴夫 4 15% 8 20%
艾琳 4 15% 8 20%
我想要的是:
爱丽丝的总结
爱丽丝 4 15% 8 20%
人 2 8 30% 6 15%
人 3 4 15% 8 20%
人 4 4 15% 8 20%
人 5 4 15% 8 20%
鲍勃的总结
人 1 4 15% 8 20%
鲍勃 8 30% 6 15%
人 3 4 15% 8 20%
人 4 4 15% 8 20%
人 5 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 来做到这一点。
谢谢!
不确定您在宏中到底想做什么,也不知道您的结果出了什么问题,我可以在您的代码中发现 3 个错误:
1.
data person;
在你的循环中,每次执行循环时,你都会覆盖数据集 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;
,因为您使用此数据步只是为了生成一些宏变量并且不再使用输出,因此无需创建新数据集 here.And 数据步过时后退出...
编辑:
我今天测试过,这段代码对我来说绝对有效,如果你仍然得到错误,我猜你有错字或者你的环境有问题:
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;
结果:
我有部分解决方案使用 proc sql
中的联合查询,其中包含实现匿名人员姓名和号码的子查询。
但是正如您所注意到的,每个人都是手动输入到每个 select 查询中的。对于数据集中的 200 人而不是示例中显示的 5 人,您可能不愿意这样做。一种可能性是 运行 插入反映联合 select 查询的查询:
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 00;
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
/for
循环/apply
函数在几秒钟内完成此操作,但 SAS 语法是另一个世界!