[ABAP] 7.5xの新しいSELECT文記述方法について(NEW ABAP SQL SELECT IN ABAP 7.5x)（その２）

こんにちは。

今回は、SELECT文の書き方についての2回目となります。
7.5xでSELECTでできることは大きく増えていますが、自分で業務で書くコードで必要性が高いと
考えたものについてまとめてみました。
※実行環境がベーシスリリース7.53ですので、最新リリースの7.54については未確認です。
また、ABAP SQLでの検証となりますので、ABAP CDSのみで動作する機能についても
動作確認をしていません。その点のご留意をお願いいたします。

## 記事一覧

- [7.5xの新しいSELECT文記述方法について（その１）] (https://qiita.com/Go_Ohta/items/3882caf9149619e8bdd7)
    - これまでの記述方法との比較、FIELDS句、インライン定義
 
- [7.5xの新しいSELECT文記述方法について（その２）] ※当記事
    - リテラル・固定値・演算値・文字列編集・条件分岐・型変換

- [7.5xの新しいSELECT文記述方法について（その３）] (https://qiita.com/Go_Ohta/items/bf7bd6f2964675c97740)
    - 日付系機能・グループ化・内部テーブルをデータソースとして使用・UNION/WITH・RIGHT JOIN/CROSS JOIN

・・・

---
## 内容

- リテラル値・固定値・変数・項目初期値を取得項目に指定する

- 演算値を取得項目に指定する
    - 数値用機能（Numeric Functions）一覧

- 文字列編集処理の結果を項目に設定する
    - 文字列編集用機能（String Functions）一覧

- CASEによる条件分岐

- COALESCEによる条件分岐

- CASTによる型変換

- 次回予定

---

## 1.リテラル値・固定値・変数値・項目初期値を取得項目に指定する

リテラル値・CONSTANTSで定義した固定項目値・変数値を、SQLの取得項目として指定できます。
インライン宣言による内部テーブル定義の場合で、項目定義時（＝SELECT時）に値を設定できないような場合は、初期値を設定することが可能です。

```abap:リテラル値・固定値・変数・初期値
DATA: var1 TYPE char10 VALUE 'VARIABLES'.
CONSTANTS: CONS1 TYPE char10 VALUE 'CONSTANTS'.

SELECT FROM vbak AS t1
    FIELDS
      'LITERAL' AS lit,                  "リテラル値
      @var1 AS  var_field,               "変数
      @CONS1 AS cns_field,               "固定値
      @abap_on as check,                 "予約語
      @( VALUE vbak-erdat( ) ) AS erdat, "初期値
   INTO TABLE @DATA(results).

```

リテラル値以外は先頭に「@」を付ける必要があります。固定値を設定することのメリットとして、
初期値設定に利用できるという点かな、と思っていました。しかし、その後下記のように、データの存在チェックとして任意の項目値を取得する場合に、取得処理とその後の判定ロジックを使いまわせる点もあるとのことです。

```abap:存在チェックサンプル
SELECT FROM MARA as t1
  FIELDS @abap_on 
  where …
  into @lw_exist_chk.
if lw_exist_chk.  "「= abap_on」の記述を省略
" データが存在した場合のロジック
else.
" データが存在しなかった場合のロジック
endif.

```
※この情報は、下記openSAPの内容から参考にさせていただきました。
[openSAP ABAP Development for SAP 3rdWeek Unit.1 Recent Open SQL Enhancements - Part 1](https://open.sap.com/courses/a4h1/items/1oht7BmOsOuoIRd2BVLPCn)

---
## 2.演算値を取得項目に指定する

テーブル項目値や変数、数値リテラルを使用した演算結果を項目値として格納することができます。
制限として以下があります。

* 負の値、小数位を持ったリテラルは使用できない（-10、1.1など）→変数に値を事前定義して使用する
    * ABAP CDSの場合は小数点ありリテラル数値を記載しても適切に動作するようです

* 除算を使用する場合、後述のDIVかDIVISIONを使う方が便利ですが、「/」を使用する場合は割る側も割られる側もFLTP、DECFLOAT16、DECFLOAT34のどれかににCAST（型変換）するようにとSAPHELPに記載があります。ただし、DECFLOAT16と同34は7.54から導入されたため、結果を確認できていません。

```abap:演算値
SELECT FROM vbap
    FIELDS
       netwr,  "項目IDがNETWRで定義される
       kwmeng, "項目IDがkwmengで定義される
       netwr * 100 AS jpy_netwr, "演算結果
       CASE kwmeng "条件分岐
        WHEN 0 THEN 0
        ELSE division( netwr , kwmeng, 3 )
       END AS calc2,
       CASE kwmeng 
         WHEN 0 THEN CAST( 0 AS FLTP )  "結果がFLTP型になるため
         ELSE CAST( netwr AS FLTP ) / CAST( kwmeng AS FLTP )
       END AS calc3
    INTO TABLE @DATA(results).
```

上記2つのコードは、インライン宣言で内部テーブルを定義しています。それらのFIELDS句の各項目を見ると、
`netwr,` のようにASで項目名を定義していないものと、
`netwr * 100 AS jpy_netwr,` のようにASで項目名を定義している2種類があります。
この違いについては以下のとおりです。

* **ASによる項目名定義が必要**
    * リテラル値、固定値、変数値
    * 項目名重複などの理由で、DB項目名と内部テーブル項目定義名を異なる名称にする場合
        *  `netwr AS netwr2` など
    * 演算値、編集加工値、型変換（上記のCAST）、条件分岐（上述のCASE）の結果


* **ASによる項目定義を省略可能**
    * DB項目値そのままを取得しDB項目名と同じ名称で内部テーブル項目名を定義する場合
        * `kwmeng as kwmeng → kwmeng のみでOK`


### 数値用機能（Numeric Functions）一覧

すでにDIVISIONが上記のサンプルコードに登場していますが、
数値項目処理用の機能概要を以下一覧にまとめます。（以前からあるSUM・AVGなどは省略）。

|機能|説明|
|:---|:---|
| ABS      |対象値の絶対値|
| CEIL     |対象値より小さくない、最大の整数|
| DIV      |対象2値を除算したときの商<br/>※2値の符号が異なる場合は負の値|
| DIVISION |対象2値の除算結果を指定小数位で丸める|
| FLOOR    |対象値より大きくない、最小の整数|
| MOD      |対象値2値を除算したときの余り|
| ROUND    |対象値を指定された桁で丸め|

[SAPHELP Arithmetic Functions](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abensql_arith_func.htm)

---

## 3.文字列編集処理の結果を項目に設定する

簡単な文字列の編集処理がSQLでできるようになりました。

```abap:文字列編集
SELECT FROM sflight
  FIELDS
    @abap_on AS check, "固定値
    carrid,
    connid,
    concat_with_space( carrid,connid,4 ) AS cws,
    left( planetype, 3 ) AS plane_series1,
    length( planetype ) as plane_series2,
    lpad( CAST( paymentsum AS CHAR ) , 20, '0'  ) AS paymentsum_char,
    concat_with_space( CAST( seatsmax_b AS CHAR ), CAST( seatsocc_b AS CHAR ), 2 ) AS field_concat
 INTO TABLE @DATA(results).
```

###文字列編集用機能（String Functions）一覧

文字列項目処理用の機能概要を以下一覧にまとめます。

|機能|説明|
|:---|:---|
| LOWER            |対象値内の1バイト英大文字を英小文字に変換|
| UPPER            |対象値内の1バイト英小文字を英大文字に変換|
| CONCAT           |2項目の文字列結合。各項目の後ろの1バイトスペースは無視される。 ※3項目以上の場合はネストする<br />|
| CONCAT_WITH_SPACE|CONCATと同様だが、文字列間に1バイトスペースを指定数分設定する|
| LEFT             |対象値の左側から、文字数分の内容を取得|
| LPAD             |対象値の左側から、指定した長さまで指定文字で埋める|
| LTRIM            |対象値の左側から、指定文字を除去|
| RIGHT            |対象値の右側から、文字数分の内容を取得|
| RPAD             |対象値の右側から、指定した長さまで指定文字で埋める|
| RTRIM            |対象値の右側から、指定文字を除去|
| INSTR            |対象値の中で指定値が最初に発生する位置を返す ※位置が1文字目の場合は1 |
| LENGTH           |文字列の文字数を取得|
| REPLACE          |対象値内にある変換前値すべてを、変換後値に変換|
| SUBSTRING        |対象値の指定位置から、指定文字数分の内容を取得|

[SAPHELP String Functions](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abensql_string_func.htm)

なお、文字列リテラルや一部の文字項目（制限あり）を連結する場合は、「&&」を使用した連結が可能です。

```ABAP:文字列連結

FIELDS
  'PARTNER NAME IS ' && ADRC~name1 && ' ' && ADRC~name2 as FIELD1 "&&で結合した場合

  CONCAT( 'PARTNER NAME IS ' , 
          concat_with_space( ADRC~name1, ADRC~name2, 1 ) ) as field1 "CONCAT系で書いた場合
```
ただし、結合できる項目がリテラル値または、ディクショナリタイプがCHAR、CLNT, CUKY, LANG, UNITのものとなります。
また後述するCASTを使用して文字列への型変換をした値も使用できないため、基本的に「テキスト項目のみを連結する場合のみ」使用可能と
考えておくのが良いかと思います。

---

## 4.CASEによる条件分岐

上述のコードでもう使用済みですが、条件分岐を使用して項目の設定値を決定することが可能となりました。
値（演算値や編集加工値含む）による分岐と、設定値ごとに条件を記述していく2つのパターンがあります。

### 4.1.値による条件分岐

```abap:CASE1
   CASE kwmeng                         "演算値、編集加工値なども使用可能
    WHEN 0 THEN 0                      "WHENは最低1つ必要。THENが必要
    WHEN 1 THEN netwr                  "２つめ以降のWHENは省略可能
    ELSE division( netwr , kwmeng, 3 ) "ELSE省略可能
    END AS calc2,                      "ENDCASEではなくEND
```

### 4.2.複雑な条件分岐

```abap:CASE1
   CASE                                             "何も書かない
    WHEN matnr is initial  THEN 'MATERIAL IS BLANK' "各判定条件をWHENの後に記述
    WHEN matnr = 'DUMMY' and TYPE = 'DUNNY' THEN 'DUMMY MATERIAL' "複数の判定条件を書くことが可能
    WHEN matnr <> 'DUMMY' and TYPE = 'DUMMY' THEN 'INVALID DATA'
    WHEN matnr = 'DUMMY' and TYPE <> 'DUMMY' THEN 'INVALID DATA'
    else 'VALID DATA'
    END AS ERRMSG1
```
どちらの場合も、

* WHENは最低１つ必要、ELSEはなくても可
* 演算値や文字列編集値を判定用項目や条件、設定値に使用可能
* １つのWHEN内の判定条件内に、ANDやORなどを利用して複数の条件を記述可能


[SAPHELP CASE](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abensql_case.htm)

---

## 5.COALESCEによる条件分岐

COALESCE（コアレス）を使用すると、「列挙した値のうち、最初にNull値でない値」を項目値に設定することが可能です。

```abap:COALESCE
COALESCE( A, B, C, D ) as FIELD1
```
上記の場合、A、B、Cの順番で値が確認され、最初にNull値でない値があるとその値がFIELD1に設定されます。
もし、すべての値がNullの場合は、最後に設定されたdの値が設定されます。
上記をCASEで書き換えると以下のようになります。

```ABAP:COALESCE→CASE

CASE 
  WHEN A is not null then A
  WHEN B is not null then B
  WHEN C is not null then C
  ELSE D
  end as FIELD1

```

[SAPHELP COALESCE](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abensql_coalesce.htm)

---

## 6.CASTによる型変換

こちらも上述のコードに出てきていますが、CASTを使用して項目の型を変更することが可能です。
ABAPHELPにあるコードに少し追加をしていろいろ試してみました。変換先をCHARにした場合、制限が少ないようです。

```ABAP:CAST

DELETE FROM demo_expressions.
INSERT demo_expressions FROM @( VALUE #(
         id   = 'X'
         num1 = 111                           "INT4型
         numlong1 = '12345678'     "INT8型
         dec3 = '123.456'                   "DEC型
         dats2 = sy-datum                 "DATS型
         char1  = 'ABCDEFGHIJ'         "CHAR型
         char2  = '0000123456'          "NUMC型
        ) ).

SELECT SINGLE
       FROM demo_expressions
       FIELDS
            CAST( num1      AS CHAR( 20 ) ) AS col1,
            CAST( numlong1  AS DEC( 12, 3 ) ) AS col2,
            CAST( dec3      AS CURR( 10, 2 ) ) AS col3,
            CAST( dats2     AS CHAR( 20 ) ) AS col4,
            CAST( char1     AS CHAR( 4 ) ) AS col5,
            CAST( char2     AS NUMC( 5 ) ) AS col6,
            CAST( concat( @sy-datlo, @sy-timlo )  AS char( 20 ) ) AS col7
       WHERE id = 'X'
       INTO @DATA(results).
 cl_demo_output=>display(  results ).

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326392/32ecb1f0-7209-e719-14ac-14aaf0fafae0.png)

変換前型と変換後型の組み合わせで一部制限があり、下記SAPHELPにて一覧化されています。
[SAPHELP CAST](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abensql_cast.htm)

---

## 7.次回予定

次回は、複数のSQLの処理結果を連結するUNION、WITH、内部テーブルを使ったJOINなどを予定しています。
今回の内容は以上です、ありがとうございました。