Access (一般機能)

Accessの一般機能に関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Home : Microsoft 365)
CHOOSE関数 や SWITCH関数
投稿日時: 24/02/08 15:46:39
投稿者: たらのり

お世話になります
  
SELECT句の中で CHOOSE関数や SWITCH関数を使用していますが、
たとえば、フィールド F1 には値 1 〜 5 が格納されてい、
偶数を NULL としたい場合(例なので わざとらしいものです):
  

SELECT CHOOSE(F1, 1, NULL, 3, NULL, 5) FROM T1;


  
SELECT SWITCH(F1 = 1, 1,
              F1 = 2, NULL,
              F1 = 3, 3,
              F1 = 4, NULL,
              F1 = 5, 5) FROM T1;

とは書けないのは仕様でしょうか(結果の値が文字化けのようになります)。
  
  
次のように書けば OKでした:
  
SELECT SWITCH(F1 = 1, 1,
              F1 = 3, 3,
              F1 = 5, 5) FROM T1;

関数の中に NULL を書かず、条件に漏れた場合(2 と 4) NULL を返す。
  
バージョン 2401

回答
投稿日時: 24/02/08 16:46:40
投稿者: Suzu

SELECT CHOOSE(F1, "1", NULL, 3, NULL, 5) FROM T1;
 
ではどうでしょう。

投稿日時: 24/02/08 23:19:15
投稿者: たらのり

Suzu さん,
お世話になります。
Suzu さんの投稿はいつも有意義に拝見しています。
  
ご指摘いただいた方法で結果が抽出されました。
関数に中に NULL を記述できないということはないのですね。
しかしコレ,Suzu さんには既知の現象だったのでしょうか……
  
次のような実験をしてみると:

SELECT CHOOSE(F1, 1, NULL, 3, NULL, 5)
FROM (
    SELECT 1 AS F1 FROM DUAL
    UNION
    SELECT 2 AS F1 FROM DUAL
    UNION
    SELECT 3 AS F1 FROM DUAL
    UNION
    SELECT 4 AS F1 FROM DUAL
    UNION
    SELECT 5 AS F1 FROM DUAL
);

次の結果が得られました:
+----------+
| Expr1000 |
+----------+
|      &H1 |
|     NULL |
|      &H3 |
|     NULL |
|      &H5 |
+----------+

 
結果セットの 1行めは実際には '・' のような文字で表示されますが、
文字コードが確認できるテキストエディタに貼り付けると
(バイナリの) 1 (&H1) となっています。
2行めは期待通りに NULL になっているようです(見た目は空です)。
  
この値(&H1)を文字に変換して表示してほしいのですが、
「この列は TEXT型なので,値はそのまま(文字として)表示しよう」
と判定しているかのようですね。
というか,ナマのまま表示しているのですかね……
  
候補の値は整数と NULL なので,結果の列は整数型であると類推して
くれるとよいのですけど。。。
  
  
※ DUAL とありますが,オラクルなどで実行したものではなく
   次のテーブルの存在を前提としています
 
DUAL
+-------+
| DUMMY |
+-------+
|  'X'  |
+-------+

回答
投稿日時: 24/02/09 09:19:40
投稿者: Suzu

関数の中身等、詳しい 内容については判りかねます。
 
CHOOSE(F1, 1, NULL, 3, NULL, 5)
 
の結果について
 
言いたい事は、
 NULL の部分で 表示がおかしくなっているのではなく
 数値 1 の 場合、1 を返しているハズの部分でおかしくなっている。
 
 「1」と表示したいだけなら、数値として 返すのではなく、文字として返す様に
 
CHOOSE(F1, "1", NULL, 3, NULL, 5)
CHOOSE(F1, 1, NULL, "3", NULL, 5)
 :
の様に、どこか一つでも文字列を返す設定にすれば、 1,3,5 全てが 文字として返されます。
そうすれば、少なくとも 文字化けの様な状態にはならない
 
と、回避策を提示したに過ぎません。
 
 
必要なら、そこから更に、文字列を 数値に変換する様にすれば良いです。
 
SELECT ID, IIF(ISNULL(F2), NULL, CLNG(F2)) AS F3
FROM (
 SELECT ID, CHOOSE(F1, "1", NULL, 3, NULL, 5) AS F2
  FROM (
    SELECT 1 AS F1 FROM DUAL
    UNION
     :
 
IIF の 分岐条件が、ISNULL で正しいのかは、ご自身で判断ください。

投稿日時: 24/02/09 12:06:01
投稿者: たらのり

Suzu さん、
コメントをありがとうございます。
 
VBAでクエリを開き、Fields(0).Type の値を確認すると、
それぞれ次のようでした:
 

(1) CHOOSE(F1, 1, NULL, 3, NULL, 5)     -- dbBinary

(2) CHOOSE(F1, '1', NULL, 3, NULL, 5)   -- dbText

(3) CHOOSE(F1, 1, 2, 3, 4, 5)           -- dbLong

 
僕が最初に当たったケースは (1) で、このとき列の値をナマ
(バイナリ)のまま出力しているように見えます。
(1) のときにも (3) のように解釈してくれるとよいのですが。
 
 
次のような(余計な)実験をすると結果は期待通りだったので、
列のデータ型は関数によってことなるとしか……
 
SELECT IIF(F1, 1, NULL), IIF(F1, NULL, 2) FROM (
    SELECT TRUE  AS F1 FROM DUAL
    UNION
    SELECT FALSE AS F1 FROM DUAL
)

Expr1000 Expr1001
       1     NULL
    NULL        2

 
何ともいえないですね、、、
 
 

回答
投稿日時: 24/02/09 16:02:06
投稿者: Suzu

引用:
列のデータ型は関数によってことなるとしか……

 
関数 かつ、関数の戻り値 により 異なる と言うことでしょう。
関数は変わっていないですからね。
 
その辺りは、柔軟(?)に対応する Office製品の良いところでもあり、悪いところ でしょう。
文字列型 の 数値 が 値となっている フィールドに *1 をすれば、数値として計算する事が出来ますよね。
他のRDBMSであれば、きちんと型変換関数を間に含めないと 型エラーで計算できませんから。
 
 
引用:
何ともいえないですね、、、

 
内部処理については ユーザー側では 推測する事しかできませんし、推測したとて、推測に過ぎません。
中身はMSしか判らないでしょう。
 
こんな事があるから、改善して下さいと言うことは出来るでしょうが
改善されるとも限りません。
 
現象に対し、どうしたら 希望通りの結果を得られるかをテストし対策を採るのが現実的でしょう。

投稿日時: 24/02/10 00:50:38
投稿者: たらのり

Suzu さん,
引き続きコメントをいただき感謝です。
 
正式に文書化されていない使い方は,経験や実験結果に基づいて
用いることは少し危険かもしれませんね。
いつその振る舞いが変更されてしまっても文句が言えないので……
 
トリッキーな使い方はなるべく避けたく,今回のようなケースでは
可読性を優先して,愚直に IIF関数をネストするなどして対応する
のかなと(SQL中にコメントが書ければ,少しだけ自由に表現(記述)が
できそうですが。説明で可読性が補えるという意味で)。
 
関数も IIFは引数の数が固定されていますが,CHOOSEや SWITCHは
可変の個数をとることの違いもありそうです。
 
/* 以下は妄想です */
 
IIF関数は評価済みの(式の)値を 2つ取り,もしかしたら IIF関数は
それらの値に何かしらの計らいをして出力しているかもしれません。
 
CHOOSE関数や SWITCH関数の出力は評価結果(ナマモノ)そのもので,
良きに計らう何かが一枚噛んでいないというか……
(わかりにくいですよね)
 
# もはや給湯室ネタですがww
 
 

回答
投稿日時: 24/02/10 01:48:23
投稿者: hatena
投稿者のウェブサイトに移動

引用:
正式に文書化されていない使い方は,経験や実験結果に基づいて
用いることは少し危険かもしれませんね。
いつその振る舞いが変更されてしまっても文句が言えないので……

 
純粋にデータベース的な方法でやれば安全では。
自分ならこの方法を採用します。
 
下記のようなテーブルを作成します。
 
テーブル名 T_Switch
 
Var	Res
1	1
2	
3	3
4	
5	5

 
クエリのSQL
SELECT T_Switch.Res
FROM T1 LEFT JOIN T_Switch
ON T1.F1 = T_Switch.Var;

投稿日時: 24/02/12 01:38:41
投稿者: たらのり

hatena さん,
コメントをありがとうございます。
 
本来は奇偶を分けることでなくコード変換が目的なので,
ご指摘のように変換用のテーブルを用いればよいですね。
 
単純な組み合わせだったので,インラインで書きたくなりまして。
 
 
しかし,
 

(a) CHOOSE(F1, 1, 2, 3, 4, 5)           -- dbLong
はい
 
(b) CHOOSE(F1, '1', NULL, 3, NULL, 5)   -- dbText
わかる
 
(c) CHOOSE(F1, 1, NULL, 3, NULL, 5)     -- dbBinary
んんんっ!? … ここは整数型では……
 
 
投稿するときにはいつもおかしなことばかりでごめんなさい。
 
Suzu さん,
hatena さん,
ありがとうございました。