SOQL 入門

Salesforce では、保存したレコードの読み込みに使用できる Salesforce Object Query Language (SOQL) を提供しています。SOQL は、標準の SQL 言語と似ていますが、Lightning Platform 用にカスタマイズされています。また、Apex に埋め込まれた SOQL は、インライン SOQL と呼ばれます。この記事では基本的な所から詳しく説明します。

## 1.実践で構文を学ぶ
soqlの基本的な構文は他SQLとそんなに変わりません、基本的な SOQL クエリの構文を次に示します。
```
SELECT fields FROM ObjectName [WHERE Condition]
```
SELECT句、FROM句 WHERE 句で構築されWHERE 句は省略可能です。SELECT句で欲しいレコードを指定し検索するテーブルをFROM句で指定レコード詳しい条件加える場合はWHERE 句、まず簡単なクエリから始めましょう。
### 1-1.基本的な構文を実践しよう
まず、salesforce組織にログインしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/56b5e2be-cf13-ac0c-0b2b-d03cf1446f50.png)
次はコンソルを開きましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/df76394e-db09-a92d-d4ec-b68cccdcca56.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/54169db1-bcb5-41ed-36b8-b8dcc9afb669.png)
SOQL文を実行してみよう。
```
SELECT Name, Company, Email, Status FROM Lead
```
実行結果を確認することができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/ba0ce32f-5304-fcbd-7b1c-aef107b89cfb.png)
オブジェクトマネージャーからLeadを確認しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/9f952620-2438-5441-78c4-5eebc76ac617.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/2f9abbb2-f2c7-4afd-2478-0c618d3936c3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/76a4ed0d-01ab-d4d4-9774-99dedb946253.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/09d9460e-4534-c541-e87b-bd1a3220acb9.png)
項目とリレーションを選択して項目名を参照して指定するレコード名を知ることができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/1478539a-40a7-01e2-4920-a65347e34dd2.png)

### 1-2.WHERE 句とOR句やAND句を実践してみよう。
検索するレコードに条件追加する場合はWHERE 句を使う、二つ以上の条件追加はどっちかを満たせば十分の場合はORを使う。必ずどっちも満たす場合はANDを使う。
まず、WHERE 句を確かめましょう。
```
SELECT Name, Status, Company, Email FROM Lead WHERE Status='Closed - Converted' 
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/88aafdd5-def6-151a-ee80-688cdc6f991c.png)
次にOR条件を使ってみよう。
```
SELECT Name, Status, Company, Email FROM Lead WHERE Status='Closed - Converted' OR Status='Closed - Not Converted'
```
これで項目名StatusがClosed - ConvertedとClosed - Not Convertedのレコードが両方選び出された
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/9d98936a-4e61-ae0e-a2dc-6a393553b4b9.png)
最後はAND条件を追加してみましょう。
```
SELECT Name, Status, LeadSource, Company, Email FROM Lead WHERE (Status='Closed - Converted' OR Status='Closed - Not Converted') AND LeadSource='Web'
```
これで項目名StatusがClosed - ConvertedとClosed - Not Convertedのレコード且つ項目名LeadSourceがWebのレコードのみが選択された
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/12ac109e-7a0d-5a26-a46d-dbf301ce6b7e.png)

### 1-3.IN句とLIKE句追加
レコードの複数条件指定はINを使う、レコードのキーワード指定はLIKEを使う。
OR条件を外してINを指定しましょう。
```
SELECT Name, Status, LeadSource, Company, Email FROM Lead WHERE Status IN ('Closed - Converted', 'Closed - Not Converted') AND LeadSource='Web'
```
OR指定した条件と同じ役割を果たしました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/d8fff88d-c772-4603-7feb-8223193861c6.png)
条件を外してLIKEを指定しましょう。前方一致の場合は'keyword%',後方一致の場合は'%keyword',完全一致の場合は'%keyword%'.
```
SELECT Name, Status, LeadSource, Company, Email FROM Lead WHERE Status LIKE 'Closed%' AND LeadSource='Web'
```
Status項目名がClosedで始まる、LeadSource項目名がWebのものが選択されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/d4a5bf29-743a-48fb-195e-407d951e6b8e.png)

### 1-4.「ORDER BY」句を使うソート
ORDER BYはソートを行ってくれる機能、その基本的な使い方を実践しましょう。まず、Nameレコード昇順でソートしてみる。
```
SELECT Name, Status, LeadSource, Company, Email FROM Lead ORDER BY Name
```
AーZの順番でNameで表示しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/0d1720ee-c203-d878-a8c4-9704c7242f36.png)
次はNameレコード降順で並べてみる、命令最後にDESCを追加する
```
SELECT Name, Status, LeadSource, Company, Email FROM Lead ORDER BY Name DESC
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/813ac241-c09d-1455-e855-15ffda0350c0.png)

### 1-5.LIMIT句とOFFSET句
LIMIT 句を使用することで取得するデータの数を指定することができます。OFFSET 句を使用するとどの位置からデータを取得するのかを指定することができる。

取得数をLIMIT 句で制限してみよう。
```
SELECT Name, Status, LeadSource, Company, Email, CreatedDate FROM Lead LIMIT 10
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/1725b381-98a8-22ff-5513-a5941b86fc8e.png)
普通にデータを取得する場合とOFFSETで取得開始制限を加えた場合と比べてみよう。
```
SELECT Name, Status, LeadSource, Company, Email, CreatedDate FROM Lead
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/907b2546-400a-dff1-c6dd-69709b790782.png)

```
SELECT Name, Status, LeadSource, Company, Email, CreatedDate FROM Lead OFFSET 5
```
5番目のデータから取得開始するようになった
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/a09bf580-1898-f4d2-21e1-3bfad1abe19e.png)

## 2.主従関係/参照関係にある子から親/親から子を参照SOQL
soqlは他のsql言語と違い内部結合及び外部結合などクエリはありません。お互い参照する場合は必ずしも親子関係が必要である。ここでは子から親/親から子を参照の両方クエリを紹介します。

### 2-1.親オブジェクトと子オブジェクトの確認
まず、組織にログインしてアプリケーションランチャーを開きましょう。次はセールスを開きましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/eb2ab201-674f-9d08-3b53-9abdfd624d75.png)
取引先を選択しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/ee5e86b1-f6cd-283e-98c9-ee781d50068c.png)
適当項目を開きましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/1249d6fc-bd7d-d0d6-cec2-319e256f5944.png)
関連ページで書いてあるオブジェクトが取引先の子リレーションのオブジェクトである
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/8655fa8e-8e47-ac51-2ec2-45e71b85eca0.png)
設定を開きましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/dd890d64-3ffb-7c5b-95ef-ffa127d29a9e.png)
オブジェクトマネージャーを開きましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/a98c52fa-849a-9499-760b-ebfa748599e5.png)
取引をクイック検索で入力し、親オブジェクトである取引先と子オブジェクトである取引先責任者のAPI参照名を確認しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/a07d67cb-7396-ab93-429a-48656611cbaa.png)

### 2-2.親から子を参照するクエリ
開発者コンソルを開いて以下クエリを実行してみよう。
```
SELECT Name, Phone, Website, (SELECT Name, Department, Email FROM Contacts) FROM Account
```
このように子リレーションオブジェクトのレコードのクエリを挟むことで親から子を参照することができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/f2408831-7970-6cbe-c7d9-2086f13e7a6e.png)

### 2-3.子から親を参照するクエリ
開発者コンソルを開いて以下クエリを実行してみよう。
```
SELECT Name, Phone, Department, Account.Name, Account.Website FROM Contact
```
このように親オブジェクト名で呼び出しすることができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/aeab6da0-be04-4dfa-e022-d19b67119f73.png)


## 3.Apex 変数の使用のSOQLクエリ
SOQLは直接Query Editorで直接実行する以外にApexで応用することも非常に多い、このセクションでApexコードでの基本的な使い方を紹介します。

### 3-1.list型とmap型のsoql応用
まず、開発者コンソルを開いてDebugメニューのOpen Execute Anoymous Windowを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/e1d2c53c-7cee-90a0-1f3d-bf6b67ee5c77.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/7a1b04e3-e4fe-838d-e173-cb676a681bc3.png)
次はlist型の配列にSOQLを代入しましょう。
```
List<Account> accounts = [SELECT Name, Phone FROM Account];


for(Account account : accounts){
    System.debug('Account Name: '+account.Name+' Account Phone: '+account.Phone);
}

```
実行結果を確認しましょう。検索条件にふさわしいレコードを全て取り出した
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/8e29cd52-91d1-de7f-c7b7-bd4b46269bc4.png)
Map型はidをkeyとして、Accountをmapとすればlist型の配列と同じ結果を出せる
```
Map<Id, Account> accountsMap = new Map<Id, Account>([SELECT Name, Phone FROM Account]);
for(Account account : accountsMap.values()){
    System.debug('Account Name: '+account.Name+' Account Phone: '+account.Phone);
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/9ac0b8ae-e58c-49af-eeff-89aba1f90317.png)

### 3-2.親から子参照するクエリをApexに応用
親から子を参照するSOQLをListに代入する。循環内に循環を挟む方法で子リレーションに必要なレコードを取り出す
```
List<Contact> contacts = [SELECT Account.Name, Account.Rating, Name, Department, Title, (Select CaseNumber, Subject FROM Cases) FROM Contact ORDER BY Name];

for(Contact con : contacts){
    System.debug('Contact Name: '+con.Name+', Contact Department: '+con.Department+', Contact Title: '+con.Title+', Account Name: '+con.Account.Name+', Account Rating: '+con.Account.Rating);
    // iterate over the child records (Cases)
    for(Case caseObj : con.Cases){
        System.debug('Case Number: '+caseObj.CaseNumber+', Case Subject:'+caseObj.Subject);
    }
}

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/974946d2-f649-b519-609a-431257c85c7d.png)
### 3-3.配列を利用する複数条件検索
検索したいキーワードを含む配列accountNames を作成しましょう。INクエリを使いaccountNamesを条件として指定する検索クエリを代入するリストaccounts を作成しましょう。
```
List<String> accountNames = new List<String>();
accountNames.add('Sample SObject Account');
accountNames.add('New Line Cinema');
accountNames.add('SFDCFacts');
accountNames.add('Burlington Textiles Corp of America');

List<Account> accounts = [SELECT Id, Name, Phone, Rating FROM Account
                         	WHERE Name IN :accountNames];
System.debug('Accounts: '+accounts);
System.debug('Accounts Size: '+accounts.size());

```
実行結果を確かめましょう。オブジェクトに存在するアカウント名のキーワードのみ検索された。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705822/4140c5c7-f7ac-25d6-e8d6-da44d2401308.png)


## まとめ

以上がSOQLの基本的な構文と応用でした、今後はもっと研究してより複雑な応用を紹介します。