深入探索 SAS 中 REPORT 与 DOCUMENT 过程的高级应用
在 SAS 数据分析与报告生成的领域中,
PROC REPORT
是一个强大的工具,它能帮助我们创建各种复杂的报告。同时,
ODS DOCUMENT
和
PROC DOCUMENT
则为报告的存储、管理和结构调整提供了更多的可能性。本文将详细介绍
RBREAK
语句的
CONTENTS=
选项,以及
ODS DOCUMENT
和
PROC DOCUMENT
的使用方法和应用场景。
1. RBREAK 语句的 CONTENTS= 选项
RBREAK
语句的
CONTENTS=
选项仅在与
BEFORE
位置、
PAGE
选项和
SUMMARIZE
选项同时使用时才有效。使用该选项会在第三节点级别添加一个新条目。不过,由于该选项的使用条件较为严格,在大多数业务场景中可能不太实用。
以下是一个示例代码:
proc report data=orders;
column customer_country product_line quantity total_retail_price;
define customer_country / group;
define product_line / group;
rbreak before / contents="Summary" page summarize;
run;
这个示例展示了如何使用
RBREAK
语句的
PAGE
和
CONTENTS=
选项,运行后会添加一个标记为 “Summary” 的节点。
2. ODS DOCUMENT 和 PROC DOCUMENT 概述
通过
PROC REPORT
控制节点数量和标签可能会让人感到沮丧和困难。在某些情况下,
PROC REPORT
对节点的控制能力有限。这时,我们可以先让
PROC REPORT
创建最少数量的必要节点,然后使用
ODS DOCUMENT
目的地和
PROC DOCUMENT
来重构目录结构并更改条目标签。
ODS DOCUMENT
目的地用于将输出对象存储在文档项存储中。我们可以从存储的信息中为多个 ODS 目的地生成输出,而无需重新运行原始的
PROC
或
DATA
步骤。
PROC DOCUMENT
则更强大,它不仅可以将文档项存储中的输出对象发送到任何打开的 ODS 目的地(使用
REPLAY
语句),还可以更改输出对象的顺序和重构目录结构。
3. ODS DOCUMENT 约定
ODS DOCUMENT
目的地的语法与其他目的地相同,需要先打开目的地,在数据和过程步骤之后关闭目的地。
ods document name=temp;
proc report …
run;
ods document close;
ODS DOCUMENT
语句的默认访问模式是
Update
,它会将新的过程信息追加到已存在的文档项存储中。为了避免对存储内容的混淆,我们可以指定
Write
访问模式,该模式会删除存储中的所有现有内容,每次都从头开始。
需要注意的是,如果使用了自定义格式,
ODS DOCUMENT
会存储临时格式,但不会保存永久格式。在重放文档时,需要确保 SAS 知道用户定义格式的位置,可以使用
PROC FORMAT
或带有
FMTSEARCH
选项的
OPTIONS
语句来实现。
4. PROC DOCUMENT 语句和选项
PROC DOCUMENT
有多个语句和选项,以下是一些常用的:
-
LIST 语句
:用于列出文档中每个条目的内容。需要使用
LEVELS=
和
DETAILS
选项,
LEVELS=ALL
可以让输出包含存储中的每个条目和路径,
DETAILS
选项则可以查看每个路径的
TYPE
和
LABEL
变量值。
-
MAKE 语句
:用于创建新目录,将对存储项的所有更改放在新目录中,避免对
PROC REPORT
创建的项造成意外更改。
-
SETLABEL 语句
:用于分配节点标签。
-
COPY 语句
:用于将
PROC REPORT
创建的项复制到新目录中,同样是为了避免意外更改。
PROC DOCUMENT
支持
RUN-Group
处理,因此
RUN
语句非常重要,它能确保所有语句都被执行。过程必须以
QUIT
语句结束,以正确终止。
5. 默认项分析
了解
PROC REPORT
放入文档项存储中的条目结构很重要。下面是一个简单的
PROC REPORT
步骤创建项存储的示例代码:
ods document name=temp(write);
proc report data=orders;
column product_line quantity total_retail_price;
define product_line / group;
run;
ods document close;
proc document name=temp;
list / levels=all details;
run;
quit;
默认情况下,
PROC REPORT
创建三个节点级别,文档存储通常有三个项:
| 序号 | 项类型 | 对应内容 | 标签默认值 |
| ---- | ---- | ---- | ---- |
| 1 | Dir | 由
ODS PROCLABEL
语句创建的过程标签,是包含输出对象的目录结构的顶部 | “The Report Procedure” |
| 2 | Dir | 对应
PROC REPORT
语句中
CONTENTS=
选项控制的报告标签,创建子目录 | “Detailed and/or summarized report” |
| 3 | 实际输出对象 |
PROC REPORT
创建的表格 | 由于
ODS DOCUMENT
创建观察和
PROC REPORT
提供正确标签的时间顺序问题,标签值缺失 |
当在
BREAK
语句中添加
PAGE
选项时,虽然目录结构会发生变化,但文档存储中可能只包含一个表条目,这是由于时间问题导致的。例如:
ods document name=temp(write);
proc report data=orders;
column customer_country product_line quantity total_retail_price;
define customer_country / group;
define product_line / group;
break after customer_country / page;
run;
ods document close;
proc document name=temp;
list / levels=all details;
run;
quit;
无论如何,文档存储至少会有两个项,一个是目录,另一个是表格输出对象。即使通过
PROC REPORT
移除目录中的第二和第三级节点,文档存储中仍然会有两个条目。
6. BY 变量项列表
当在
PROC REPORT
步骤中使用
BY
语句时,会为
BY
变量的每个唯一值在主目录下添加一个子目录,每个子目录都有一个唯一的序列号。多个
BY
变量不会改变子目录结构,但会增加子目录的数量,因为每个
BY
变量值的组合都会有一个对应的子目录。
以下是一个示例代码:
proc sort data=orders;
by customer_age_group;
run;
ods document name=temp(write);
proc report data=orders;
by customer_age_group;
column product_line quantity total_retail_price;
define product_line / group;
run;
ods document close;
proc document name=temp;
list / levels=all details;
run;
quit;
假设
CUSTOMER_AGE_GROUP
变量有五个唯一值,那么会添加五个子目录,分别为
ByGroup1#1
、
ByGroup2#1
等。每个
BY
值目录下还有一个子目录,其中包含表格输出对象。
7. 创建具有多个子节点的父节点
在实际应用中,我们可能希望在目录中创建一个具有多个子节点的父节点。
BREAK
语句的
PAGE
和
CONTENTS=
选项无法在项存储中创建多个项,因此无法直接用于创建子节点。而
PROC DOCUMENT
可以帮助我们实现这一需求。
创建一个具有多个子节点的父节点需要两个步骤:
1.
创建包含
PROC REPORT
输出的文档项存储
:需要使用
BY
语句来创建所需数量的项。
proc sort data=orders;
by customer_country;
run;
ods document name=temp(write);
proc report data=orders contents="";
by customer_country;
format customer_country $cntry.;
column customer_country product_line quantity total_retail_price;
define customer_country / group;
define product_line / group;
break before customer_country / page contents="";
run;
ods document close;
- 在项存储中创建新目录并将输出对象移动到该目录 :为新目录和子节点设置有意义的标签。
proc document name=temp;
make \parentchild;
setlabel \parentchild "Country Sales";
setlabel \Report#1\ByGroup1#1\Report#1 "Australia";
copy \Report#1\ByGroup1#1\Report#1 to \parentchild#1;
setlabel \Report#1\ByGroup2#1\Report#1 "Canada";
copy \Report#1\ByGroup2#1\Report#1 to \parentchild#1;
setlabel \Report#1\ByGroup3#1\Report#1 "Germany";
copy \Report#1\ByGroup3#1\Report#1 to \parentchild#1;
setlabel \Report#1\ByGroup4#1\Report#1 "Israel";
copy \Report#1\ByGroup4#1\Report#1 to \parentchild#1;
setlabel \Report#1\ByGroup5#1\Report#1 "Turkey";
copy \Report#1\ByGroup5#1\Report#1 to \parentchild#1;
setlabel \Report#1\ByGroup6#1\Report#1 "United States";
copy \Report#1\ByGroup6#1\Report#1 to \parentchild#1;
setlabel \Report#1\ByGroup7#1\Report#1 "South Africa";
copy \Report#1\ByGroup7#1\Report#1 to \parentchild#1;
run;
ods pdf file="CountrySales.pdf";
replay \parentchild;
run;
ods pdf close;
quit;
上述代码中,手动编写了所有的
SETLABEL
和
COPY
语句,这可能会很繁琐且容易出错。我们可以使用宏程序来简化这个过程。使用宏程序更新项存储需要以下步骤:
1. 创建包含
PROC REPORT
输出的文档项存储。
2. 创建一个包含存储项列表的数据集。
ods output properties=itemlist;
proc document name=temp;
list / levels=all details;
run;
quit;
- 为需要操作的每个路径和标签创建宏变量。
data _null_;
set itemlist end=last;
if _n_ ne 1 then do;
if type not in ("Table") then do;
countl+1;
call symputx('label'||trim(left(countl)),scan(label,2,"="));
end;
end;
if type in ("Table") then do;
count+1;
call symputx('path'||trim(left(count)),path);
end;
if last then call symputx('total',count);
run;
- 创建具有所需节点级别的新项结构,并将新结构重放到所需的 ODS 目的地。
%macro newtoc;
proc document name=temp;
make \parentchild;
setlabel \parentchild "Country Sales";
%do i=1 %to &total;
setlabel &&path&i "&&label&i";
copy &&path&i to \parentchild#1;
%end;
run;
ods pdf file="CountrySales.pdf";
replay \parentchild;
run;
ods pdf close;
quit;
%mend newtoc;
%newtoc
通过以上步骤,我们可以更灵活地控制报告的目录结构,创建出满足需求的报告。希望本文对你在 SAS 中使用
PROC REPORT
、
ODS DOCUMENT
和
PROC DOCUMENT
有所帮助。
下面是创建具有多个子节点的父节点的流程图:
graph TD;
A[创建包含PROC REPORT输出的文档项存储] --> B[创建包含存储项列表的数据集];
B --> C[为路径和标签创建宏变量];
C --> D[创建新项结构并重放];
通过上述内容,我们详细了解了
RBREAK
语句的
CONTENTS=
选项,以及
ODS DOCUMENT
和
PROC DOCUMENT
的使用方法和应用场景。这些技术可以帮助我们更好地管理和定制 SAS 报告的结构和内容。在实际应用中,我们可以根据具体需求选择合适的方法,提高报告生成的效率和质量。
深入探索 SAS 中 REPORT 与 DOCUMENT 过程的高级应用
8. 宏程序实现的详细解释
在使用宏程序更新项存储以创建具有多个子节点的父节点时,每个步骤都有其特定的作用。
8.1 创建包含存储项列表的数据集
ods output properties=itemlist;
proc document name=temp;
list / levels=all details;
run;
quit;
-
ods output properties=itemlist;:这行代码将PROC DOCUMENT的LIST语句输出的信息存储到名为itemlist的数据集中。LIST语句结合levels=all details选项,会列出文档存储中所有条目的详细信息,包括路径、类型和标签等。 -
proc document name=temp;:指定要操作的文档存储为temp。 -
list / levels=all details;:列出temp文档存储中所有条目的详细信息。 -
run;和quit;:RUN语句确保PROC DOCUMENT中的语句被执行,QUIT语句正确终止该过程。
8.2 为路径和标签创建宏变量
data _null_;
set itemlist end=last;
if _n_ ne 1 then do;
if type not in ("Table") then do;
countl+1;
call symputx('label'||trim(left(countl)),scan(label,2,"="));
end;
end;
if type in ("Table") then do;
count+1;
call symputx('path'||trim(left(count)),path);
end;
if last then call symputx('total',count);
run;
-
data _null_;:这是一个空数据集,用于执行数据步操作而不创建实际的数据集。 -
set itemlist end=last;:从itemlist数据集中读取数据,end=last用于标记最后一条记录。 -
if _n_ ne 1 then do;:跳过itemlist数据集中的第一条记录,因为第一条记录通常是主目录信息。 -
if type not in ("Table") then do;:处理非表格类型的条目,为每个BY变量项创建一个宏变量,其值为BY变量的值。 -
countl+1;:计数器,用于为每个BY变量项生成唯一的编号。 -
call symputx('label'||trim(left(countl)),scan(label,2,"="));:创建宏变量,名称为label1、label2等,值为BY变量的值。 -
if type in ("Table") then do;:处理表格类型的条目,为每个表格项创建一个宏变量,其值为输出对象的路径。 -
count+1;:计数器,用于为每个表格项生成唯一的编号。 -
call symputx('path'||trim(left(count)),path);:创建宏变量,名称为path1、path2等,值为输出对象的路径。 -
if last then call symputx('total',count);:在处理完所有记录后,创建一个宏变量total,其值为输出对象的总数。
8.3 创建新项结构并重放
%macro newtoc;
proc document name=temp;
make \parentchild;
setlabel \parentchild "Country Sales";
%do i=1 %to &total;
setlabel &&path&i "&&label&i";
copy &&path&i to \parentchild#1;
%end;
run;
ods pdf file="CountrySales.pdf";
replay \parentchild;
run;
ods pdf close;
quit;
%mend newtoc;
%newtoc
-
%macro newtoc;和%mend newtoc;:定义一个名为newtoc的宏程序。 -
proc document name=temp;:指定要操作的文档存储为temp。 -
make \parentchild;:在文档存储中创建一个新的目录\parentchild,作为父节点。 -
setlabel \parentchild "Country Sales";:为父节点设置标签为 “Country Sales”。 -
%do i=1 %to &total;:循环处理每个BY变量项。 -
setlabel &&path&i "&&label&i";:为每个子节点设置标签,标签值为之前创建的label宏变量的值。 -
copy &&path&i to \parentchild#1;:将每个子节点的输出对象复制到新的父节点下。 -
ods pdf file="CountrySales.pdf";:打开 ODS PDF 目的地,指定输出文件名为 “CountrySales.pdf”。 -
replay \parentchild;:重放新创建的目录\parentchild,将其内容输出到 ODS PDF 目的地。 -
run;和quit;:确保PROC DOCUMENT中的语句被执行,并正确终止该过程。
9. 总结与实际应用建议
通过上述对
RBREAK
语句的
CONTENTS=
选项,以及
ODS DOCUMENT
和
PROC DOCUMENT
的详细介绍,我们可以总结出以下要点:
-
功能总结
-
RBREAK
语句的
CONTENTS=
选项在特定条件下可添加新节点,但使用场景有限。
-
ODS DOCUMENT
用于存储输出对象,
PROC DOCUMENT
用于管理和重构存储的内容,包括更改目录结构和节点标签。
- 使用
BY
语句可在文档存储中创建多个子目录,方便对数据进行分组管理。
- 通过宏程序可以简化创建具有多个子节点的父节点的过程,提高效率和减少错误。
-
实际应用建议
- 在使用
ODS DOCUMENT
时,根据实际需求选择合适的访问模式,避免数据混淆。
- 当需要对报告的目录结构进行复杂调整时,优先考虑使用
PROC DOCUMENT
和宏程序。
- 在处理自定义格式时,确保在重放文档时 SAS 能找到相应的格式。
以下是一个总结表格:
| 功能 | 描述 | 注意事项 |
| ---- | ---- | ---- |
| RBREAK 语句的 CONTENTS= 选项 | 在特定条件下添加新节点 | 与 BEFORE、PAGE 和 SUMMARIZE 选项同时使用 |
| ODS DOCUMENT | 存储输出对象 | 注意访问模式和自定义格式的处理 |
| PROC DOCUMENT | 管理和重构存储内容 | 支持 RUN - Group 处理,使用 RUN 和 QUIT 语句 |
| BY 语句 | 创建多个子目录 | 多个 BY 变量会增加子目录数量 |
| 宏程序 | 简化创建具有多个子节点的父节点的过程 | 需按步骤创建数据集和宏变量 |
10. 未来拓展方向
虽然本文介绍了
PROC REPORT
、
ODS DOCUMENT
和
PROC DOCUMENT
的常见应用场景,但在实际应用中还有很多可以拓展的方向。
-
自动化报告生成
:结合宏程序和数据驱动的方法,可以实现根据不同的数据集自动生成具有特定目录结构的报告。
-
与其他 SAS 过程结合
:可以将
PROC REPORT
与
PROC SQL
、
PROC FREQ
等其他 SAS 过程结合使用,获取更丰富的数据并生成更复杂的报告。
-
可视化报告
:将生成的报告与 SAS Visual Analytics 等工具结合,实现更直观的可视化展示。
通过不断探索和实践,我们可以充分发挥这些工具的潜力,为数据分析和报告生成提供更强大的支持。
希望以上内容能帮助你更好地理解和应用 SAS 中的这些高级功能,在实际工作中创造出更优质的报告。
超级会员免费看

被折叠的 条评论
为什么被折叠?



