# SAS Base

# Base言語活用のポイント

- マクロの世界とdataステップの世界を分けて考える
- シングルクォートとダブルクォートの違いをしっかり押さえる
- ステートメント、ステートメントに紐づくオプション、データセットに紐づくオプションをしっかり区別する
- dataステップが実際に動くときのなんとなくのイメージを掴む 
    - 記述するのは列名とかだけであるが、実際の処理では1行ずつループされる
- 他のプログラミング言語とは異なり、「マクロを呼び出した箇所にマクロの定義内容を出力する」性質を持っている。そのため、カンマ区切りの内容だけを持つマクロを定義し、proc sqlのselect句の指定部分に用いるなどの芸当が可能。

# dataステップ内関数(文字列の情報取得)

# count関数

文字列Xに存在する'A'の個数をカウントする。`count(X, 'A')`

# length関数

文字列Xの長さを1バイト単位で取得する。`length(X)`

# klength関数

文字列Xの長さを文字数単位で取得する（1バイト文字も2バイト文字も長さ1としてカウント）。`klength(X)`

# index関数

文字列Xの最初の'ABC'の開始位置を取得する。`index(X, 'ABC')`

# substr関数

文字列Xの部分文字列（5～8文字目）を取得する。`substr(X, 5, 8)`

# dataステップ内関数(文字列の編集)

# cat関数

文字列を結合する。`cat(X, Y, ...)`

# cats関数

文字列の先頭・末尾のスペースを取り除き、結合する。`cats(X, Y, ...)`

# catx関数

文字列の先頭・末尾のスペースを取り除き、指定した区切り文字で結合する。`catx('区切り文字', X, Y, ...)`

# tranwrd関数

- 文字列X内の'ABC'を'XYZ'に置換する。`tranwrd(X, 'ABC', 'XYZ')`
  - `tranwrd(変換したい文字列, 検索文字列, 置換する文字列)`
  - [TRANWRD関数 - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/lefunctionsref/p0pgemqcslm9uen1tvr5gcrusgrw.htm)

# compress関数

文字列Xから、指定した文字Aをすべて取り除く。除去対象の文字列を指定しない場合は、スペースをすべて取り除く。`compress(X, 'A')`

# trim関数

文字列の末尾のスペースを取り除く。`trim(X)`

# strip関数

文字列の先頭および末尾のスペースを取り除く。`strip(X)`

# dataステップ内関数(その他)

# fileexist関数

- 外部ファイルの存在を確認する。存在する場合は`1`、存在しない場合は`0`が返却される。
  - [FILEEXIST関数 - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/lefunctionsref/n06xm8hwk0t0axn10gj16lfiri43.htm)

# グローバルステートメント

# filenameグローバルステートメント

- 外部ファイル（.csvや.xlsxなど）がある場所に「ファイル参照名」を付ける（パス情報を特別な変数に入れる）
  - [filenameステートメント](https://documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/lestmtsglobal/p05r9vhhqbhfzun1qo9mw64s4700.htm)

``` sas
filename test_data = 'C:\SAS_Study\test.csv';
proc import datafile=test_data out=work.test dbms=csv replace;
    getnames = yes;
    datarow = 2;
run;
```

# xグローバルステートメント

- OSコマンドを実行する。
  - [xステートメント- SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/lestmtsglobal/p11ba12uypvfazn1jk7acffuzlbl.htm)

# libnameグローバルステートメント

- SASデータセットが格納されるSASライブラリを定義する。
  - [libnameステートメント](https://documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/lestmtsglobal/n1nk65k2vsfmxfn1wu17fntzszbp.htm)
- データセット以外にも「SASエンジン」を指定することで、他のタイプのファイルへのアクセスを可能にすることもできる。

# procステップ

[PROCステップ - SAS® Help Center](https://documentation.sas.com/doc/ja/lrcon/9.4/n0k19ydenc62jtn14mpv4fhzjmyg.htm)

# proc sortステートメント

- データセットのソートを行う。
  - [proc sortステートメント - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/proc/p02bhn81rn4u64n1b6l00ftdnxge.htm)

#### サンプル

``` sas
proc sort data=sashelp.cars out=work.cars_sorted;
by Model;
run;
```

#### オブション
`proc sort`から`;`までの間にスペース区切りで記述する。

|オプション|指定する内容|説明|
|-|-|-|
|data=|データセット名|ソート対象のデータセットを指定|
|out=|データセット名|ソートした内容を格納するデータセットを指定（指定しない場合は上書きされる）|
|nodupkey|-|重複の削除を行う場合は指定<br>（キー変数について、重複するデータがあった場合は重複している2件目以降の行を削除する）|

#### プロシジャ内ステートメント
`proc sort ～;`から`run;`までの行に記述する。

|ステートメント|指定する内容|説明|
|-|-|-|
|by|列名|ソートのキーとする列を指定<br>（列名の直前に`descending`を付与することで、降順でソートできる）|

# proc transposeステートメント

- データセットを転置する。
  - [proc transposeステートメント - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/proc/p1r2tjnp8ewe3sn1acnpnrs3xbad.htm)

#### サンプル

``` sas
proc sort data=sashelp.cars out=work.cars_sorted;
by Model;
run;

proc transpose data=work.cars_sorted out=work.cars;
by Model;
run;
```

#### オブション
`proc transpose`から`;`までの間にスペース区切りで記述する。

|オプション|指定する内容|説明|
|-|-|-|
|data=|データセット名|転置対象のデータセットを指定|
|out=|データセット名|転置後のデータセットを指定|
|prefix=|文字列|転置後の列名に付与したい接頭辞を指定|
|suffix=|文字列|転置後の列名に付与したい接尾辞を指定|

#### プロシジャ内ステートメント
`proc transpose ～;`から`run;`までの行に記述する。

|ステートメント|指定する内容|説明|
|-|-|-|
|by|列名|転置せずにそのまま残す列を指定<br>（byを使用する場合は、指定する列で事前にソートしておく必要がある）|
|var|列名|転置する列を指定|
|id|列名|列の内容を「転置後の列名」として使用する列を指定|
|idlabel|列名|転置後の変数ラベルとして使用する変数を指定|

# proc importステートメント

- 外部ファイルを読み込む。
  - [proc importステートメント - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/proc/n18jyszn33umngn14czw2qfw7thc.htm)

#### サンプル

``` sas
proc import datafile='C:\SAS_Study\test.csv' out=work.test dbms=csv replace;
    getnames = yes;
    datarow = 2;
run;
```

``` sas
filename input_data = 'C:\SAS_Study\input_data.txt'
proc import datafile=input_data out=work.test dbms=tab replace;
    getnames = yes;
run;
```

#### オブション
`proc import`から`;`までの間にスペース区切りで記述する。

|オプション|指定する内容|説明|
|-|-|-|
|datafile=|ファイルパス<br> or ファイル参照名|「入力ファイルのフルパス」または「filenameステートメントで定義したファイル参照名」を指定|
|out=|データセット名|転置後のデータセットを指定|
|dbms=|データソース名|外部ファイルのデータの種類を指定<br>xlsx / csv / tab / dlm(delimiterステートメントと併用)|
|replace|-|出力データセットを上書きする場合は指定|

#### プロシジャ内ステートメント
`proc import ～;`から`run;`までの行に記述する。

|ステートメント|指定する内容|説明|
|-|-|-|
|getnames=|yes / no|列名情報をファイルから取得するかどうかを指定|
|sheet=|Excelシート名|読み込むシート名を指定（dbms=xlsxの場合のみ有効）|

# proc exportステートメント

- データセットを外部ファイルへ出力する。
  - [proc exportステートメント - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/proc/n0ku4pxzx3d2len10ozjgyjbrpl9.htm)

#### サンプル

``` sas
proc export data=sashelp.class outfile='C:\SAS_Study\class.csv' dbms=csv replace;
run;
```

``` sas
proc export data=sashelp.class outfile='C:\SAS_Study\class.xlsx' dbms=xlsx replace;
    sheet = class;
run;
```

#### オブション
`proc export`から`;`までの間にスペース区切りで記述する。

|オプション|指定する内容|説明|
|-|-|-|
|data=|データセット名|出力対象のデータセットを指定|
|outfile=|ファイルパス<br> or ファイル参照名|「出力先ファイルのフルパス」または「filenameステートメントで定義したファイル参照名」を指定|
|dbms=|データソース名|外部ファイルのデータの種類を指定<br>xlsx / csv / tab / dlm(delimiterステートメントと併用)|
|replace|-|出力データセットを上書きする場合は指定|

#### プロシジャ内ステートメント
`proc export ～;`から`run;`までの行に記述する。

|ステートメント|指定する内容|説明|
|-|-|-|
|putnames=|yes / no|列名情報をファイルに書き出すかどうかを指定（デフォルトはyes）|
|sheet=|Excelシート名|読み込むシート名を指定（dbms=xlsxの場合のみ有効）|

# proc univariateステートメント

- 各種統計量を算出し、レポートを出力する。
  - [univariateプロシジャ - SAS® Help Center](https://documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/procstat/procstat_univariate_toc.htm)

``` sas
proc univariate data=sashelp.class normal plot;
    var height;
    output out=work.result n=n mean=mean std=std median=median;
run;
```

# データセットオプション

# データセットオプションの概要

- dataステップのsetステートメントなどで、データセット名の直後に`データセット名(～～～)`のように記述し、利用する。
  - 複数のオプションを指定する場合はスペースで区切る。
  - [カテゴリ別のデータセットオプション - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/ledsoptsref/n03k13diwk36x1n1az3mpixdfbfp.htm)


``` sas
data work.test;
set sashelp.class(keep=Name Height Weight where=(Height>60 and Weight>100));
run;
```

# keep=データセットオブション

保持したい列名をスペース区切りで記載する。ここに記載されていない列はそもそも読み込まれないため、dataステップなどで使用不可となる。

# drop=データセットオプション

除去したい列名をスペース区切りで記載する。ここに記載した列はそもそも読み込まれないため、dataステップなどで使用不可となる。

# where=データセットオプション

<https://documentation.sas.com/doc/ja/pgmsascdc/v_061/ledsoptsref/p0ny9o8t8hc5zen1qn3ft9dhtsxx.htm>

データセット行の取得条件を指定する。
条件部分は`()`で括り、`where=(Height>60 and Weight>100)`のように記述する必要がある。
(`keep=`や`drop=`の後に`where=`が処理される)

``` sas
data work.test;
  set sashelp.class(where=(Height>60 and Weight>100));
run;

# rename=データセットオブション

データセットの列名を異なる列名で読み込む。`rename=(name1=new_name1 name2=new_name2)`のようにセットで指定する。(`keep=`や`drop=`の後に`rename=`が処理される)



``` sas
data work.test;
  set work.table1(rename=(name1=new_name1 name2=new_name2));`
run;
```

# 外部ファイルを読み込む

# Excelファイルを読み込み、データセット化するマクロ

- `proc import`を使用する。

``` sas
%macro ImportExcel(i_file_path=, i_sheet_name=, ods_output_name=);
    proc import datafile=&i_file_path out=&ods_output_name. dbms = xlsx replace;
        getnames = yes;
        sheet = &i_sheet_name.;
    run;
%mend ImportExcel;
```

# 外部CSVファイルをproc importプロシジャで読み込み、データセット化する

``` sas
proc import datafile='C:\SAS_Study\test.csv' out=work.work.test dbms=csv replace;
    getnames = yes;
    datarow = 2;
run;
```

``` sas
filename input_data = 'C:\SAS_Study\input_data.txt' 
proc import datafile=input_data out=work.test dbms= replace;
    getnames = yes;
run;
```

# 外部CSVファイルをdataステップで読み込み、データセット化する

``` sas
filename sample "C:\SAS_Study\test2.csv";
data work.test;
    infile sample dim="," firstobs=2;
    input id:$8. name:$32. class:8.;
run;
```

# 外部ファイルの読み込み(proc import)

- [proc importステートメント - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/proc/n18jyszn33umngn14czw2qfw7thc.htm)

##### サンプル

``` sas
proc import datafile='C:\SAS_Study\test.csv' out=work.test dbms=csv replace;
    getnames = yes;
    datarow = 2;
run;
```

``` sas
filename input_data = 'C:\SAS_Study\input_data.txt'
proc import datafile=input_data out=work.test dbms=tab replace;
    getnames = yes;
run;
```

##### オブション
`proc import`から`;`までの間にスペース区切りで記述する。

|オプション|指定する内容|説明|
|-|-|-|
|datafile=|ファイルパス<br> or ファイル参照名|「入力ファイルのフルパス」または「filenameステートメントで定義したファイル参照名」を指定|
|out=|データセット名|転置後のデータセットを指定|
|dbms=|データソース名|外部ファイルのデータの種類を指定<br>xlsx / csv / tab / dlm(delimiterステートメントと併用)|
|replace|-|出力データセットを上書きする場合は指定|

##### プロシジャ内ステートメント
`proc import ～;`から`run;`までの行に記述する。

|ステートメント|指定する内容|説明|
|-|-|-|
|getnames=|yes / no|列名情報をファイルから取得するかどうかを指定|
|sheet=|Excelシート名|読み込むシート名を指定（dbms=xlsxの場合のみ有効）|

# infileステートメント

- データセットとして読み込む外部ファイルの情報を指定する。
  - [infileステートメント - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/lestmtsref/n1rill4udj0tfun1fvce3j401plo.htm)

``` sas
filename test_data "C:\SAS_Study\test2.csv";
data work.test;
    infile test_data dim="," firstobs=2;
    input id:$8. name:$32. class:8.;
run;
```

# 制御文字を文字リテラルで扱う

# 改行文字CR

```
'0D'x
```

# 改行文字LF

```
'0A'x
```

# タブ文字

```
'09'x
```

# proc sql内で「欠損値かどうか」の条件を指定する

`where`ステートメント内で`is missing演算子`を使用する。反転する場合は`is not missing`を使用する。

# dataステップ内で「欠損値かどうか」の条件を指定する

`missing(列名)`を使用する。反転する場合は`not missing(列名)`とする。

# 指定の文字列をN回繰り返した文字列を用意する

dataステップ内で`repeat(繰り返したい文字, N - 1);`を使用する。もしくは `N * '繰り返したい文字'`とする。

# proc sqlでのサブクエリの使用

- 通常のSQLのように記述できる。

# dataステップ内のset句で読み込んだデータセットに、行番号を付与する

`set データセット名 CUROBS=一時変数名`で新しい列に行番号を挿入できる。

# データセットの列の重複を削除して取得

`proc sort`および`nodupkey`を使用する。

```sas
/* carsデータセットのMake列の内容を、重複削除して取得する */
proc sort data=sashelp.cars(keep=Make) out=work.cars nodupkey;
    by logic_type;
run;

```

# ログにテキストや変数の内容を出力する

- dataステップ内では`put`、マクロ内では`%put`を使用する。
- データセット内の変数を出力する場合は、シングルクォートやダブルクォートで括る必要はなく、変数名をそのまま指定する。
- 複数の内容を連結して出力する場合、`put`は半角スペースで並べて記載、`%put`は`||`や`cats()`で明示的に結合して記載する。
- `put`でデータセットの列を並べて記載した際、不要な半角スペースが付与されてしまう場合は、列名の直後に`+(-1)`を記載しておく。（詳細はputステートメントのリファレンスに記載されている）

```sas
%let val = test;
%put &val.;

```

```sas
data _null_;
    set sashelp.class;
    put Name +(-1) ', ' Age ;
run;

```

# リスト文字列などを指定の区切り文字で区切り、n番目の要素を取り出す

dataステップ内で`scan(文字列, n, 区切り文字(指定しない場合はあらゆる文字列で分割する))`を使用し、値を取り出す。

# データセットの内容はいじらないが、dataステップ内で使用できる関数を使用したいとき

- 出力先データセット名に`_null_`を指定する。

```sas
data _null_;
  put 'ログ出力のテスト';
run;

```

# リスト文字列の要素でループする

- `%do %while`などを組み合わせる。

```sas
%macro LoopTest();
    %let name_list = AAA BBB CCC DDD;
    %let index = 1;
    %let name = %scan(&name_list., &index., ' ');

    %do %while(not %sysevalf(%superq(name) =, boolean));
        %put &name.;

        %let index = %eval(&index. + 1);
        %let name = %scan(&name_list., &index., ' ');
    %end;
%mend LoopTest;

```

# proc sqlで取得したクエリ結果を、区切り文字で結合しマクロ変数に代入する

- `into: マクロ変数名 separated by '区切り文字'`を用いる。 
    - 複数列から出力する場合でもintoは1つだけ。マクロ変数名にコロンを前置する
    - [INTO句 - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/mcrolref/n1y2jszlvs4hugn14nooftfrxhp3.htm)

```sas
proc sql noprint;
    select Name, Age
        into :name_list separated by ' ', age_list separated by ' '
        from sashelp.class
        where age > 12;
quit;

```

# SASデータセットの各行の値を(任意の区切り文字)で結合し、文字列としてマクロ変数に格納する

- `retain`や`end = eof`を活用する。 
    - [RETAINステートメント - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/lestmtsref/p0t2ac0tfzcgbjn112mu96hkgg9o.htm)

```sas
data _null_;
    set work.input_table end = eof;
    attrib
        input_file_list length = $1000.
        output_file_list length = $1000.
    ;
    retain input_file_list output_file_list;

    input_file_list = catx(' ', input_file_list, cats('input_', category, '.xlsx'));
    output_file_list = catx(' ', output_file_list, cats('output_', category, '.csv'));

    /* 最後まで行ったらマクロ変数に出力 */
    if (eof) then do;
        call symputx("input_file_list", input_file_list, 'G');
        call symputx("output_file_list", output_file_list, 'G');
    end;
run;

```

- `end=一時変数名` 最後の行を読み込んだ時、一時変数に「1」が入る
- `_N_` データステップの反復回数（処理中の行番号）が格納される
- `cats(値1, 値2, ...)` 引数値の両端の半角スペースを除いて結合する

# 外部ファイルにテキストを出力する

- `filename`および`file`ステートメントを使用する。 
    - `filename` ... 「SASファイル参照名」と「外部ファイルまたは出力デバイス」の関連付け・関連付けの解除を行う。
    - `file` ... putステートメントの出力先ファイルを指定する。

```sas
data _null_;
    filename OUTFILE "file_path";
    file OUTFILE encoding="utf-8"; /* ファイル内容を空っぽにする */
run;

data _null_;
    set sashelp.class;
    file OUTFILE MOD; /* ファイルに追記する */
    put Name;
run;

```

# 文字列「yyyymmdd_hhmmss」を得る

```
%local _timestamp;
data _null_;
    call symputx("_timestamp", put(today(), yymmddn8.) || '_' || compress(put(datetime(), tod8.), ':'));
run;

```

# よく使うシステムオプション

- [カテゴリ別のシステムオプション - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/lesysoptsref/p0r3gu6wvyq0l0n1gkadgl7iukfm.htm)

##### ログを簡素化する

```sas
option nosource nonotes;

```

- `nosource` ... ソースステートメント（実行しているSASコードの内容）をSASログに表示しないようにする
- `nonotes` ... NOTEログを表示しないようにする（エラーメッセージや警告メッセージは変わらず表示される）

##### ログを詳細化する

```sas
option symbolgen mprint mlogic;

```

- `symbolgen` ... マクロ変数の置換結果を表示する
- `mprint` ... マクロ実行時に行われるSASステートメントをログに出力する
- `mlogic` ... マクロ変数の評価式やマクロの実行開始、終了をログに出力する

# リスト文字列の要素でループする

- `%do %while`などを組み合わせる。

```sas
%macro LoopTest();
    %let name_list = AAA BBB CCC DDD;
    %let index = 1;
    %let name = %scan(&name_list., &index., ' ');

    %do %while(not %sysevalf(%superq(name) =, boolean));
        %put &name.;

        %let index = %eval(&index. + 1);
        %let name = %scan(&name_list., &index., ' ');
    %end;
%mend LoopTest;

```

# 文字列の長さに合わせてブロックコメントを生成する

- `length()`および`klength()`を組み合わせ、マルチバイト文字を含めたいい感じの文字長を計算し、ブロックコメントを生成する。 
    - 実行環境によってはうまくいかないこともある。

```sas
data _null_;
    comment_text = strip(&comment_contents.);
    comment_len = (length(comment_text) - klength(comment_text)) / 2 + klength(comment_text);
    comment_line = '/*-' || repeat('-', comment_len - 1) || '-*/';
    put comment_line;
    put '/* ' "&comment_contents." ' */';
    put comment_line;
run;

```

# proc sqlで取得したクエリ結果を、区切り文字で結合しマクロ変数に代入する

- `into: マクロ変数名 separated by '区切り文字'`を用いる。（複数列から出力する場合でもintoは1つだけ．マクロ変数名にコロンを前置する） 
    - [INTO句 - SAS® Help Center](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/mcrolref/n1y2jszlvs4hugn14nooftfrxhp3.htm)

```sas
proc sql noprint;
    select Name, Age
        into :name_list separated by ' ', age_list separated by ' '
        from sashelp.class
        where age > 12;
quit;

```

# ods htmlステートメント

- データセットやレポートをHTMLファイルへ出力する。 
    - [ods htmlステートメント](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/grmapref/n06apepzft3fsen1x9ku6sr8ytfi.htm)

```sas
ods html file='C:\SAS_Study\class.html';
proc means data=sashelp.class;
run;
ods html close;

```

# 日時データの利用

- [YYMMDDx出力形式](https://documentation.sas.com/doc/ja/vdmmlcdc/8.1/leforinforref/p0iptsg6780kzfn1k5f0b8s7k7dq.htm)

```sas
data work.date_info;
now_datetime = datetime(); 
now_date = datepart(now_datetime);
now_time = timepart(now_datetime);

yyyymmddn = put(now_date, yymmddn8.); /* yyyymmdd(n:区切り文字なし) */
yyyymmddb = put(now_date, yymmddb8.); /* yyyymmdd(b:スペース区切り) */
yyyymmddc = put(now_date, yymmddc8.); /* yyyymmdd(c:コロン区切り) */
yyyymmddd = put(now_date, yymmddd8.); /* yyyymmdd(d:コロン区切り) */
yyyymmddp = put(now_date, yymmddp8.); /* yyyymmdd(p:ピリオド区切り) */
yyyymmdds = put(now_date, yymmdds8.); /* yyyymmdd(s:スラッシュ区切り) */
yyyymdd10 = put(now_date, yymmdd10.); /* yyyy-mm-dd */
ddmmmyyyy = put(now_date, date10.); /* ddmmmyyyy */
hhmmss = put(now_time, time.); /* hh:mm:ss */

year = year(now_date);
month = month(now_date);
day = day(now_date);

hour = hour(now_time);
min = minute(now_time);
second = second(now_time);

format until_time time8.;
until_day = input('20250101', yymmdd8.) - now_date;
until_sec = input('24:00:00', hhmmss8.) - now_time;
run;

```

# dataステップ内関数の使用例

```sas
data work.test;
set sashelp.class;

height_cm = round(height * 0.0254, 0.01); /* inchをmに変換 */
height_str = put(height_cm, best8.); /* 数値を文字列に変換 */
height_str = tranwrd(height_str, '.', 'm'); /* 文字列を置換 */
height_str = compress(height_str); /* 空白を削除 */
name_height = cats(Name, '_', height_str, 'cm'); /* 文字列を結合 */
run;

```

# ソート済のデータセット列について、その値をもつ「最初の行」や「最後の行」だけで処理を行う

- dataステップ内でbyステートメントを適用すると、byステートメントで指定した列ごとに「first.列名」および「last.列名」の列が生成される。 
    - 使用したいデータセット列は、`proc sort`などであらかじめソートしておく必要がある。
    - [SASによるBYグループの処理方法](https://go.documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/lestmtsref/p0yeyftk8ftuckn1o5qzy53284gz.htm#n1gd3sjlellqfxn1q67on4bzgsfs)
- それぞれ、下記の値が格納されている。 
    - first.列名 ... byステートメントでグループ化された各行のうち、最初の行にのみ'1'が格納されており、それ以外は'0'
    - last.列名 ... byステートメントでグループ化された各行のうち、最後の行にのみ'1'が格納されており、それ以外は'0'
- この変数を使用すると、「最初だけ処理、最後だけ処理」といった処理を行わせることができる。
- `first.column_name`や`last.column_name`を使用し、`if`文で分岐させる。

```sas
proc sort data=sashelp.fish out=work.fish_sorted;
by species;
run;

data work.fish;
set work.fish_sorted(where=(not missing(Weight))); /* 欠損値の行を削除 */
by species; /* species列でグループ化 */

/* 計算用の列を初期化 */
if first.species then do;
count = 0;
weight_sum = 0;
end;

/* グループ内の行について、件数と合計を計算 */
retain count weight_sum;
count = count + 1;
weight_sum = weight_sum + Weight;

/* 平均値を計算し、行を出力 */
if last.species then do;
weight_avg = round(weight_sum / count, 0.1);
output;
end;

/* 出力したい列を指定 */
keep species count weight_sum weight_avg; 
run;

```

# CASL

# table.loadTableアクション

[https://documentation.sas.com/doc/ja/pgmsascdc/v_061/caspg/cas-table-loadtable.htm](https://documentation.sas.com/doc/ja/pgmsascdc/v_061/caspg/cas-table-loadtable.htm)

# table.promoteアクション

[https://documentation.sas.com/doc/ja/pgmsascdc/v_061/caspg/cas-table-promote.htm](https://documentation.sas.com/doc/ja/pgmsascdc/v_061/caspg/cas-table-promote.htm)