質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • Apex

    16questions

    Apexは、Salesforce上で動作するアプリケーション作成をサポートするアプリケーション開発プラットフォーム。プログラミング言語であるApexコードと、独自のApex WebサービスAPIなどで構成されています。

データ取得ロジック周りを簡潔に書く方法

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 611

tera1

score 69

変更履歴テーブルからデータを取得して表示するプログラムを書き、動作上は正常動作していますが、
より簡潔に書く方法があればご指導いただければ幸いです。

言語はsalesforceのapexというものになりますが、書き方はjavaと似ています。

早速ですが、データ構造から説明させていただきます。

変更履歴テーブルに以下のようなデータが入っている状態です。

作成日時 項目名 新しい値 実行者
2017-03-31T02:35:41.000Z contact_id 003N0000010thphIAA 横浜 太郎
2017-03-31T02:35:41.000Z download_datetime 2017-03-31T02:35:41.000Z 横浜 太郎
2017-03-31T02:35:41.000Z contact_id 横浜 太郎 横浜 太郎
2017-03-31T02:36:41.000Z download_datetime 003N0000010rrpHIAQ 新宿 太郎
2017-03-31T02:36:41.000Z download_datetime 2017-03-31T02:36:41.000Z 新宿 太郎
2017-03-31T02:36:41.000Z contact_id 新宿 太郎 新宿 太郎
2017-03-31T03:02:11.000Z download_datetime 2017-03-31T03:02:11.000Z 新宿 太郎

上記データを、プログラム通して、最終アウトプットしたものは以下です。

ダウンロード日時 ダウンロード実行者
2017/03/31 11:35 横浜太郎
2017/03/31 11:36 新宿太郎
2017/03/31 12:02 新宿太郎

変更履歴テーブルのデータは、以下の操作をしたときのデータになります。

1.横浜太郎というユーザがダウンロードを実行。
→上記の表のデータ1行目〜データ3行目が記憶されます。

2.新宿太郎というユーザがダウンロード実行
→上記の表のデータ4行目〜データ6行目が記憶されます。

3.新宿太郎というユーザが再度ダウンロード実行
→上記の表のデータ7行目が記憶されます。
(※contact_idが前回と同じ新宿太郎のため、8行目がつくられません)

また、データがたまる仕様、およびデータの抽出で、以下の制約があります。

  1. 項目名列のcontact_idにおいて、1行目と3行目や4行目と6行目のように
    IDと名称が残るものの、IDは最終的なアウトプットには必要ないので、プログラム上で除外しています。

  2. 項目名列のcontact_idにおいて、前回と同じであれば、レコードは作られません。

  3. 新しい値列はsql(soql)のwhere条件指定できません。

プログラムは以下です。

        // 処理実行プログラムです
       public List<History> histories {get; set;} // ゲッターセッターの機能を持ちます Historyクラスはデータ保持クラスで構造は画面下に記載しました。
        histories = new List<History>(); // アウトプットデータの初期化
        History h = new History(); // soqlで取得したデータ(縦持ち)を、横持ちに変換と保持するクラス
        String prevData2; // ダウンロード実行者が新旧で変化が無い場合はレコードが作成されないので旧のダウンロード実行者を保持して新にアサイン
        Boolean notAdd = false; // NewValueがIdの場合は無視する=>true
        Integer i = 0;
        for (a_history hist: [
                SELECT
                        Field,
                        NewValue
                FROM
                        a_history
                WHERE
                        Field in ('download_datetime', 'contact_id')
                ORDER BY
                        CreatedDate, Field, NewValue desc
        ]) {
            i++;

            // 奇数のタイミングでhistoriesに追加とhistoryを生成
            if (i >= 3 && math.mod(i, 2) == 1) {
                if (notAdd) {
                    notAdd = false;
                } else {
                    this.histories.add(h);
                    h = new History('', h.data2);
                }
            }

            if ('download_datetime'.equals(hist.Field)) { 
                // 個人的に、特に以下の偶数・奇数判定が気持ち悪いです。必要でこうしたのですが、すでに説明できない。
                if (math.mod(i, 2) == 1) {
                    h.data1 = Datetime.valueOf(hist.NewValue).format('yyyy/MM/dd HH:mm', 'JST');
                } else {
                    this.histories.add(h);
                    h = new History(
                            Datetime.valueOf(hist.NewValue).format('yyyy/MM/dd HH:mm', 'JST'),
                            h.data2
                    );
                    i++;
                }
            }

            if ('contact_id'.equals(hist.Field)) {
                // contact_idを変更すると、Idと名称それぞれのレコードができている
                // Idの場合は無視する(SOQLでNewValueで除外指定できない)
                if (String.valueOf(hist.NewValue).indexOf('003') != -1) {
                    i++;
                    notAdd = true;
                } else {
                    h.data2 = String.valueOf(hist.NewValue);
                }
            }
        }
        if (String.isNotBlank(h.data1)) {
            this.histories.add(h);
        }
    // データ保持クラスです
    public class History {
        public String data1 {get; set;}
        public String data2 {get; set;}
        public History() {
        }
        public History(String d1, String d2) {
            this.data1 = d1;
            this.data2 = d2;
        }
    }

何卒よろしくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

変更履歴テーブルの作成日時が1回のダウンロード実行で一致してれば、
SQLの結果が以下のようになるかと思うので、

作成日時 項目名 新しい値
2017-03-31T02:35:41.000Z contact_id 003N0000010thphIAA
2017-03-31T02:35:41.000Z contact_id 横浜 太郎
2017-03-31T02:35:41.000Z download_datetime 2017-03-31T02:35:41.000Z
2017-03-31T02:36:41.000Z contact_id 003N0000010rrpHIAQ
2017-03-31T02:36:41.000Z contact_id 新宿 太郎
2017-03-31T02:36:41.000Z download_datetime 2017-03-31T02:36:41.000Z
2017-03-31T03:02:11.000Z download_datetime 2017-03-31T03:02:11.000Z

上から順に処理していけば

  1. contact_idかつユーザ名だったらアウトプットを初期化して実行者を設定
  2. download_datetimeだったら日時を設定してリストに追加

for文の中だけ書くと

// ダウンロード実行者の設定・初期化
if ('contact_id'.equals(hist.Field) && String.valueOf(hist.NewValue).indexOf('003') != -1) { 
  h = new History('', hist.NewValue);
}

// ダウンロード日時を設定してリスト化
if ('download_datetime'.equals(hist.Field)) { 
  h.data1 = Datetime.valueOf(hist.NewValue).format('yyyy/MM/dd HH:mm', 'JST');
  histories.add(h);
}


みたいな感じで行けそうですがいかがでしょうか。
download_datetimeが複数回続くようだったらユーザ名は初期化されないので、問題ないかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/31 17:13

    ご回答ありがとうございます。

    > 作成日時が1回のダウンロード実行で一致
    はい、一致します。

    おそらく以下については、
    String.valueOf(hist.NewValue).indexOf('003') != -1
    以下の意図かと思いますが、
    String.valueOf(hist.NewValue).indexOf('003') == -1

    この場合、アウトプットが、2017/03/31 11:35の実行者の欄が
    空白になってしまいました。
    だいぶシンプルになりましたが・・・

    キャンセル

  • 2017/03/31 17:28 編集

    ご指摘通り

    > String.valueOf(hist.NewValue).indexOf('003') == -1

    ですね、コピペしてそのままでした、すいません。。

    SQLの実行結果が期待通りか確認できますか。
    SFDCということなので、別のソートが勝手にかかってそうで。。。

    以下みたいな感じの戻り値だと、アウトプットの1行目の実行者は空白になっちゃいますね。。。
    ※2行目と3行目が逆
    |作成日時|項目名|新しい値|
    |||
    |2017-03-31T02:35:41.000Z|contact_id|003N0000010thphIAA|
    |2017-03-31T02:35:41.000Z|download_datetime|2017-03-31T02:35:41.000Z|
    |2017-03-31T02:35:41.000Z|contact_id|横浜 太郎|
    |2017-03-31T02:36:41.000Z|contact_id|003N0000010rrpHIAQ|
    |2017-03-31T02:36:41.000Z|contact_id|新宿 太郎|
    |2017-03-31T02:36:41.000Z|download_datetime|2017-03-31T02:36:41.000Z|
    |2017-03-31T03:02:11.000Z|download_datetime|2017-03-31T03:02:11.000Z|

    キャンセル

  • 2017/03/31 18:01 編集

    早速のご回答ありがとうございます。

    すみません。Field列に書いた値に誤記がありました。
    contact_idですが、正しくは 「download_contact_id」 でした。
    申し訳ございません。

    また、sfdcのsoqlで不可解なことがあり、
    ORDER BY
    CreatedDate, Field, NewValue desc

    の指定であれば、Field列(項目名列)の並びはa→zになるはずなのに、
    以下のように降順になってしまう動作しております。

    2017-03-31T02:35:41.000Z download_datetime 2017-03-31T02:35:41.000Z 横浜 太郎
    2017-03-31T02:35:41.000Z download_contact_id 横浜 太郎 横浜 太郎
    2017-03-31T02:35:41.000Z download_contact_id 003N0000010thphIAA 横浜 太郎
    2017-03-31T02:36:41.000Z download_datetime 2017-03-31T02:36:41.000Z 新宿 太郎
    2017-03-31T02:36:41.000Z download_contact_id 新宿 太郎 新宿 太郎
    2017-03-31T02:36:41.000Z download_contact_id 003N0000010rrpHIAQ 新宿 太郎
    2017-03-31T03:02:11.000Z download_datetime 2017-03-31T03:02:11.000Z 新宿 太郎


    逆に、Field列にdescといれると、以下のようになります。

    ORDER BY
    CreatedDate, Field desc, NewValue desc 

    2017-03-31T02:35:41.000Z download_contact_id 横浜 太郎 横浜 太郎
    2017-03-31T02:35:41.000Z download_contact_id 003N0000010thphIAA 横浜 太郎
    2017-03-31T02:35:41.000Z download_datetime 2017-03-31T02:35:41.000Z 横浜 太郎
    2017-03-31T02:36:41.000Z download_contact_id 新宿 太郎 新宿 太郎
    2017-03-31T02:36:41.000Z download_contact_id 003N0000010rrpHIAQ 新宿 太郎
    2017-03-31T02:36:41.000Z download_datetime 2017-03-31T02:36:41.000Z 新宿 太郎
    2017-03-31T03:02:11.000Z download_datetime 2017-03-31T03:02:11.000Z 新宿 太郎


    現在、どのようにしたらよいか混乱しているのですが、
    soqlの取得結果が重要な点はわかっております・・・^^;

    キャンセル

  • 2017/04/01 12:53

    ありがとうございました。色々コード改変して解決しました^^;

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Apex

    16questions

    Apexは、Salesforce上で動作するアプリケーション作成をサポートするアプリケーション開発プラットフォーム。プログラミング言語であるApexコードと、独自のApex WebサービスAPIなどで構成されています。