简介:本资源是SAS Base Programmer认证考试官方出品的全真模考题PDF,专为备考SAS基础编程认证的开发者、数据分析师及统计从业人员设计,聚焦核心语法、数据读写、变量处理与函数应用等实操能力训练。文件共1个PDF文档(283KB),内容完整覆盖INPUT/PUT语句、日期格式解析(如date9.与mmddyy8.)、字符与数值变量定义、libname路径配置、substr字符串操作、!!连接符使用等高频考点,并含50道标准单选题及详细题干场景(如原始数据格式识别、输出位置控制@符号、CODE变量生成逻辑等),每题均模拟真实考试难度与命题风格。目前已有199人学习下载,适合考生进行限时自测、错题归因与知识点靶向强化,是贴近SAS Institute官方要求的权威备考材料。
1. 这不是题库,是 SAS Base 认证考试的「行为镜像」:20 道真题暴露的不是知识点,而是你写 DATA 步骤时下意识的语法惯性
很多人把这份 PDF 当成普通练习题——抄答案、背选项、刷完就扔。但真正用过 SAS Base 认证模考题的人都知道:它不考“你会不会”,而考“你是不是这样想”。比如第 7 题里Jose,47,210和Sue,,108这两行数据,表面在考infile选项,实则在测你对缺失值处理机制的肌肉记忆——是习惯性加missover,还是条件反射写dsd?再如第 15 题total = total + quantity,没声明retain却期望累加,暴露的是对 PDV(Program Data Vector)生命周期的理解断层。这份模考题由 SAS Institute 官方于 2003 年发布(版权页明确标注),虽年代较早,但所有题目均基于 SAS Base Programming 的核心语义层设计:INPUT 解析逻辑、变量隐式类型推导、DATA step 执行流、自动变量_ERROR_和_N_的触发边界、以及put与input的格式对称性。它适合三类人:刚学完 SAS 基础语法但不敢写完整 DATA 步骤的新手;已能跑通代码却总在认证题里栽在“看似 trivial”的细节(如: date9.中冒号的作用)的中级使用者;以及需要快速定位团队成员 SAS 思维盲区的内训讲师。它不教新功能,只照见你和 SAS 编译器之间尚未对齐的那部分认知。
2. INPUT 语句的解析逻辑:从原始字符流到结构化变量的四步转化链
SAS 的INPUT语句不是简单读取,而是一套带状态机的解析引擎。它必须同时解决四个问题:字段边界识别、类型推断、格式转换、缺失值标记。模考题中第 1、7、10、13 题集中暴露出考生在这条转化链上的常见断裂点。
2.1 字段边界识别:dsd、dlm=、missover的语义差异不可互换
原始数据Jose,47,210和Sue,,108(第 7 题)表面是 CSV,但第二行中间存在空字段。此时若仅用dlm=',':
infile 'rawdata.txt' dlm=','; input name $ age weight;SAS 会将Sue,,108解析为name='Sue'、age=' '(空字符串)、weight=108,但age是数值型,空字符串强制转数值 →.(缺失),且不报错。这看似“正确”,实则掩盖了数据结构风险。而missover的作用是:当某字段无值时,直接跳过该字段,不尝试转换,保持目标变量为缺失值。dsd(delimiter-sensitive data)则更进一步:它将连续分隔符(,,)视为空字段,并自动启用missover行为,同时忽略引号包围的字段内分隔符。验证方式如下:
/* 测试数据:rawdata.txt 内容 */ Jose,47,210 Sue,,108 /* 方案A:仅 dlm=',' */ data test_dlm; infile 'rawdata.txt' dlm=','; input name $ age weight; run; /* 查看结果:age 在第二行是 .,但 log 中有 NOTE: Invalid numeric data */ /* 方案B:dsd */ data test_dsd; infile 'rawdata.txt' dsd; input name $ age weight; run; /* 结果相同,但 log 更干净,且支持 "John,Doe,1980" 这类含逗号的字段 */提示:
dsd是处理真实 CSV 的首选,它隐含missover且兼容引号。dlm=','仅适用于严格单一分隔符且无空字段的场景。missover单独使用适合固定列宽或自定义分隔符但需显式控制缺失逻辑的情况。
2.2 类型推断与格式转换:date9.vsmmddyy8.vs: date9.的执行路径分化
第 1 题考察日期输入,选项 A/B/C/D 的区别本质是 SAS 如何绑定格式与变量。关键在于理解:修饰符的作用:
input relation $ first_name $ birthdate date9.;
→birthdate必须是数值型变量(因date9.是数值格式),且输入值必须严格匹配01JAN1990格式。若输入01/31/89,SAS 尝试按date9.解析失败 →_ERROR_=1,birthdate设为.。input relation $ first_name $ birthdate mmddyy8.;
→mmddyy8.要求输入为01311989或01/31/89(8位内含分隔符)。01/31/89可被识别,但12-25-87(第 1 题原始数据)会失败。input relation $ first_name $ birthdate : date9.;
→:是“修饰符”,表示跳过空白后读取,且允许输入值与格式不完全对齐。SAS 先跳过前导空格,再尝试用date9.解析01/31/89。由于date9.内部支持/分隔符,此式成功。input relation $ first_name $ birthdate : mmddyy8.;
→ 同理,mmddyy8.支持/和-,12-25-87可被识别。
验证代码:
/* 创建测试数据 */ data _null_; file 'test_dates.txt'; put 'son Frank 01/31/89'; put 'daughter June 12-25-87'; put 'brother Samuel 01/17/51'; run; /* 测试不同 INPUT 语句 */ data test_formats; infile 'test_dates.txt'; /* 尝试 C 选项:: date9. */ input relation $ first_name $ birthdate : date9.; format birthdate date9.; run; proc print data=test_formats; run; /* 输出:birthdate 均为有效 SAS 日期值 */注意:
:修饰符不改变变量类型,只放宽格式匹配。birthdate仍为数值型(存储为自 1960-1-1 起的天数),date9.仅控制读入和显示。未加:时,格式必须与输入字符串字面量完全一致(长度、分隔符)。
2.3 缺失值传播:_ERROR_变量的触发条件与调试价值
第 13 题给出Germany 12/31/2000和France 01/32/2001,问_N_=2时_ERROR_的值。_ERROR_是 SAS 自动创建的标志变量,值为 1 表示当前观测发生数据错误(如无效日期、非数字转数值)。01/32/2001是非法日期(1月无32日),SAS 在input时检测到 →_ERROR_=1,date设为.。而_N_是观测序号,第二行即_N_=2。因此答案为 B(1)。
实际调试中,应主动捕获_ERROR_:
data check_errors; infile 'bad_dates.txt'; input country $8. date mmddyy10.; if _ERROR_ then do; put 'ERROR at obs ' _N_ ': ' _infile_; /* 记录错误行到日志或单独数据集 */ end; run;提示:
_ERROR_在 DATA step 每次迭代末重置。它不标记语法错误(如run;缺失),只标记运行时数据解析错误。结合_infile_(当前原始行)可精确定位脏数据。
3. DATA step 执行模型:PDV、自动变量与隐式初始化的底层契约
SAS 的 DATA step 不是线性脚本,而是基于 PDV(Program Data Vector)的循环处理器。模考题第 12、15、17 题直指 PDV 的初始化规则和累积逻辑。
3.1 PDV 初始化:total = total + quantity为何返回缺失值?
第 15 题中total = total + quantity;在首次迭代时,total未声明也未赋初值。SAS 规则:数值变量在 PDV 中初始值为缺失(.),字符变量为长度空格填充的字符串。因此:
- 第一行:
quantity=2,total初始为.→total = . + 2→.(缺失值参与运算结果仍为缺失) - 后续行同理,
total始终为.
正确写法必须显式初始化:
data money; infile 'years.txt'; input year quantity; if _N_ = 1 then total = 0; /* 首次迭代设初值 */ total = total + quantity; run; /* 或更标准:retain total 0; */ data money_retain; infile 'years.txt'; retain total 0; /* retain 使 total 在迭代间保持值 */ input year quantity; total = total + quantity; run;retain语句是显式声明变量跨迭代持久化的唯一方式。未retain的变量每次迭代重置为初始值(.或空格)。
3.2do until循环的终止条件陷阱:products gt 6的执行时序
第 12 题do until (products gt 6); products + 1; end;。do until的特点是:先执行循环体,再判断条件。执行过程:
- 初始
products=7 - 进入循环体:
products + 1→products=8 - 判断
products gt 6→8 > 6为真 →退出循环 - 最终
products=8
若改为do while (products le 6),则先判后执行,products=7时条件假,循环体一次不执行,products保持7。
验证代码:
data test_loop; products = 7; do until (products gt 6); products + 1; put 'Inside loop: products=' products; end; put 'After loop: products=' products; run; /* Log 输出: Inside loop: products=8 After loop: products=8 */注意:
do until至少执行一次;do while可能零次。二者条件逻辑相反(until 是“直到条件为真才停”,while 是“当条件为真时继续”)。
3.3 函数缺失值处理:mean(6,4,.,2)的计算逻辑与.的语义
第 17 题average = mean(6,4,.,2);。mean()函数的规则:忽略缺失值(.),对剩余非缺失值求平均。参数6,4,.,2中,6+4+2=12,共 3 个非缺失值 →12/3=4。答案为 C(4)。
对比其他函数:
sum(6,4,.,2)→6+4+2=12(sum也忽略.)max(6,4,.,2)→6(忽略.后取最大)std(6,4,.,2)→sqrt(((6-4)^2+(4-4)^2+(2-4)^2)/(3-1)) = sqrt(8/2)=2(样本标准差,n-1)
验证:
data test_mean; avg1 = mean(6,4,.,2); avg2 = mean(6,4,2); /* 等价写法 */ put 'avg1=' avg1 'avg2=' avg2; run; /* Log: avg1=4 avg2=4 */提示:SAS 中
.是数值缺失值,参与四则运算结果必为.(如1 + . = .),但统计函数(mean,sum,std等)默认剔除.。需用mean(of var1-var10)处理数组,或coalesce()提供默认值。
4. 输出控制与报告生成:put语句定位、PROC REPORT 选项及 CLASS/VAR 的层级关系
SAS 输出不仅是proc print,更是对数据呈现逻辑的精确编排。模考题第 3、4、5、9、14、18 题覆盖了put定位、变量类型声明、分类统计和报表格式四大维度。
4.1put语句的绝对定位:@5 age 2.中@的坐标系统
第 3 题put name $15. @5 age 2.;。@n表示将输出指针移动到第 n 列(列号从 1 开始)。name $15.占 15 列(如Janice输出为"Janice "),之后指针在第 16 列。@5强制跳回第 5 列,再输出age的 2 位数值(如10→"10")。结果是name覆盖第 1-15 列,age覆盖第 5-6 列,二者重叠。
实际效果(以Janice 10为例):
name $15.→"Janice "(15 字符)- 指针移至第 5 列 → 覆盖位置 5-6
age 2.→"10"写入第 5-6 列 →"Jan10 "(第 5-6 字符变为10)
验证:
data _null_; name = 'Janice'; age = 10; file 'output.txt'; put name $15. @5 age 2.; run; /* output.txt 内容:Jan10 */注意:
@是绝对定位,+n是相对右移,+0可用于重复写同一位置。@常用于生成固定宽度报表或覆盖式输出。
4.2 变量长度声明:length city $20;与trim(city)的内存分配真相
第 14 题length city $20; city = 'Paris '; city2 = trim(city);。length city $20;声明city为 20 字节字符变量,存储'Paris '(6 字符,含尾随空格)。trim()返回去除尾随空格的字符串,但不改变目标变量的长度声明。city2未声明长度,SAS 按trim(city)的实际长度(5)隐式定义 →city2长度为 5。
验证:
data test_length; length city $20; city = 'Paris '; city2 = trim(city); put 'city length=' $20. / 'city2 length=' $5.; /* 实际查看长度需用 $CHAR. 格式或 attrc() 函数 */ len_city = length(city); /* =20,返回声明长度 */ len_city2 = length(city2); /* =5,返回实际内容长度 */ run;提示:
length语句必须在data步骤开头(input前)声明,否则无效。trim()返回新字符串,其长度由内容决定,与源变量长度无关。
4.3 PROC MEANS 与 PROC FREQ 的分类逻辑:classvsvar的职责划分
第 5 题要求生成按Style分组的bedrooms和baths均值表。class style;指定分组变量(行维度),var bedrooms baths;指定分析变量(列维度)。二者缺一不可:
- 仅
class style→ 报告只有Style分组,无具体统计量 - 仅
var bedrooms baths→ 对全数据集计算bedrooms和baths的均值,不分组 class style; var bedrooms baths;→ 交叉分组,生成Style下各变量的统计量
第 6 题涉及if-else逻辑陷阱:if jobcode in ('Actor I', 'Actor II') then joblevel = 'Beginner'; if jobcode = 'Actor III' then joblevel = 'Advanced'; else joblevel = 'Unknown';。此处第二个if是独立语句,else绑定到第二个if,而非第一个。当jobcode='Actor I'时:第一行设joblevel='Beginner',第二行条件假,执行else→joblevel='Unknown',覆盖前值。正确写法需用else if:
if jobcode in ('Actor I', 'Actor II') then joblevel = 'Beginner'; else if jobcode = 'Actor III' then joblevel = 'Advanced'; else joblevel = 'Unknown';4.4 PROC REPORT 的 SPLIT= 选项:多行标题的换行控制
第 18 题问控制列标题多行显示的选项。SPLIT=指定一个字符作为标题换行符。例如:
proc report data=sashelp.class nowd; column name sex age height weight; define name / group label="Student|Name"; /* | 是换行符 */ define sex / group label="Gender"; split '|'; /* 声明 | 为换行符 */ run;SPLIT='*'则可用*替代|。LABEL=设置标签文本,BREAK=控制分组中断,SPACE=设置列间空格数,均不控制换行。
注意:
SPLIT=必须在proc report语句后、column前声明,且换行符需在label=中显式出现。
5. 认证级排错技巧:从 LOG 信息反推 DATA step 执行路径的 3 个关键锚点
通过模考题暴露的典型错误,可提炼出快速定位 SAS Base 问题的三个 LOG 锚点。它们比“看报错行”更高效,因为多数认证题错误不报错,只产生静默异常。
5.1NOTE: Invalid numeric data—— 数据类型转换失败的黄金线索
当input或计算中出现非数字字符赋给数值变量时,SAS 记录此 NOTE,并设目标变量为.。例如第 10 题$23,456 750,若用input salary $ 1-7读取salary为字符型,后续newsalary = salary + raise会触发此 NOTE,因为salary是$23,456(字符),不能直接加数值raise。正确解法是input(salary,comma7.)显式转换。
排查步骤:
- 在 LOG 中搜索
Invalid numeric data - 定位对应行号和变量名(如
variable=salary line=10 column=1) - 检查该变量的 INPUT 格式是否匹配原始数据(
comma7.对应$23,456,best.会失败)
5.2WARNING: Multiple lengths were specified for the variable XXX—— 长度冲突的源头定位
当同一变量在多个地方声明长度(如length语句、input语句、set数据集继承),SAS 发出此 WARNING,并采用最先声明的长度。例如length city $10; set sashelp.class;,若sashelp.class.name长度为 8,则city仍为 10;但若input name $20.;在length后,则name长度为 20。
认证题中第 4 题idnumber = 4198;(A)与idnumber = '4198';(B)的区别即在此:A 创建数值型idnumber,B 创建字符型(长度由首次赋值决定,通常为 4)。length idnumber = 8;(C)声明数值型长度 8(无效,数值型无字节长度概念),length idnumber $ 8;(D)声明字符型长度 8。
5.3NOTE: The file XXX is not printed because it is missing or empty—— 输出文件未生成的根因分析
第 3 题选项 D “Output is not created as the program fails...” 是干扰项。实际file 'spec'; put ...;语句本身不报错,但若file-specification路径无效或权限不足,LOG 会出现此 NOTE。而题目中file 'file-specification'是占位符,真实考试中会给出合法路径。
更隐蔽的问题是put语句未执行:若data步骤因set数据集为空或if条件全假,则put不触发,文件为空。验证方法:
data _null_; file 'test.out'; if 0 then put 'test'; /* 永不执行 */ run; /* LOG: NOTE: The file test.out is not printed because it is missing or empty */实战技巧:在
put前加put _n_=;输出观测序号,确认put是否被执行;用proc datasets检查输出数据集是否存在;用filename语句显式指定文件路径并检查权限。
本文还有配套的精品资源,点击获取