Accueil > Conseils > Anatomie d’une requête SOQL

Anatomie d’une requête SOQL

 10 min read

AUTEUR
DATE

avril 21, 2022

CATEGORIES
HASHTAGS
PARTAGEZ !
ABONNEZ-VOUS :

La requête SOQL (Salesforce Object Query Language) est l’outil qui permet de lire dans la base de données dans Salesforce, que ce soit dans du code Apex ou pour exporter des données.

requête SOQL

Une requête SOQL est constituée de blocs (à la manière de propositions dans une phrase en français) qui commencent toujours par un mot-clé. Cet article présente ces mots-clés et les fonctionnalités qu’ils permettent. Par convention, les mots spécifiques aux requêtes seront écrits en majuscule, mais ce n’est pas obligatoire pour leur fonctionnement.

Nous allons voir différents exemples de requêtes, en expliquant à chaque fois les nouveaux mots-clés et en présentant leur fonctionnement.

 

Niveau 1 – Structure d’une requête basique

Voyons une première requête simple pour nous familiariser avec les bases d’une requête SOQL :

SELECT Id, Name
FROM Account
WHERE Name = 'Toto'
LIMIT 20

Ici, on peut déjà distinguer 4 blocs :

  • SELECT : permet de préciser la liste des champs que l’on souhaite récupérer, séparés par des virgules (dans ce cas, l’identifiant est le nom).
  • FROM : identifie le type d’objet que l’on veut récupérer (dans le cas présent, les comptes).
  • WHERE : rajoute un filtre sur la requête. Seuls les enregistrements qui répondent à cette condition seront retournés (ici, les comptes dont le nom est égal à ‘Toto’).
  • LIMIT : permet de limiter le nombre d’enregistrements qui seront retournés (ici, pas plus de 20).

Les deux mots-clés vraiment indispensables sont SELECT et FROM, les autres étant facultatifs.

 

Niveau 2 – Logique de filtres et ordre

La requête précédente présentait un filtre simple, mais il est possible d’utiliser plusieurs champs pour affiner la recherche :

SELECT Id, Account.Name
FROM Case
WHERE CreatedDate = LAST_QUARTER
      AND (NOT (ContactEmail != null OR ContactMobile != null))
ORDER BY LastModifiedDate DESC
LIMIT 10
OFFSET 10
  • LAST_QUARTER : C’est une expression littérale qui représente une période donnée relative à la date d’aujourd’hui. Dans cet exemple, seules les requêtes ayant été créées pendant le trimestre précédent seront récupérées.
  • AND / OR / NOT : permet de combiner plusieurs critères dans le filtre WHERE, à partir de la logique spécifiée (on utilise des parenthèses pour préciser l’ordre de priorité).
  • ORDER BY : permet d’ordonner les résultats selon un ou plusieurs champs définis. L’ordre peut être ascendant (ASC, valeur par défaut) ou descendant (DESC). Ici, les requêtes ayant été modifiées le plus récemment apparaîtront en premier.
  • OFFSET : permet d’ignorer un certain nombre de résultats retournés. Cela peut être utile en combinaison avec LIMIT dans le cadre d’un système de pagination, par exemple, pour ne récupérer que les résultats correspondant à une page en particulier.

 

Niveau 3 – Filtres avancés et corbeille

Pour terminer sur les filtres, il existe des fonctions plus avancées qui peuvent répondre à des besoins spécifiques :

SELECT Name
FROM Opportunity
WHERE StageName IN ('Prospecting', 'Qualification')
AND Name LIKE '_Force%'
AND Multipicklist__c INCLUDES ('Value1')
ALL ROWS
  • IN / NOT IN : permet de tester un champ parmi une liste de valeurs, et plus une seule comme avec l’opérateur ‘=‘.
  • LIKE : il s’agit d’une comparaison d’un texte avec un format particulier. Le symbole ‘_‘ correspond à n’importe quel caractère, et le symbole ‘%‘ à n’importe quelle chaîne de caractères (y compris vide).
  • INCLUDES / EXCLUDES : est un opérateur de comparaison utilisé pour les champs multi-picklists (listes déroulantes à choix multiples), et permet de vérifier qu’une valeur y est présente ou pas.
  • ALL ROWS : permet d’étendre la requête aux enregistrements placés dans la corbeille et aux activités archivées, qui ne sont pas pris en compte autrement.

 

Niveau 4 – Requêtes imbriquées, Scopes

Lorsque l’on fait une requête sur un objet, il est possible d’en récupérer également les enregistrements liés :

SELECT FIELDS(STANDARD),
       (SELECT Id, Name FROM Opportunities WHERE Amount >= 10)
FROM Account
USING SCOPE Mine
  • FIELDS : est une fonction qui permet de récupérer l’ensemble des champs STANDARD, CUSTOM ou tous les champs (FIELDS(ALL))
  • (SELECT * FROM *) : il s’agit d’une requête imbriquée qui va récupérer une liste d’enregistrements d’un objet enfant. Ici par exemple, chaque compte aura une colonne contenant la liste de ses opportunités liées.
  • USING SCOPE : permet de définir la visibilité des enregistrements récupérés. Cet exemple ne retournera que les comptes dont l’utilisateur est propriétaire. On peut également ne demander que les enregistrements appartenant à son équipe, par exemple.

requete SOQL 2

Niveau 5 – Groupements

Dans certains cas, il peut être intéressant de récupérer un groupe d’enregistrements. Ceci permet de faire différents calculs sur les lignes de ce groupe :

SELECT LeadSource,
       COUNT(Id),
       AVG(Amount),
       MAX(CloseDate)
FROM Opportunity
WITH SECURITY_ENFORCED
GROUP BY LeadSource
  • GROUP BY : groupe les résultats selon un champ donné. Une requête groupée renverra une liste d’objets de type AggregateResult qui contiendra les groupes créés. Chaque groupe contient les éléments présents dans le SELECT et accessibles en Apex via la méthode get.
  • COUNT / AVG / MAX : ce sont des fonctions d’agrégation à utiliser avec GROUP BY qui permettent de faire des calculs sur les éléments d’un groupe. Par exemple, AVG prendra la moyenne du champ spécifié, MAX / MIN en prendront les valeurs maximales / minimales. COUNT fera le compte des enregistrements qui ont une valeur dans le champ spécifié. Dans notre exemple, chaque ligne contiendra le nombre d’enregistrements, la moyenne du champ Amount et la valeur maximale du champ CloseDate.
  • WITH SECURITY_ENFORCED : permet d’appliquer les permissions concernant les champs et les objets à la requête. Si l’utilisateur qui exécute la requête n’a pas les droits sur un champ, il ne pourra pas le récupérer.

Il existe également des fonctions pour grouper par dates, par exemple par mois, par année fiscale ou par trimestre (à la manière des expressions littérales vues plus tôt). À noter qu’en groupant les enregistrements, on perd l’information des enregistrements individuels : on ne peut sélectionner que les champs par lesquels on groupe et des agrégats.

 

Niveau 6 – Fonctions avancées des groupes

La requête précédente montrait la possibilité de grouper les enregistrements selon un champ. Il est également possible de les grouper selon plusieurs champs, et de filtrer les groupes :

SELECT AccountId, GROUPING(AccountId) grpAcc,
       Type, GROUPING(Type) grpType,
       SUM(Amount),
       MIN(CloseDate)
FROM Opportunity
GROUP BY ROLLUP(AccountId, Type)
HAVING COUNT(ID) > 3

Ici on peut constater l’utilisation d’alias après les fonctions d’agrégation (‘grpAcc‘ dans ‘GROUPING(AccountId) grpAcc‘), qui permettent d’y faire référence plus facilement.

  • ROLLUP : cette fonction se combine à un GROUP BY pour faire calculer et combiner des sous-totaux des agrégats sélectionnés. Dans cet exemple, la requête renverra une ligne pour chaque couple AccountId/Type, une ligne de sous-total pour chaque valeur de AccountId, et une ligne rassemblant tous les enregistrements (tous les comptes).
  • GROUPING(champ) : vaut 1 si la ligne est un sous-total du type spécifié et 0 sinon. Dans cet exemple, les lignes qui rassemblent tous les types (correspondant à un compte) auront grpType = 1, tandis que les lignes correspondant à un couple AccountId/Type auront grpType = 0.
  • HAVING : définit une condition que doit remplir les groupes (et non plus les enregistrements) pour être prise en compte dans la requête. Ici, seuls les groupes contenant plus de 3 enregistrements apparaîtront. C’est l’équivalent du WHERE, s’appliquant aux groupes.

Notez aussi l’existence du mot-clé GROUP BY CUBE, variante de ROLLUP, qui calculera des sous-totaux pour toutes les combinaisons des champs. Pour reprendre l’exemple ci-dessus, l’utilisation de GROUP BY CUBE renverra les mêmes lignes qu’avec ROLLUP, mais rajoutera également les sous-totaux pour chaque valeur de Type.

 

Niveau 7 – Relations polymorphiques

Une relation polymorphique est un champ qui peut lier plusieurs objets différents, contrairement aux look-ups (relation de recherche) ou master-detail (maître détail), qui ne peuvent n’en représenter qu’un seul. Pour ces relations, les champs à récupérer vont dépendre de l’objet contenu dans la relation, on utilise donc une syntaxe spécifique :

SELECT
       TYPEOF What
           WHEN Account THEN Phone, NumberOfEmployees
           WHEN Opportunity THEN Amount, CloseDate
           ELSE Name, Email
       END
FROM Task
FOR UPDATE

Ici, on récupère des champs différents selon que la relation pointe vers un compte, une opportunité ou un autre objet.

  • TYPEOF / END : spécifie la relation polymorphique que l’on souhaite utiliser dans le filtre, le END termine le block.
  •  WHEN / THEN / ELSE : permet de préciser les champs à requêter pour chaque objet (le ELSE représentant toutes les situations qui n’auraient pas été traitées auparavant).
  • FOR : spécifie un traitement particulier à appliquer aux enregistrements récupérés, comme par exemple, le fait de les verrouiller dans le but de les mettre à jour sans avoir à se préoccuper de conflits potentiels avec FOR UPDATE. Il existe aussi FOR VIEW et FOR REFERENCE, qui permettent de prendre en compte des enregistrements dans la liste des « Récemment visualisés ».

 

Niveau 8 – Cas particuliers des requêtes SOQL

Certains objets offrent des fonctionnalités particulières pour les requêtes SOQL, comme par exemple, les articles « Knowledge » de Salesforce :

SELECT Title
FROM KnowledgeArticleVersion
WITH DATA CATEGORY Group1__c ABOVE SubCategory1__c
  • WITH DATA CATEGORY : permet de filtrer les articles en fonction de leur catégorie dans la hiérarchie des catégories dans Knowledge. C’est donc un filtre qui n’ira chercher les articles que dans les catégories répondant au critère spécifié (ici, ceux donc la catégorie est au-dessus de SubCategory1__c). Il existe plusieurs sélecteurs pour déterminer où chercher l’article à partir de la catégorie donnée (AT, BELOW, ABOVE_OR_BELOW).

Le mot-clé WITH peut également s’utiliser dans d’autres cas spécifiques décrits dans la documentation.

 

Pour résumer

Nous avons vu des exemples de requêtes SOQL permettant de mettre en évidence les différentes fonctionnalités à notre disposition. La liste n’est cependant pas exhaustive et certaines possibilités n’ont pas été présentées dans cet article.

Notez qu’il existe un certain nombre de limites qui peuvent s’appliquer à ces requêtes, comme par exemple, une limite dans le nombre de lignes qui peuvent être retournées d’un coup, ainsi que des limites associées à certains objets. Il est aussi important que les mots-clés apparaissent dans un certain ordre pour que la requête fonctionne.

La documentation officielle rentre plus dans les détails de chaque fonctionnalité pour en expliquer les usages et limites.

Si vous souhaitez en savoir plus sur SOQL, découvrez l’article de Fabien Taillon !