プログラマ38の日記

主にプログラムメモです。

【Salesforce】メタデータエクスポートツールのバージョンを上げました(APIVer41)

Salesforceのバージョンアップに伴い、コマンドラインで動作するメタデータのエクスポートツールのバージョンを上げました。

 

ダウンロードはこちらです。

 

今回のバージョンアップでは、メタデータで目立って追加されているものはないように思います。(TopicsForObjectsが追加されていたり、Workflowでは、何も指定していないオブジェクトはダウンロードしないようになっていたりしています。)

後、メタデータでは取得できないですが、Sobjectは増えています。

 

以前のバージョンは次になります。

 [APIVer40]

crmprogrammer38.hatenablog.com

 

 [APIVer39]

crmprogrammer38.hatenablog.com

 

最後に

以前、CustomFeedFilterでエラーになることが判明してエクスポートツールではワイルドカードで取得するようにしているのですが、今回のバージョンアップでは解消されていませんでした。

crmprogrammer38.hatenablog.com

 

 以前、承認プロセスのメタデータの一覧を取得すると物理名ではなく論理名が帰ってくる不具合があったのですが、しばらくはそのままだったなーとちょっと思い出しました。

 

【Salesforce/Excel】直接オブジェクト一覧と項目一覧を取得するExcelマクロのバージョンをあげました(APIver41)

Salesforceのバージョンアップに伴い、オブジェクト一覧と項目一覧(子リレーション一覧も含む)のバージョンを上げました。

 

ダウンロードはこちらからです。

 

以前のバージョンはこちらです。

crmprogrammer38.hatenablog.com

 

 

SOAPENVELOPEのXMLを直接操作しているので、プログラムの変更は不要でした。

出力している項目は次の通りです。

 

[オブジェクト一覧]  Salesforceヘルプからの引用です。

# 名前 説明
1 name オブジェクトの名前。
2 label 適用される場合は、ユーザインターフェースで名前が変更されたタブまたは項目のラベルテキスト。変更されていない場合はオブジェクト名。たとえば、医療分野の組織では「取引先」を Patient に変更する場合があります。タブや項目は Salesforce ユーザインターフェースで名前を変更できます。詳細は、Salesforce オンラインヘルプを参照してください。
3 keyPrefix オブジェクト ID の 3 文字のプレフィックスコード。オブジェクト ID はオブジェクト型を示す 3 文字のコードが先頭に付けられます。たとえば、Account オブジェクトのプレフィックスは 001、Opportunity オブジェクトのプレフィックスは 006 です。主要なプレフィックスを複数のオブジェクトで共有する場合があるため、必ずしもオブジェクトを一意に識別するわけではありません。
子に 1 つ以上の親オブジェクトが存在する場合 (多態的な場合)、親のオブジェクト種別を確認するためにこの項目の値を使用します。たとえば、Task または Event の親の keyPrefix 値を取得しなければならない場合にこの値を使用します。
4 labelPlural オブジェクト名の複数形を表すラベルテキストです。
5 layoutable オブジェクトが describeLayout() コールをサポートしているか (true)、否か (false) を示します。
6 mruEnabled 最後に使用 (MRU) リスト機能がオブジェクトで有効か (true)、否か (false) を示します。
7 triggerable オブジェクトが Apex トリガをサポートしているかどうかを示します。
8 activateable 将来の使用のために予約されています。
9 custom カスタムオブジェクトであるかどうかを示します (カスタムオブジェクトの場合は true、そうでない場合は false)。
10 customSetting カスタム設定項目であるか (true)、否か (false) を示します。
11 feedEnabled オブジェクトで Chatter 項目が有効か (true)、否か (false) を示します。このプロパティは、API バージョン 19.0 以降で使用できます。
12 mergeable オブジェクトが同じ型の他のオブジェクトとマージ可能か (true)、否か (false) を示します。リード、取引先責任者、取引先については true となります。
13 searchable オブジェクトが search() コールで検索可能か (true)、否か (false) を示します。
14 retrieveable オブジェクトが retrieve() コールで取得可能か (true)、否か (false) を示します。
15 replicateable オブジェクトを getUpdated() および getDeleted() コールで複製可能か (true)、否か (false) を示します。
16 queryable オブジェクトが query() コールでクエリ可能か (true)、否か (false) を示します。
17 createable オブジェクトが create() コールで作成可能か (true)、否か (false) を示します。
18 updateable オブジェクトが update() コールで更新可能か (true)、否か (false) を示します。
19 deletable オブジェクトが delete() コールで削除できるか (true)、否か (false) を示します。
20 undeletable オブジェクトが undelete() コールで復元可能か (true)、否か (false) を示します。

 

[項目一覧] Salesforceヘルプ(Fieldの箇所)からの引用です。

# 名前 説明
1 name create()、delete()、query() など、API コールで使用される項目名。
2 label Salesforce ユーザインターフェースの項目の隣に表示されるテキストラベル。このラベルはローカライズが可能です。
3 type 設定可能な値のリストは、「FieldType」を参照してください。
4 length 文字列項目において、Unicode 文字での最大サイズを指定 (バイトではないことに注意)。
5 byteLength 可変長項目 (バイナリ項目も含む) の最大サイズをバイトで指定。
6 precision 倍精度浮動小数点数型の項目で使用します。小数点の右側と左側の両方をあわせた (ただし小数点自体は含まない)、格納可能な最大桁数を示します。
7 scale 倍精度浮動小数点数型の項目で使用します。小数点の右側の最大桁数です。API は小数点の右側の余分な桁は通知することなく切り捨てます。ただし、小数点の左側の桁数が多すぎる場合は、エラーのレスポンスを返します。
8   選択リストのラベル名(カンマ区切り)
9 picklistValues 選択リストのAPI名(カンマ区切り)
10 defaultValue デフォルト値
11 defaultValueFormula 数式が使用されていない場合に、この値に指定されるデフォルト値。値が指定されていない場合、この項目は返されません。
12 referenceTo 他のオブジェクトを参照する項目において、この配列は参照されるオブジェクトのオブジェクト種別を示します。
13 relationshipName 主従関係の項目の場合、リレーションの名前。
14 referenceTargetField 外部オブジェクトの間接参照関係にのみ適用されます。値が子外部オブジェクトの間接参照関係項目の値と照合される、親標準またはカスタムオブジェクトのカスタム項目の名前。この照合は、相互に関連するレコードを判別するために行われます。この項目は、API バージョン 32.0 以降で使用できます。
15   親オブジェクトが削除されると一緒に削除される場合true。
16   親オブジェクトが削除されるとエラーにする場合、true。
17 relationshipOrder 主従関係の項目の場合、リレーションの種類。有効な値は、次のとおりです。
0: 項目が主リレーションの場合
1: 項目がセカンダリリレーションの場合
18 restrictedPicklist 項目が制限付き選択リストであるか (true)、否か (false) を示します。
19 controllerName この選択リストの値を制御する項目の名前。type が picklist または multipicklist であり、dependentPicklist が true の場合のみ適用されます。「連動選択リストについて」を参照してください。制御項目から連動項目への対応付けは、この選択リストの各 PicklistEntry の validFor 属性に格納されます。「validFor」 を参照してください。
20 dependentPicklist 選択リストが連動選択リストであるかどうかを示します (利用可能な値が制御項目で選択された値に従う場合は true、そうでない場合は false)。「連動選択リストについて」を参照してください。
21 calculatedFormula この項目に指定された数式。数式が指定されていない場合、この項目は返されません。
22 calculated 項目がカスタム数式項目であるか (true)、否か (false) を示します。カスタム数式項目は常に参照のみです。
23 autonumber この項目が自動採番項目であるか (true)、否か (false) を示します。SQL の IDENTITY 型に似て、自動採番項目は参照のみ可能で、作成できない項目であり、最長 30 文字です。自動採番項目は参照のみの項目であり、内部オブジェクト ID に依存しない一意な ID を提供します (購入注文番号や請求書番号など)。自動採番項目は、全体的に Salesforce ユーザインターフェースで構成されています。API はこの属性へのアクセスを提供しているため、クライアントアプリケーションは指定された項目が自動採番項目かどうかを確認できます。
24 nillable 項目を空白にできるか (true)、否か (false) を示します。null 値が許可される項目は、中身を空にすることができます。null 値が許可されないオブジェクトでは、オブジェクトを作成して保存するには必ず値を設定する必要があります。
25 unique この項目が一意である必要があるかどうかを示します (一意である必要がある場合は true、そうでない場合は false)。
26 externalId この項目が外部IDであるかどうかを示します (外部IDである必要がある場合は true、そうでない場合は false)。
27 caseSensitive この項目が大文字と小文字を区別するかどうかを示します (区別する場合は true、しない場合は false)。
28 inlineHelpText この項目の項目レベルのヘルプでフロート表示テキストとして表示されるテキストです。
このプロパティは、オブジェクトの 1 つ以上の項目に値が含まれていないと返されません。少なくとも 1 つの項目に項目レベルのヘルプが存在する場合、オブジェクトのすべての項目がプロパティを項目レベルのヘルプの値で表示します。項目レベルのヘルプが空の項目では null 値となります。
29 compoundFieldName 複数項目をまとめて1つの項目となる場合、その項目のAPI
30 deprecatedAndHidden 将来の使用のために予約されています。
31 digits 整数型の項目で使用。最大桁数。整数値がこの桁数を超えた場合、API はエラーを返します。
32 displayLocationInDecimal ヘルプに説明無し。
33 extraTypeInfo 項目が textarea データ型の場合、テキストエリアがプレーンテキストか (plaintextarea)、リッチテキストか (richtextarea) を示します。
項目が url データ型の場合、この値が imageurl ならば、URL は画像ファイルを参照します。標準オブジェクトの標準項目でのみ使用できます (Account.photoUrl、Contact.photoUrl など)。
項目が reference データ型の場合、外部オブジェクトリレーションの種別を示します。外部オブジェクトでのみ使用できます。
null — 参照関係
externallookup — 外部参照関係
indirectlookup — 間接参照関係
34 highScaleNumber 項目詳細の指定内容に関係なく、項目に小数点以下 8 桁までの数値が保存されるか (true)、否か (false) を示します。価格が数分の 1 セントの大量の製品の通貨を処理するために使用されます。組織で、高スケールの単価設定が有効ではない場合、この項目は返されません。API バージョン 33.0 以降で使用できます。
35 htmlFormatted ハイパーリンクのカスタム数式項目などの項目が HTML のために形式化されており、HTML として表示するためのエンコーディングが必要かどうかを示します (必要な場合は true、必要でない場合は false)。カスタム数式項目の項目に IMAGE テキスト関数があるかどうかも示します。
36 encrypted このページは、従来の暗号化ではなく Shield プラットフォームの暗号化について書かれています。この違いについては、こちらをクリックしてください。
この項目が暗号化されているかどうかを示します。この値は、describeSObjects() コールの結果が true の場合にのみ結果に表示され、それ以外の場合は結果から除外されます。この項目は API バージョン 31.0 以降で使用できます。
37 mask 将来の使用のために予約されています。
38 maskType 将来の使用のために予約されています。
39 nameField 項目が名前項目であるか (true)、否か (false) を示します。標準オブジェクトの名前項目 (Account オブジェクトの AccountName など) やカスタムオブジェクトの名前項目を識別するために使用します。Contact オブジェクトなど、FirstName および LastName 項目が使用されている場合を除き、1 オブジェクトにつき 1 つに制限されます。
個人取引先の Name 項目などのように複合名が存在する場合、そのレコードの nameField は true に設定されます。複合名が存在しない場合、FirstNameおよび LastName ではこの項目が true に設定されます。
40 namePointing 項目の値が、このオブジェクトの親の Name であるか (true)、否か (false) を示します。親のオブジェクト種別が 2 つ以上ある可能性のあるオブジェクトで使用します。たとえば、ToDo は取引先と取引先責任者が親であることが考えられます。
41 idLookup upsert() コールのレコードの指定に項目を使用できるかどうかを指定します (指定できる場合は true、できない場合は false)。
42 custom 項目がカスタム項目であるか (true)、否か (false) を示します。
43 permissionable 項目に FieldPermissions を指定可能か (true)、否か (false) を示します。
44 searchPrefilterable 外部キーが SOSL WHERE 句で使用されたときに外部キーを事前絞り込みに組み込むか (true) 組み込まないか (false) を示します。事前絞り込みでは、完全な検索クエリを実行する前に特定の項目値で絞り込みを行います。API バージョン 40.0 以降で使用できます。
45 soapType 設定可能な値のリストは、「SOAPType」を参照してください。
46 writeRequiresMasterRead この項目は主従関係にのみ適用されます。ユーザが、子レコードの挿入、更新および削除を行う場合に親レコードに対して必要なのは、参照の共有アクセス権限であるのか (true)、編集の共有アクセス権限であるのか (false) を示します。いずれの場合も、ユーザは子オブジェクトに対しても、作成、編集および削除のオブジェクト権限が必要です。
47 defaultedOnCreate 作成時にこの項目がデフォルト設定されているか (true)、否か (false) を示します。true の場合、この項目の値が create() コールで渡されなくても、Salesforce は、オブジェクト作成時にこの項目の値を暗黙的に割り当てます。たとえば、Opportunity オブジェクトで、値が Stage 項目から取得されている、Probability 項目にはこの属性が指定されています。同様に、ほとんどのオブジェクトの Owner にはこの属性が設定されています。Owner 項目が特に指定されない限り、値は現在のユーザから取得されます。
48 polymorphicForeignKey 外部キーに複数のエンティティ種別が含まれるか (true)、否か (false) を示します。
49 queryByDistance ヘルプに説明無し。
50 sortable クエリでこの項目に基づいて並び替えができるか (true)、できないか (false)) を示します。
51 aggregatable クエリでこの項目に基づいて集計ができるか (true)、できないか (false)) を示します。
52 filterable 項目を除外できるか (true)、否か (false) を示します。true の場合、この項目を query() コールのクエリ文字列の WHERE 句で指定できます。
53 groupable 項目を SOQL クエリの GROUP BY 句に含めることができるかどうかを示します (できる場合は true、できない場合は false)。『Salesforce SOQL および SOSL リファレンス』の「GROUP BY」を参照してください。API バージョン 18.0 以降で利用できます。
54 createable 項目を作成できるか (true)、否か (false) を示します。true の場合、この項目値を create() コールで設定できます。
55 updateable 次のいずれかを示します。
項目を更新できるか (true)、否か (false)。
true の場合、この項目値を update() コールで設定できます。
項目がカスタムオブジェクトの主従関係項目である場合は、子レコードの親を別の親レコードに変更できるか (true)、否か (false) を示します。

 

最後に

マクロで表示している項目の説明を書きました。基本は、ヘルプをそのまま引用しているのですが、ヘルプに記載がなかったりしているものは、自分で補足しています。何かのお役に立てればうれしいです。

後、VBAでSOAPEnvelopeを操作しているので、APIのバージョンがあがってもタグの名前や階層が変わっていなければそのまま動作するのは楽だなーと思いました。

【Java/その他】テキストファイルで、utf8からshift_jis(CP932)への変換時に注意すること

テキストファイルなどutf8だと扱いづらく、shift_jisに変換したい時があります。

欲しいコマンドがみつからない時に、自分で作成するときの注意事項です。

 

結論として、utf8からshift_jisへの変換で、プログラムで工夫することで文字化けを回避できる文字があります。

 

そもそも utf8からshift_jisの変換はshift_jisよりutf8の方が文字が多いため、文字化けは回避できません。ですが、次の文字は次のようにマッピングが可能で文字化けを回避できます。

 

shift_jisで文字化けする文字 shift_jisで文字化けしない文字
表示 文字コード 表示 文字コード
¢ ¢
£ £
¬ ¬

※OSのバージョンでは変換しなくても文字化けしない場合があります。

 

Java文字コード変換プログラムを作成する場合に、上の変換を考慮する前と後では次のようになります。

 

[文字の変換を考慮する前]

    String in = "読込むファイル名";
    String out= "書込むファイル名";
    
    String readEncoding = "utf8";
    String writeEncoding= "Windows-31J";
    

    BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(in),readEncoding));
    
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(out),writeEncoding));
    

    while(true){
      String line = br.readLine();
      
      if(line ==null){
        break;
      }

      bw.write(line);
      bw.newLine();

    }
    
    br.close();
    bw.close();

 [文字の変換を考慮した後]

    String in = "読込むファイル名";
    String out= "書込むファイル名";
    
    String readEncoding = "utf8";
    String writeEncoding= "Windows-31J";
    

    BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(in),readEncoding));
    
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(out),writeEncoding));
    
    
    //ShiftJIS用に変換するマップ
    HashMap<Character, Character> conversion = new HashMap<Character, Character>();

        conversion.put('−','-' );     
        conversion.put('〜','~' );     
        conversion.put('¢','¢' );     
        conversion.put('£','£' );     
        conversion.put('¬','¬' );     
        conversion.put('—','―' );     
        conversion.put('‖','∥' );     
    
    
    while(true){
      String line = br.readLine();
      
      if(line ==null){
        break;
      }

      //文字化けする文字の変換
      for(char src : conversion.keySet()){
        line = line.replace(src, conversion.get(src));
      }
      bw.write(line + " ");
    }
    
    br.close();
    bw.close();

上のように工夫することで、shift_jisでも文字化けせずに済みます。

特に「〜」は、DBからのデータ取得や、webでのデータ取得の中で、文字化けする方の文字コードとなっている時が多いなーと感じています。

【JDBC】接続URLではまること(SQLServer , MySQLでメモリエラーが発生する件)

Javaで、SQLServerMySQLのデータ連携プログラムを書くとき注意事項のメモです。(ある程度の件数がある時の場合です。)

 

結論としては jdbcのURLのパラメータをきちんと書かないと、「out of memory」のエラーになる可能性が高くなります。

 

「out of memory」エラーになる書き方

SQLServer
jdbc:sqlserver://[ホスト名]:[ポート番号];databaseName=[データベース名]

MySQL
jdbc:mysql://[ホスト名]:[ポート番号]/[データベース名]

 

「out of memory」エラーにならない書き方

SQLServer
jdbc:sqlserver://[ホスト名]:[ポート番号];databaseName=[データベース名];SELECTMETHOD=cursor

MySQL
jdbc:mysql://[ホスト名]:[ポート番号]/[データベース名]?useCursorFetch=true&defaultFetchSize=1000

 

SQLServerでは、selectmethod=cursor 、 MySQLではuseCursorFetch=trueでかつdefaultFetchSize=XXXを指定しないと取得結果がメモリに展開されてしまい、データがメモリの容量を超えるとエラーになります。

 

SQLServerは、selectmethod=cursorを設定しない場合、デフォルトでselectmethod=direct扱いとなり、一方的にDBから結果が送られてきます。DBからの結果を全てメモリに展開してから次の処理が動くわけではないのがまだましです。

ですが、MySQLでは、useCursorFetch=trueでかつdefaultFetchSize=XXXを指定しないと、全てメモリに展開してから次の処理が動きます。100万件程度を操作するとほぼメモリエラーになると思います。

 

最後に

JavaベースのETLツールもありますので、jdbc urlには充分注意が必要です。

jdbc urlでは、パラメータを指定しない場合は、遅いけどエラーにならない動きを選択して欲しいなと思いました。

 

MySQLである程度のデータを取得する場合、パラメータを指定しないとまずエラーというのはひどい設計だと思います。こういう部分ではoracleは安定してるなーと思います。

【Salesforce】データローダの起動についてのメモ(メモリ不足など)

Salesforceのデータをまとめて編集をする時に、データローダを使います。

環境的な制約でうまく動作しなかった時のメモになります。

※データローダのバージョンは40を前提としています。

 

環境的な問題

  1. Javaのインストールが許可されていない
  2. メモリ不足のエラー(heap size error)が出る

 

解決策

1. Javaのインストールが許可されていない

データローダは32bit、Java8以上のJavaがインストールされている前提となっています。そのため、Javaのインストールが許可されていない場合は「dataloader-40.0.0.exe」からは起動できません。

 

というのは「dataloader-40.0.0.exe」はlaunch4jで作成されていて、インストールされている32bit、Java8以上をレジストリから探すようになっているからです。例え、環境変数「Path」にjavaw.exeへのパスを通していても、「JAVA_HOME」の環境変数を設定していても起動ができないということになります。

 

そこで、まずJavaをインストールをしないで、モジュール一式をファイルとして配置します。(一旦インストールできる環境でインストールをしてからjavaファイル自体をコピーすることになります。)

f:id:crmprogrammer38:20171010091533p:plain

上のjavaモジュール一式をフォルダにつめて持って行きます。

 

次に、起動用のショートカットを作成します。

f:id:crmprogrammer38:20171010091836p:plain

上のデータローダの中身から、「dataloader-40.0.0-uber.jar」のショートカットを作成します。

作成したショートカットのプロパティから、リンク先を次のように修正します。

"~javaw.exe"  -Dappdata.dir="C:ProgramData"  -jar "~dataloader-40.0.0-uber.jar"

上の「~javaw.exe」 は、最初に配置したjavaモジュール一式の中のjavaw.exeへのフルパスになり、「~dataloader-40.0.0-uber.jar」は、ショートカットを作成した「dataloader-40.0.0-uber.jar」へのフルパスになります。

 

これで、Javaをインストールすることなくデータローダが使えます。

※さらにデータローダのインストールも許可されていない場合は、データローダのモジュール一式をファイルとして配置した後に、上記を行うことで起動することができます。

 

2. メモリ不足のエラー(heap size error)が出る

通常の「dataloader-40.0.0.exe」から起動したデータローダでメモリ不足のエラーがでる場合、データローダのフォルダ内になる「dataloader-40.0.0.l4j.ini」を修正することで対応します。

[変更前 dataloader-40.0.0.l4j.ini]
-Dappdata.dir="C:ProgramData"
-jar "D:programfilessf_dataloaderdataloader40dataloader-40.0.0-uber.jar"
[変更後 dataloader-40.0.0.l4j.ini]
-Xmx1G
-Dappdata.dir="C:ProgramData"
-jar "D:programfilessf_dataloaderdataloader40dataloader-40.0.0-uber.jar"

 上記のようにjavaコマンドのメモリサイズ指定を追加します。

 

「1. Javaのインストールが許可されていない」で、ショートカットから起動するようにした場合は、

[変更前 ショートカット]
"~javaw.exe"  -Dappdata.dir="C:ProgramData"  -jar "~dataloader-40.0.0-uber.jar"
[変更後 ショートカット]
"~javaw.exe" -Xmx1G -Dappdata.dir="C:ProgramData"  -jar "~dataloader-40.0.0-uber.jar"

 上記のようにjavaコマンドのメモリサイズ指定を追加します。

 

 

最後に

ロングテキストエリアの10万文字とか、大きい添付ファイルやコンテンツなどを扱うとメモリ不足のエラーが出る時があるので、メモリサイズの指定を行う機会はあると思います。

 

以前はデータローダはjavaが同梱されていたのですが、最近はjavaのインストールは別に行うようになっています。javaのサイズが大きくなったことも原因の1つなんじゃないかなーと勝手に考えています。

 

 

 

 

【Salesforce】データ連携時に気をつけること(Salesforce→他システム)

Salesforceから他システムへデータを渡したい時があります。

入力はsalesforceでPCとモバイルから行い、その後入力したデータを基幹システムや分析システムに連携することはよくあることだと思います。

 

その時に気をつけておくことのメモです。

  1. 大量データを連携する方法
  2. 日付/時間の形式
  3. 数値の形式

 1. 大量データを連携する方法

データの取得は基本的に、SalesforceAPI のqueryを使うことになります。

1度に、大量データを取得する時に気をつけることがあって、取得結果が大き過ぎるとクエリがタイムアウトする場合があります。

(微妙な件数だと一度目は失敗するけど、二度目は成功するなんてこともあります。Salesforceのキャッシュの制御次第だと思います)

そういった時には、一度に取得する件数を少なくするように条件をつけることで解決します。

例えば、直近1ヶ月に作成されたデータを連携する場合

Where CreatedDate = LAST_N_DAYS:30

の条件をつけることで取得できますが、これでタイムアウトする場合は、

Where CreatedDate = LAST_N_DAYS:30
  and CreatedDate < LAST_N_DAYS:29
  

Where CreatedDate = LAST_N_DAYS:29
  and CreatedDate < LAST_N_DAYS:28  

・・・・

Where CreatedDate = LAST_N_DAYS:2
  and CreatedDate < LAST_N_DAYS:1  

Where CreatedDate = LAST_N_DAYS:1

 

と取得結果を分割することで対処します。

 

このextractを処理を、データローダのコマンドラインモードで何度も実行することになります。

 

あまり問題にはなりませんが、通常のsfdc.usernameとsfdc.passwordで指定すると、extractを実行するたびログインを行います。そのためログイン回数が増えてしいまい、イベントログではデータ連携のログインばかりになってしまいますし、APIの消費もかさみます。

 

ログインを減らすには、データローダのパラメータでセッションIDとインスタンスURLを指定することで解決できます。(ログインは最初に1度行い、そこでインスタンスURLとセッションIDの取得しておく必要があります)

process-conf.xmlに次を指定します。

<entry key="sfdc.endpoint" value="インスタンスURL(例.https://ap2.salesforce.com)"/>
<entry key="sfdc.oauth.accesstoken" value="セッションID/>

sfdc.oauth.accesstokenを指定する場合、sfdc.usernameとsfdc.passwordは不要です。

これでデータローダ実行時に、ログイン処理はスキップされます。

2. 日付/時間の形式

APIで取得した時の日付/時間のフォーマットは選べず、日付/時間はGMTの出力となります。(yyyy-MM-dd'T'HH:mm:ss'.000Z')

この形式となるため、データローダで出力した日付/時間の値を、連携先で日本時間として取り込む場合、取り込む時に、日本時間へ変換してもらうことになります。

※ETLツールを使う場合や、CSVを変換するプログラムを作らない場合の話です。

3. 数値の形式

取得する値が大きいと指数形式となります。(1.E+10 のような値)

また、Salesforceで小数点以下が0の項目としていても、データとして小数点を持っている場合があります。(apexや、APIでセットうっかりセットしている時があります)

データローダで出力したcsvを、連携先で取り込む場合は、正しい数値へ変換してもらう必要があります。(連携先の取込ツールが対応しているか、文字として取り込んでから変換するかなどになります)

 

最後に

salesforceとの連携処理は、データローダを使うことにして簡単に済ます場合が多いと思いますが、上のようなことを考慮・定義しておく必要があります。

さすがに作成日を1日に限定しないとタイムアウトするほど件数がある環境はまれだと思いますが。。

CSVの変換処理は件数が多いと意外と大変なので、どちらで変換するかは決めて、変換する側はその処理を行う時間を見ておく必要があります。

【TERADATA】 TERADATAの後に、普通のDBに戻るのに時間がかかった思い出

しばらくTERADATAの開発を行った後に、通常のDB(業務用のSQL ServerOracle)に戻った時がありました。

 

TERADATAでは、極力まとめて処理を行うのがポイントで、1000万件くらいであれば処理は数秒で終わります。

※TERADATAにもキャパシティはあるので、そのTERADATAがどこまでまとめていけるかは把握しておく必要はあります。

 

CSVのロードや、テーブルからテーブルへのインサートなどストレスなく処理ができます。セカンダリインデックス(いわゆるB-Treeインデックスに近いもの)は、TERADATAでは効果が低くあまり使いません。

 

3,4年TERADATAの開発後、通常のRDBの開発に戻った時に処理の組み方を忘れていて大変でした。TERADATAだと500万件のマスタと5000万件のトランザクションくらいであれば普通に結合しますが、通常のRDBでは結合するとなかなか結果が返ってきません。(もしかすると永遠に返ってこないかも)

TERADATAでは、カーソルの制御はほぼ行わないのですが、通常のRDBではカーソルを回してRDBの処理内に収まるように設計することが必要です。(もちろん、処理の前に、主キー、結合キーはきちんとインデックスを作成し、統計をとっておく必要があります。)

 

通常のRDBで設計するときは、TERADATAで扱える件数の1/100くらいの件数が扱える件数としておきかえて設計するのがベストだと考えています。

TERADATAで1000万件くらいであれば、特に考慮はしないですが、TERADATAで10億件となると、さすがに慎重に設計するので、無理なSQLは実行しません。

これを踏まえると、通常のRDBではまとめて1万件処理するのは問題ないけど、100万件処理するときは慎重に設計しようとなります。(もしかすると、今時のサーバならもっと処理できるかもしれません。今書いてるのは、ちょうど5年ほど前の話になります。)

 

最後に

扱うアーキテクチャに合わせた設計というのはとても大切です。

TERADATAだったら楽勝なのになーと思う前に、用意されているものできちんと開発しないといけないんですよね。きちんと、PL/SQL や transact/SQL でカーソルを回して処理を行うのが必要です。 

 

まぁ、頭ではわかってるんです。生活水準を上げるとなかなか下げられないということを聞きますが、TERADATAならもっと楽なのになと考えてしまうのは、それに近いのかなと思いました。