📑 TFL 输出模板

← 知识体系

Table

Table优化:减少冗余计算

原代码在if块内反复调用index()——每条记录重复10+次。改为前置计算布尔值

SAS
/* ❌ 低效:if块内重复index() */
if TRTEMFL = "Y" then do;
    ACNFL1 = ifc(index(AEACN1,"暂停用药")>0 or index(AEACN2,"暂停用药")>0, "Y", "N");
    ACNFL2 = ifc(index(AEACN1,"暂停用药")>0 and index(AEACN2,"暂停用药")>0, "Y", "N");
    /* ... 重复8次index() ... */
end;

/* ✅ 高效:前置计算布尔值,后面直接引用 */
ACN_PAUSE1 = index(AEACN1, "暂停用药") > 0;  /* 只算一次 */
ACN_PAUSE2 = index(AEACN2, "暂停用药") > 0;
ACN_STOP1  = index(AEACN1, "永久停药") > 0;
ACN_STOP2  = index(AEACN2, "永久停药") > 0;

if TRTEMFL = "Y" then do;
    ACNFL1 = ifc(ACN_PAUSE1 | ACN_PAUSE2, "Y", "N");  /* 直接引用 */
    ACNFL2 = ifc(ACN_PAUSE1 & ACN_PAUSE2, "Y", "N");
    /* ... */
end;
drop ACN_PAUSE1 ACN_PAUSE2 ACN_STOP1 ACN_STOP2;

手动构建dummy数据

有些Table需要0行也显示——当某SOC/PT下没有事件时,构建空的dummy记录来占位。

SAS
/* TEAE Table dummy:每个SOC/PT都遍历所有治疗组和relord */
data DUMMY;
    set DUM;
    if AESOC = "" then do;          /* "Any TEAEs" 行 */
        GRP=1; ORD1=0;
        do TRT=1 to 11,99; output; end;
        GRP=1; ORD1=1;
        do RELORD=1 to 2;
            do TRT=1 to 11,99; output; end;
        end;
    end;
    /* SOC和PT级别同理... */
run;

Listing

Hash对象维护排序序号

Listing中需要按col1、col2分组内对col3的值从1开始编号——Hash对象比DATA步retain更可靠。

SAS
/* Hash对象:按(col1, col2)内col3首次出现序号递增 */
data FIN1;
    if _n_ = 1 then do;
        dcl hash H();
        H.defineKey('COL1', 'COL2', 'COL3');
        H.defineData('SEQ');
        H.defineDone();
    end;
    set FIN;
    by ORD COL1 COL2 VISITNUM COL3;
    retain MAXSEQ 0;

    if first.COL2 then MAXSEQ = 0;

    if H.check() ^= 0 then do;
        MAXSEQ + 1;
        SEQ = MAXSEQ;
        RC = H.add();
    end;
    else RC = H.find();

    drop RC MAXSEQ;
run;
proc sort; by ORD COL1 COL2 SEQ COL3 VISITNUM; run;

分页 & 受试者不跨页

SAS
/* 每10条记录一页 */
PAGE = ceil(_n_ / 10);

/* 波浪号转义:避免RTF解析为不可见字符 */
if index(VISIT, '~') then
    VISIT = tranwrd(VISIT, '~', '~{unicode 007E}');

ODS导出Excel

SAS
/* ODS Excel 导出(推荐:比PROC EXPORT更可控) */
ods excel file="&OUTPATH.\ADaM_&RUNDATE._rawdata.xlsx"
    options(
        frozen_headers = '1'
        autofilter     = 'all'
        embedded_titles= 'yes'
    );

proc print data=ADAM.ADAE label noobs; run;
proc print data=ADAM.ADCM label noobs; run;

ods excel close;

常见坑

⚠️ raw_text排序异常?先看format。出Table时如果排序结果和预期不符,检查format是否截断了实际值。
⚠️ SAS中一个中文占3字节。UTF-8编码下定义变量length时中文×3,否则截断。
⚠️ cats会自动去掉两端空格,catx会默认中间加一个空格。两个函数的行为差异常在拼接Table列时造成格式问题。
⚠️ ODS Excel vs PROC EXPORT:ODS Excel支持frozen_headers/autofilter等;PROC EXPORT轻量但格式控制弱。交付推荐ODS。