Mudar de SQL para SOQL
Objetivos de aprendizagem
Após concluir esta unidade, você estará apto a:
- Entender os benefícios dos Objetos do Salesforce.
- Identificar as semelhanças e as diferenças entre SQL e SOQL.
- Criar um demonstrativo SOQL simples usando o Workbench.
- Criar consultas de relacionamento mais complicadas.
- Criar consultas agregadas.
Como entender objetos do Salesforce
A Salesforce Platform oferece um banco de dados potente com muitos recursos que tornam a criação de aplicativos mais rápida e fácil. Se você já lidou com o SQL Server, sabe que os dados são armazenados em tabelas e linhas. O banco de dados no Salesforce, por outro lado, usa objetos para armazenar dados. Os objetos contêm todas as funcionalidades que você espera de uma tabela, com mais algumas melhorias que os tornam mais poderosos e versáteis. Cada objeto comporta diversos campos, que correspondem às colunas de um banco de dados. Os dados são armazenados em registros do objeto, que correspondem às linhas de um banco de dados. Mas espere um pouco… Ainda não acabou!
Existem dois tipos de objeto:
-
Objetos padrão – São aqueles objetos que vêm integrados ao Salesforce. Entre os objetos de CRM mais comuns, estão Accounts, Contacts, Opportunities e Leads.
-
Objetos personalizados – São objetos novos que você cria para armazenar informações exclusivas em seu aplicativo. Os objetos personalizados ampliam as funcionalidades oferecidas pelos objetos padrão. Por exemplo, se você estiver criando um aplicativo para rastrear o inventário de produtos, pode criar objetos personalizados chamados Mercadorias, Pedidos ou Faturas (Merchandise, Orders ou Invoices).
Como você provavelmente já imaginou, os objetos podem ter campos de relacionamento que definem como os registros de um objeto se relacionam com os registros de outro objeto. Esses campos são, em essência, quaisquer chaves primárias e estrangeiras; porém, eles são muito mais flexíveis, facilitando o planejamento e a implementação de seu modelo de dados.
Independentemente de serem padrão ou personalizados, os objetos do Salesforce não só oferecem uma estrutura para o armazenamento de dados como são a base dos elementos da interface que permitem que os usuários interajam com os dados, como as guias, o layout dos campos em uma página e as listas de registros relacionados. No caso das funcionalidades padrão, não há necessidade de implementar um ORM (Mapeamento de relacionamentos entre objetos), escrever uma IU para fazer CRUD de dados ou desenvolver tabelas. A plataforma oferece automaticamente essas funcionalidades padrão. Os objetos também têm suporte integrado a recursos como gerenciamento de acesso, validação, fórmulas e rastreamento de histórico. Todos os atributos de um objeto são descritos com metadados, facilitando a criação e modificação dos registros por meio de uma interface visual ou de forma programática.
Como você pode ver, os objetos são muito mais do que simples contêineres de armazenamento de dados. Eles oferecem um conjunto valioso de funcionalidades que deixam você livre para criar recursos exclusivos para o seu aplicativo. Para saber mais sobre como criar objetos personalizados, campos, relacionamentos e muito mais, confira o módulo Modelagem de dados.
Parecido, mas não igual
Como desenvolvedor .NET, é muito provável que você se sinta confortável para trabalhar com o SQL Server. E também é muito provável que você já saiba como escrever consultas ad hoc usando SQL. Então, pensamos que o melhor jeito de apresentar você a uma linguagem semelhante criada especificamente para o Salesforce, chamada SOQL (Salesforce Object Query Language, linguagem de consulta de objetos do Salesforce), seria comparar ambas.
A primeira coisa que você precisa saber é que, embora as duas sejam chamadas de linguagens de consulta, o SOQL é usado apenas para realizar consultas com o demonstrativo SELECT. O SOQL não tem demonstrativos equivalentes a INSERT, UPDATE e DELETE. No universo do Salesforce, a manipulação de dados é feita usando um conjunto de métodos chamado de Data Manipulation Language (DML - Linguagem de manipulação de dados). Falaremos mais sobre o DML em breve. Por enquanto, você só precisa saber como consultar dados do Salesforce usando o demonstrativo SELECT proporcionado pelo SOQL.
Uma grande diferença que você notará imediatamente é que o SOQL tem uma maneira diferente de fazer SELECT *
. Como o SOQL retorna os dados do Salesforce, que ficam em um ambiente multilocatário onde todos praticamente compartilham o banco de dados, usar um caractere curinga como *
é procurar encrenca. Honestamente, é demasiado fácil fazer uma nova consulta SQL e digitar SELECT * FROM SOME-TABLE
, principalmente quando você não sabe quais são os nomes dos campos da tabela. Em ambientes compartilhados, essa ação pode prejudicar imensamente os outros locatários. Para proteger a estrutura do locatário e respeitar a segurança em nível de campo, o SOQL usou FIELDS()
para mostrar apenas os campos que você tem permissão para acessar. Por exemplo: SELECT FIELDS(ALL) FROM Account
retorna todos os campos padrão e personalizados aos quais você tem acesso para o objeto Account (Conta).
No SOQL, você especifica o nome de cada campo a ser retornado. Além disso, o demonstrativo SELECT oferecido pelo SOQL é parecido com o do SQL. Você verá que escrever consultas SOQL é muito fácil. Mas você precisa saber disso: embora o SQL e o SOQL sejam parecidos, eles não são iguais. O SOQL não é compatível com alguns recursos mais avançados oferecidos pelo demonstrativo SELECT do SQL. Na plataforma do Salesforce, porém, não precisamos de todos esses recursos extras. O SOQL oferece exatamente o que é necessário de um jeito que faz você se sentir em casa.
Como criar uma consulta com o Console do desenvolvedor
Falando em escrever consultas SOQL, talvez você esteja se perguntando: “Mas como eu faço isso?”. Uma maneira fácil de começar é usar o Developer Console do Salesforce. Sabemos o quanto os desenvolvedores .NET adoram ferramentas, e essa é uma ferramenta potente que oferece vários meios para os administradores e desenvolvedores acessarem as organizações usando as APIs do Salesforce. Como desenvolvedor .NET, você provavelmente está familiarizado com o Visual Studio Code. Você ficará feliz de saber que temos Extensões Salesforce para VS Code que permitem o desenvolvimento personalizado e a criação de SOQL no seu computador local. A extensão está vinculada ao Salesforce DX, que oferece uma experiência de desenvolvimento moderna voltada para a fonte. Saiba mais sobre o Salesforce DX na trilha Introdução ao Salesforce DX.
Por enquanto, vamos nos concentrar no uso do Console do desenvolvedor para criar consultas SOQL. Se tiver algum tempo livre, porém, explore o Console do desenvolvedor e confira tudo o que ele oferece. Achamos que você vai gostar. Inscreva-se em uma organização gratuita do Developer Edition (DE) e depois:
- No menu Setup (Configuração) (
), selecione Console do desenvolvedor para abrir o Console do desenvolvedor.
- Clique na guia Query Editor (Editor de consulta) no painel inferior.
- Insira a seguinte consulta:
SELECT Id, Name, Type FROM Account
- Clique em Execute (Executar).
Os resultados da consulta mostram três colunas. Navegue pelos resultados.
Observe que a consulta obtém campos de um objeto e não de uma tabela. Os dados são mantidos dentro de objetos. Eles são chamados de sObjects, que significa Objetos do Salesforce (Salesforce Objects), e estão fortemente integrados à Salesforce Platform, o que torna mais fácil trabalhar com eles.
A má notícia é que os campos de data/hora do Salesforce são tão complicados e trabalhosos em SOQL quanto em SQL. A boa notícia é que o Salesforce oferece várias funções de data que facilitam um pouco o trabalho em SOQL. Quando for dar uma olhada na documentação, confira como o SOQL lida com os campos de moeda, porque eles também são um pouco diferentes, principalmente para as organizações que trabalham com várias moedas.
Filtrando os resultados
O SOQL tem só duas cláusulas obrigatórias: SELECT e FROM. A cláusula WHERE é opcional. Mas um bom desenvolvedor como você vai querer incluir a cláusula WHERE em praticamente toda consulta. Não faz sentido retornar mais dados do que o necessário.
Novamente, o jeito mais fácil de ver como isso funciona é usar o Workbench.
- No menu Setup (Configuração) (
), selecione Console do desenvolvedor para abrir o Console do desenvolvedor.
- Clique na guia Query Editor (Editor de consulta) no painel inferior.
- Insira a seguinte consulta:
SELECT AccountId, Email, Id, LastName FROM Contact
- Clique em Execute (Executar).
Essa consulta retorna todos os contatos da sua organização. No caso da organização de desenvolvimento, pode ser que essa lista seja pequena. Na maioria das organizações do mundo real, porém, milhares de contatos podem ser retornados. Por isso, sempre considere filtrar as consultas SOQL com a cláusula WHERE, principalmente aquelas usadas em código do Apex.
- Atualize a consulta adicionando a cláusula WHERE:
SELECT AccountId, Email, Id, LastName FROM Contact WHERE Email LIKE '%.net%'
- Clique em Execute (Executar).
Percebeu o que aconteceu? A consulta construída não inclui a palavra contains
. Em vez disso, ela usa LIKE
. A consulta também contém as aspas simples obrigatórias (porque Email é um campo de texto), além dos sinais de porcentagem antes e depois do termo pesquisado para indicar que é uma pesquisa com curinga.
Nota: Não é recomendável usar curingas, principalmente antes e depois do termo pesquisado, como no exemplo acima. Explicaremos melhor como criar consultas eficientes em uma unidade posterior, mas por enquanto lembre-se de evitar ao máximo pesquisas com curinga como a do exemplo.
- Enquanto isso, ordene os resultados por LastName com a cláusula
ORDR BY
. Agora, sua consulta fica mais ou menos assim:SELECT AccountId, Email, Id, LastName FROM Contact
WHERE Email LIKE '%.net%' ORDER BY LastName ASC NULLS FIRST
- Clique em Execute (Executar) para retornar os resultados como lista ordenada.
Algo muito importante a observar nos resultados são os dois campos de ID: AccountId e Id. Esses campos contêm uma sequência exclusiva de 18 caracteres que foi atribuída pela plataforma durante a criação dos registros de Account (Conta) e Contact (Contato). O campo AccountId está associado ao registro de conta (Account) ao qual foi atribuído esse contato (Contact) em particular. Em termos de SQL, é um relacionamento de chave estrangeira. O campo Id está relacionado ao contato. Em termos de SQL, ele representa a chave primária.
Enquanto tratamos dos relacionamentos de chave estrangeira, talvez você se pergunte como juntar tabelas em SOQL. Resumindo: isso não é possível. O SOQL não tem equivalente à cláusula JOIN. Mas não se preocupe, porque isso é bom.
Outro tipo de junção
Com certeza você não se surpreenderá com isso, mas o Salesforce combina objetos, ou tabelas, de um jeito um pouco diferente. Em vez de combinar tabelas com uma cláusula JOIN, você escreve algo que é chamado de consulta de relacionamento.
Conseguimos até ouvir você perguntando: “E o que é isso?”. Que bom que você perguntou.
O Salesforce usa o relacionamento pai-filho para combinar dois objetos. Assim como o SQL, o SOQL usa uma chave estrangeira para relacionar esses dois objetos, mas tem uma sintaxe de consulta diferente. A princípio, é meio estranho usar essa nova sintaxe porque você está trabalhando com objetos em vez de linhas. Mas depois de se acostumar com o básico, você descobrirá que escrever consultas de relacionamento é bem mais fácil do que escrever junções no SQL.
No SOQL, você precisa guardar na memória dois tipos básicos de consulta de relacionamento:
- Filho para pai
- Pai para filhos
Cada um deles tem seu próprio funcionamento. Como você já viu alguns campos dos objetos Account e Contact, que costumam ser combinados, começaremos com esses objetos. É importante saber que a conta (Account) é o pai e o contato (Contact) é o filho.
Escrever uma consulta de filho para pai
Digamos que você queira escrever uma consulta que retorne informações de conta e contato. A primeira opção é escrever uma consulta de filho para pai. Essa consulta de relacionamento usa “notação de ponto” para acessar os dados do pai, ou seja, um ponto separa o nome do relacionamento do nome do campo consultado.
Para mostrar como isso funciona, faremos um processo passo a passo que mostra como escrever uma consulta de relacionamento que retorna uma lista de contatos, incluindo o nome da conta associada. Mas, dessa vez, em vez de usar o Workbench, usaremos a guia Query Editor (Editor de consulta) no Developer Console.
- No Developer Console, clique na guia Query Editor (Editor de consulta) no painel inferior.
- Insira a seguinte consulta:
SELECT FirstName, LastName, Account.Name FROM Contact
- Clique em Execute (Executar).
Como você provavelmente ainda está pensando em termos de SQL, imagine a situação a seguir. Se você tivesse duas tabelas SQL chamadas Account e Contact com um relacionamento de um para muitos entre elas, como escreveria uma consulta SQL que retornasse essas mesmas informações?
Você usaria uma junção, é claro. Nesse caso, seria uma junção externa direita, porque você quer uma consulta equivalente que retorne todos os contatos, até mesmo aqueles que não estão relacionados a uma conta. Provavelmente, ficaria assim:
SELECT c.FirstName, c.LastName, a.Name FROM Account a RIGHT JOIN Contact c ON (c.AccountId = a.Id)
Agora, volte e observe a consulta SOQL equivalente:
SELECT FirstName, LastName, Account.Name FROM Contact
A consulta SOQL parece bem mais simples, não é?
Para falar a verdade, as consultas de relacionamento podem ser um pouco complicadas, principalmente quando tentamos descobrir o nome de relacionamentos para objetos personalizados. Para saber mais sobre a conversão de consultas SQL em consultas SOQL, confira este vídeo de treinamento prático.
Algo superimportante a se considerar com esses tipos de consulta é que a notação de ponto permite percorrer até cinco níveis em sentido ascendente. Então, é possível ir do filho para o pai, o avô, o bisavô e assim por diante.
Escrevendo consultas de pai para filhos
Consultas de pai para filhos também usam o nome do relacionamento, mas ele é usado dentro de uma consulta de seleção aninhada. Assim como no caso da nossa última consulta, é melhor explicar com um exemplo.
Dessa vez, escreveremos uma consulta do objeto pai Account e faremos com que ela contenha uma consulta aninhada que também retorne informações sobre cada contato (Contact) associado.
- No Developer Console, clique na guia Query Editor (Editor de consulta) no painel inferior.
- Insira a seguinte consulta:
SELECT Name, (Select FirstName, LastName FROM Contacts) FROM Account
O nome do relacionamento dentro da consulta aninhada usa o pluralContacts
(Contatos), em vez de Contact (Contato). É importante compreender esse detalhe, e é aí que muitas pessoas se confundem. Quando trabalhamos com consultas de relacionamento, o nome do relacionamento de pai para filho precisa estar no plural.
Quando trabalhamos com objetos personalizados, o nome do relacionamento precisa estar no plural e ter dois sublinhados e um r. Por exemplo, o nome do relacionamento do objeto personalizado My_Object__c é My_Objects__r.
- Clique em Execute (Executar).
Os resultados da consulta mostram duas colunas. Observe na imagem a seguir como os resultados da coluna Contacts são exibidos. Como cada conta costuma estar associada a vários contatos, o nome e o sobrenome são mostrados em formato JSON.
Mais uma vez, vejamos como essa consulta é escrita em SQL. No caso desta consulta, o equivalente em SQL é uma junção externa esquerda parecida com a seguinte:
SELECT a.Name, c.FirstName, c.LastName FROM Account a LEFT JOIN Contact c ON (a.Id = c.AccountId)
A consulta SQL reúne todos os registros de conta e os contatos associados a essas contas. O resultado retornado pelo SQL não está formatado como JSON. Fora isso, as consultas SQL e SOQL produzem os mesmos resultados.
A essa altura, você deve estar se perguntando se o SOQL aceita alias. Sim, mas não da forma que você está acostumado a trabalhar em SQL. O SOQL não tem palavra-chave AS. É possível usar um alias para representar o nome do objeto nas consultas SOQL, mas, no caso dos nomes de campo, os alias só funcionam nas consultas agregadas, que veremos a seguir.
Lembre-se: para se aprofundar nesse tópico, confira o vídeo de treinamento prático através do link, na seção Resources.
E a agregação?
É mesmo, o SOQL tem agregações que funcionam do jeito que esperamos. Bem, mais ou menos. Ao trabalhar com agregações, é importante considerar que, na maioria das funções, o resultado é retornado como o tipo AggregateResult.
Quanto às funções que podem ser usadas, o SOQL conta com as relacionadas na tabela abaixo. Confira os documentos oficiais para ver as especificidades de cada função.
Funções de agregação do SOQL
Função |
Descrição |
---|---|
AVG() |
Retorna o valor médio de um campo numérico. |
COUNT() e COUNT(fieldName) e COUNT_DISTINCT() |
Retornam o número de linhas que correspondem ao critério da consulta. |
MIN() |
Retorna o valor mínimo de um campo. |
MAX() |
Retorna o valor máximo de um campo. |
SUM() |
Retorna a soma total de um campo numérico. |
Para calcular a contagem de registros de determinada tabela chamada Account no SQL, você faria assim:
SELECT COUNT(*) FROM Account
No SOQL, essa mesma consulta fica assim:
SELECT COUNT() FROM Account
Bem parecido, não é?
Há alguns pontos que variam conforme a versão da função de contagem usada, pois cada versão retorna resultados diferentes. A função COUNT sem nome de campo é uma versão mais antiga que foi disponibilizada antes das outras funções de agregação. Ela retorna um número inteiro e é a mais parecida com a função count(*)
oferecida no SQL.
Count(fieldName) é uma versão mais recente que retorna o número de linhas, sendo que fieldName tem um valor não nulo. A diferença é que ela retorna o resultado como uma lista de AggregateResults, em vez de um valor único.
Vejamos como isso funciona na prática.
- No Console do desenvolvedor, clique em Query Editor (Editor de consulta).
- Insira a seguinte consulta:
SELECT COUNT() FROM Account
- Clique em Execute (Executar).
Os resultados da consulta mostram o número total de linhas com outro número ao lado dele.
- Retorne à guia Editor de consulta e altere a consulta para que ela fique assim:
SELECT COUNT(Id) FROM Account
- Clique em Executar.
Agora, os resultados da consulta retornam apenas uma linha e uma coluna, que mostra o número total de registros.
Até este ponto, não falamos muito de como lidar com os dados retornados pelas consultas SOQL. Mas por que adiar o inevitável? Vamos arregaçar as mangas e pôr as mãos à obra com alguns dados agregados.
Teremos de lidar com um pouco de Apex, mas não fique preocupado se esse trecho ainda não fizer muito sentido para você. Mais tarde, nos aprofundaremos nesse assunto.
- No Developer Console, selecione Debug (Depurar) e selecione Open Execute Anonymous Window (Abrir janela Executar no modo anônimo).
- Exclua qualquer código existente e insira o seguinte trecho:Observe como usamos um alias para representar o total junto à cláusula GROUP BY. No SOQL, só é possível usar campos de alias em consultas agregadas que usem a cláusula GROUP BY.
List<AggregateResult> results = [ SELECT Industry, count(Id) total FROM Account GROUP BY Industry ]; for(AggregateResult ar : results) { System.debug('Industry: ' + ar.get('Industry')); System.debug('Total Accounts: ' + ar.get('total')); }
- Verifique se a opção Open Log está selecionada e clique em Execute.
É carregada uma tabela que mostra o registro de execução.
- Selecione a opção Debug Only para ver apenas os demonstrativos de depuração no registro.
Quero saber mais
Além da cláusula GROUP BY, o SOQL oferece outras cláusulas de agrupamento, como GROUP BY ROLLUP, GROUP BY CUBE e GROUPING. Essas cláusulas são úteis para analisar os resultados quando a consulta retorna valores de várias tabelas relacionadas. GROUP BY CUBE é uma cláusula que permite somar os subtotais de todas as combinações dos campos agrupados nos resultados da consulta. Para saber mais sobre essas cláusulas, confira o documento GROUP BY em Recursos.
As funções agregadas também são compatíveis com uma cláusula HAVING opcional que é semelhante à cláusula HAVING do SQL Server; então, você vai se sentir em casa. Em essência, ela permite filtrar os resultados que uma função agregada retorna. Confira os Resources para saber mais.
Recursos
- Referência SOQL e SOSL: Sintaxe de SELECT do SOQL
- Referência SOQL e SOSL: Count e Count(fieldName)
- Guia do desenvolvedor do Apex: SOQL and SOSL Queries
- Referência SOQL e SOSL: GROUP BY