You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SAS数据集转置:解决列模式不一致导致的代码死循环问题

SAS数据集转置:死循环排查与解决

问题背景

需处理含75个NT变量的数据集,按ID拆分出time、date、code、notes字段并转置为指定格式,但现有SAS代码中的while循环陷入死循环,无法输出正确结果。

原始数据集代码

data have;
  input ID $ 1 NT2  NT3  NT4  NT5   NT6  ;
cards;
1NOTES 12:13:44 03-16-2018 CODE: ABC   AML NOTES 09:13:11 03-12-2018 CODE: OPI   TEST
2NOTES 04:25:09 01-04-2018 CODE: FDS   IMD NOTES 03:25:10 01-09-2018 CODE: FGH   TEST
3NOTES 12:22:49 11-12-2018 CODE: DGH   TESTNOTES 08:02:49 11-11-2018 CODE: LKO   AML
4NOTES 22:02:21 01-14-2018 CODE: MKL   TESTNOTES 07:02:21 01-10-2018 CODE: LOP   IMD
5NOTES 09:01:36 01-23-2018 CODE: HJK   TESTNOTES 09:01:56 01-23-2018 CODE: UIY   TEST
6NOTES 11:01:06 01-20-2018 CODE: LPO   IMD  TEST    NOTES 10:01:30 01-24-2018 CODE: KLO AML

;
run;

期望输出

ID   time        date      code notes
1    12:13:44    03-16-2018 ABC AML
1    09:13:11    03-12-2018 OPI TEST
2    04:25:09    01-04-2018 FDS IMD
2    03:25:10    01-09-2018 FGH TEST
3    12:22:49    11-12-2018 DGH TEST
3    08:02:49    11-11-2018 LKO AML
4    22:02:21    01-14-2018 MKL TEST
4    07:02:21    01-10-2018 LOP IMD
5    09:01:36    01-23-2018 HJK TEST
5    09:01:56    01-23-2018 UIY TEST
6    11:01:06    01-20-2018 LPO IMD/TEST
6    10:01:30    01-24-2018 KLO AML

当前问题代码

data want;
  set have;
  attrib notes length=$50;
     array _nt{*} nt:;
    do i = 1 to dim(_nt) ;
      if not missing(_nt(i)) and index(left(_nt[i]), ' NOTES') then do;
         timestamp=input(scan(_nt(i), 3, " "), time8.0);                                                                                                             
         date=input(scan(_nt(i), 4, " "), mmddyy10.);
         code = substr(_nt[i], index(left(_nt[i]), 'CODE:')+9);
      end;
       /*the while loop is used to concatenate notes that immediately follow the other, but it is running indefinitely*/
       do while(index(left(_nt[i+1]), ' NOTES')=0); 
          notes = catx('/',notes, _nt(i+1));
       end;

    output;
    end;
   drop i nt:;
   format timestamp time8. date mmddyy10.;
run;

死循环原因分析

  1. 循环变量未更新:while循环中没有递增i,导致始终检查同一个_nt[i+1]位置,若该位置不是'NOTES'开头,循环会无限执行。
  2. 逻辑混乱:遍历数组时每个i都输出一次,未按NOTES块分组处理;新NOTES块处理时未重置notes变量,会导致内容叠加错误。
  3. 数组越界风险:当i等于数组维度时,_nt[i+1]会访问不存在的元素,引发未知错误。

修正后的解决方案

换用字符串拼接+块分割的思路,避免数组遍历的循环问题:

data want;
  set have;
  length full_str $2000 time $8 date $10 code $10 notes $50;
  /* 拼接所有NT变量为完整字符串 */
  full_str = catx(' ', of nt:);
  /* 按NOTES分割出每个记录块,循环处理 */
  do j = 1 to count(full_str, 'NOTES');
    block = scan(full_str, j, 'NOTES');
    if strip(block) = '' then continue;
    /* 解析time、date */
    time = scan(block, 1, ' ');
    date = scan(block, 2, ' ');
    /* 解析code:提取CODE:后的第一个单词 */
    code_pos = index(block, 'CODE:');
    code = scan(substr(block, code_pos+5), 1, ' ');
    /* 解析notes:拼接CODE后多值内容,去除多余斜杠 */
    notes_part = substr(block, code_pos+5+length(code));
    notes = catx('/', scan(notes_part, 1, ' '), scan(notes_part, 2, ' '));
    notes = compress(notes, '/', 's');
    /* 输出当前记录 */
    output;
  end;
  drop full_str block code_pos notes_part j nt:;
run;

代码说明

  1. 字符串拼接:将所有NT变量合并为一个字符串,简化后续处理逻辑。
  2. 块分割处理:通过count(full_str, 'NOTES')确定每个ID对应的记录数,用固定次数的do循环替代while循环,彻底避免死循环。
  3. 字段解析:分别提取time、date、code,将CODE后的多值notes用斜杠拼接,自动处理空值和多余符号。

内容的提问来源于stack exchange,提问作者lydias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 17:10:28