SOQL関係のまとめ

[Answersで回答する時に使う情報のまとめ](https://qiita.com/Keiji_otsubo/items/9e6e0e946826133eddc7)
[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめN～Z](https://qiita.com/Keiji_otsubo/items/92f92bb9f668ca9688be)


+ [調べものをする時に便利なSOQLを集めてみる](https://qiita.com/Keiji_otsubo/items/242fad9ecfcb212ad40e)
+ [参照関係で結ばれている3つのオブジェクトからデータを抽出するSOQLについて](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007OX9ba)

:::note
SOQLの制約として親からは１つ下の子だけしか検索できません。子からは親の親というように最大５レベル上位を検索できます。ということはSOQLだけを考えると孫のオブジェクトからの検索になるとは思うのですが... ただTreeGridが要求するJsonにうまく変換できるかどうかですね。

As you now know, SOQL only allows us to query one level down a hierarchy. We can query up to 5 levels upwards (e.g. SELECT Id, Opportunity.Account.Owner.Manager.Profile.Name FROM OpportunityLineItem) and only one level down.

https://salesforce.stackexchange.com/questions/381625/apex-not-allowing-queries-of-3-levels-or-more-relationships
:::

# alesforce では、SOQL クエリでフィールド間の直接比較は許可されません。

+ [宣言型ルックアップ ロールアップ サマリーで SOQL が機能しない](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007cm9dL)

:::note
代わりに数式項目を作って対応する

SOQL WHERE 句でのフィールド間の比較
https://help.salesforce.com/s/articleView?id=000386076&type=1
:::


# SOQLでよく使うけど、書き方に悩む項目

```
CreatedBy.Name
CreatedDate <-- DateTime型
LastModifiedBy.Name
LastModifiedDate <-- DateTime型
Owner.Name
$User.Username
```

[日付のリテラル](https://developer.salesforce.com/docs/atlas.ja-jp.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_dateformats.htm)

# SOQLサブクエリーでも Where句は使えます

```
SELECT Name,
  (
    SELECT LastName
    FROM Contacts
    WHERE CreatedBy.Alias = 'x') 
 FROM Account WHERE Industry = 'media'
```

[Can I use a WHERE expression inside a relationship SOQL query?](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000FxUKHSA3)


```
SELECT Count(Id),AccountId FROM Asset WHERE Status = 'X' GROUP BY AccountId Having COUNT(Id) > 1  
```

**WhatId LIKE '500%'でinvalid operator on id fieldが発生**

+ [フローでケースに関する活動ログを抽出し削除する方法](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007KYvfw)

:::note
「オブジェクトおよび検索条件を選択」で条件を追加していたのですが、ケースに関連するという条件を外だしにしたところ問題なく動きました。
:::


# 文字列変数を使う　ポイントは :

```
String kyoten ='006';
List<KojiDaicyo2__c> KojiDaicyo2List = [select Id,Name,KaishiDate__c, from KojiDaicyo2__c where KaishiDate__c <= YESTERDAY AND Eigyousyo__c Like :kyoten + '%'  ];
system.debug(KojiDaicyo2List);     
```

このパターンでは相対日付は使えないと思っていましたが、大丈夫でした。ただの文字列として認識されている感じです。
```
String mySOQL2 = mySOQL + ' KaishiDate__c <= YESTERDAY AND Eigyousyo__c Like \'006%\' order by Tantousya__r.Name';
List<KojiDaicyo2__c> KojiDaicyo2List = Database.query(mySOQL2);
```

+ [SOQLでSELECTする際、文字列結合は可能か。](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007F52pw)

:::note
残念ながらSQLみたいにConcatなどは使えないですね。
制約が多いです。
数式フィールドを作って対応することが提案されています。

https://developer.salesforce.com/forums/?id=906F00000008xWKIAY

Apexでコードを書くのでfor文の中で連結して、その結果を出す方法も件数があんまり多くなければ可能かもしれません。
:::

+ [カスタムオブジェクトまたはカスタムメタデータタイプ内の長いテキスト項目に保存されているデータにアクセスする必要がある Apex クラスを作成しています。私の SOQL クエリは、完全な 2000 文字ではなく、長いテキスト項目の最大 255 文字のみを返します。](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000CgwiD)

:::note
最新情報として、カスタム メタデータ タイプ (長いテキスト) 項目に対する SOQL クエリが完全な 2000 文字を返すことが先週わかりました。値に Java リテラルが含まれていたため、デバッグ ステートメントには最大 255 文字しか表示されませんでした。

String クラスの unescapeJava() を使用して、表示する完全な Long Field 値を取得しました。
:::

# 良く忘れること

Apex Stringクラス mid

mid(startIndex, length)
 指定した開始値 0 の startIndex の文字で始まる、length によって指定された文字数の新しい string を返します。

よく忘れる0から始まる。


+ [Understanding Relationship Names](https://developer.salesforce.com/docs/atlas.en-us.242.0.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships_understanding.htm)


# 'The inner and outer selects should not be on the same object type'

+ [Report to Subquery from the sameobject](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000JeXAh)
+ [Why can't inner and outer selects be on the same object? ](https://salesforce.stackexchange.com/questions/61514/why-cant-inner-and-outer-selects-be-on-the-same-object)

メイン クエリと同じオブジェクトをサブクエリでクエリすることはできません。このような自己セミ結合クエリは、セミ結合またはアンチ結合を使用せずに記述できます。たとえば、次のセルフ セミジョイン クエリは無効です。

```
SELECT Id, Name
FROM Account
WHERE Id In (
   SELECT ParentId
   FROM Account
   WHERE Name = 'myaccount'
)
```

ただし、クエリを有効な形式に書き換えるのは非常に簡単です。次に例を示します。

```
SELECT Id, Name
FROM Account
WHERE Parent.Name = 'myaccount'
```

したがって、次のように子レコードからすべての親商談Id を選択します。

```
SELECT Parent_Opportunity__c , Id, Name, StageName FROM Opportunity WHERE StageName = 'Pre-Renewal and Type = 'Renewal' instead.
```



# 参考資料

[日付形式と日付リテラル](https://developer.salesforce.com/docs/atlas.ja-jp.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_dateformats.htm)

+ [In an Aggregate query is Date.Today() different from TODAY?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000PeLg4SAF)

Both the Queries are different.

TODAY | Starts at 12:00:00 AM on the current day and continues for 24 hours. 
https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_dateformats.htm

Date.today() returns current date time.

# Owner.Name が UserAccountTeamMember　では使えない？

+ [How to get Owner Name from UserAccountTeamMember object.](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007JCz7o)

:::note
Does not work for UserAccountTeamMember

```
SELECT Id, Owner.Name FROM UserAccountTeamMember 
```

This works

```
SELECT Id, Owner.Name FROM Account
```


Try this

```
List<UserAccountTeamMember> urmList =[ SELECT Id,OwnerId FROM UserAccountTeamMember];
Set<Id> IdSet = new ();
for (UserAccountTeamMember u :  urmList){

   IdSet.add(u.OwnerId);

}

List<User> userList = [SELECT Id,Name from User WHERE Id =: IdSet ];
```

:::

# 型変換　Cast　は使えない

+ [データ型が数値でLIKE検索が使えないため、文字列に型を変換しようとしましたが、エラーになりデプロイできません。](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007LqsVR)

:::note
Castは使えないようですが、文字列型の数式項目を作ってWhere句で使うことで回避しています。

https://intellipaat.com/community/4893/soql-type-conversion-salesforce-com
:::

+ [LWCで作成したdatatableに連番を追加したが、処理が遅い](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007LqsfCSAR)

:::note
SOQLのコードを見るとこのApexクラスのDML操作の結果が遅いのではないかと思います。
Likeを使っていますが、両端が%なので、おそらく結果的に全レコードを検索していますね。

前株、後株などを考慮してのことだとは思いますが...
改善できるかは分からないですが、（株）(有)などを取り除いた項目を作って、前方一致で検索するなどをすれば少しは早くなるかもしれません。

 You may find that the query in question needs to be more selective in the WHERE clause. I.e. as per Salesforce standards & best practices - the where clause needs to subset 10% or less of the data.
https://developer.salesforce.com/forums/?id=906F0000000DBEnIAO
:::

# ごみ箱(recycle bin)のレコードの検索

+ [How to View the record Id of deleted records in recycle bin](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000Kh37p)

:::note
Please check this article. 


https://salesforce.stackexchange.com/questions/83475/isdeleted-true-is-not-working-in-soql-query
:::