Pierwsze zapytania SOQL
Gdzie i jak uruchamiać zapytania (Salesforce Inspector, Developer Console, VS Code, CLI) oraz podstawy SOQL: filtrowanie, sortowanie, relacje i agregacje.
SOQL (Salesforce Object Query Language) to język zapytań do danych w Salesforce. Jeśli znasz SQL, poczujesz się jak w domu, z kilkoma ważnymi różnicami:
- SOQL służy tylko do odczytu danych,
- nie ma klasycznych złączeń (JOIN). Powiązane dane pobierasz przez relacje,
- zawsze wymieniasz pola, które chcesz pobrać. Nie ma odpowiednika
SELECT *znanego z SQL.
SOQL przydaje się nie tylko programistom. Piszesz w nim zapytania do generatorów dokumentów, takich jak PDF Butler, eksportujesz dane do analizy i szybko sprawdzasz, co naprawdę jest w bazie. Ten kurs prowadzi od podstaw do zapytań, których użyjesz w codziennej pracy.
Gdzie uruchamiać zapytania?
Zapytanie SOQL możesz uruchomić w kilku miejscach. Na start wystarczy jedno z dwóch pierwszych.
| Narzędzie | Dla kogo | Co trzeba zainstalować |
|---|---|---|
| Salesforce Inspector | administratorzy, konsultanci, analitycy | wtyczkę do przeglądarki |
| Developer Console | każdy, kto ma do niej dostęp w orgu | nic, jest wbudowana w Salesforce |
| Visual Studio Code | programiści | edytor, Salesforce CLI i rozszerzenia Salesforce |
| Salesforce CLI | programiści, automatyzacja eksportów | program wiersza poleceń |
Salesforce Inspector
- Otwórz dowolną stronę Salesforce. Przy prawej krawędzi okna kliknij małą zakładkę ze strzałką (1).
- W okienku wtyczki kliknij Data Export (2). Otworzy się nowa karta przeglądarki.
- Wpisz zapytanie w pole Export Query i kliknij Run Export albo naciśnij Ctrl + Enter (3).
- Wyniki pojawią się w tabeli poniżej. Przyciskiem Copy (Excel) (4) skopiujesz je do arkusza.
Jak zainstalować wtyczkę i co jeszcze potrafi, pokazujemy w następnej lekcji. Na Inspectorze ćwiczymy w całym kursie.
Developer Console
- Kliknij koło zębate w prawym górnym rogu Salesforce (1) i wybierz Developer Console (2). Konsola otworzy się w osobnym oknie. Jeśli nic się nie dzieje, sprawdź, czy przeglądarka nie zablokowała wyskakującego okna.
- Na dole konsoli kliknij zakładkę Query Editor (3).
- Wpisz zapytanie i kliknij Execute (4).
- Wyniki pojawią się w górnej części okna jako tabela Query Results (5).
Nie widzisz Developer Console w menu? Konsola wymaga odpowiednich uprawnień, więc zwykli użytkownicy często jej nie mają. W darmowym orgu do nauki jesteś administratorem i masz do niej dostęp.
Visual Studio Code
Ta opcja jest dla osób, które piszą też kod w Salesforce.
- Zainstaluj Visual Studio Code, Salesforce CLI i rozszerzenie Salesforce Extension Pack.
- Otwórz paletę poleceń (Ctrl + Shift + P), utwórz projekt poleceniem SFDX: Create Project i połącz go z orgiem poleceniem SFDX: Authorize an Org.
- Wpisz zapytanie w dowolnym pliku, zaznacz je i uruchom polecenie SFDX: Execute SOQL Query with Currently Selected Text. Wynik pojawi się w panelu Output.
Salesforce CLI
Wiersz poleceń przydaje się, gdy ten sam eksport robisz regularnie albo chcesz go zautomatyzować.
- Zainstaluj Salesforce CLI. Polecenia zaczynają się od
sf. - Zaloguj się do orga. Otworzy się przeglądarka ze stroną logowania Salesforce:
sf org login web --alias nauka
- Uruchom zapytanie:
sf data query --query "SELECT Id, Name FROM Account LIMIT 5" --target-org nauka
- Zapisz wynik do pliku CSV, który otworzysz w Excelu:
sf data query --query "SELECT Id, Name FROM Account" --target-org nauka --result-format csv > konta.csv
Twoje pierwsze zapytanie
Zanim przejdziesz dalej, uruchom w Inspectorze albo w Developer Console proste zapytanie:
SELECT Id, Name FROM Account LIMIT 10
Jeśli zobaczysz tabelę z firmami ze swojego orga, wszystko działa. Teraz poznasz składnię, która za tym stoi.
Przykładowe dane
Wszystkie przykłady w tej lekcji działają na tych samych, małych danych: 6 firm i 5 kontaktów. Dzięki temu przy każdym zapytaniu łatwo porównasz dane wejściowe z wynikiem.
Obiekt Account (firmy):
| Name | Industry | BillingCity | AnnualRevenue |
|---|---|---|---|
| Acme Polska | Technology | Warszawa | 5 000 000 |
| Beta Finanse | Finance | Kraków | 12 000 000 |
| Cyfrowy Dom | Technology | Gdańsk | 800 000 |
| Delta Retail | Retail | Warszawa | 3 500 000 |
| Echo Software | Technology | Kraków | 2 200 000 |
| Fala Media | Media | Warszawa | (puste) |
Obiekt Contact (kontakty), powiązany z firmą polem AccountId:
| FirstName | LastName | Firma (Account) |
|---|---|---|
| Anna | Nowak | Acme Polska |
| Piotr | Kowalski | Acme Polska |
| Ewa | Wiśniewska | Beta Finanse |
| Jan | Zieliński | Echo Software |
| Marta | Lewandowska | (brak firmy) |
Dwie uwagi do tabel z wynikami. Kwoty są sformatowane dla czytelności, a Salesforce zwraca je jako zwykłe liczby, np.
5000000. BezORDER BYSalesforce nie gwarantuje kolejności rekordów, więc w takich wynikach pokazujemy je w kolejności z tabeli wejściowej.
Chcesz sprawdzić przykłady u siebie? Utwórz te firmy i kontakty w swoim orgu do nauki: ręcznie albo importem z pliku CSV, jak w lekcji Praca z rekordami i widokami list. Wartości Technology, Finance, Retail i Media są na standardowej liście branż.
Podstawowa składnia
SELECT Id, Name, Industry
FROM Account
WHERE Industry = 'Technology'
ORDER BY Name
LIMIT 10
SELECT: pola do pobrania (nazwy API, nie etykiety),FROM: obiekt,WHERE: warunki,ORDER BY: sortowanie,LIMIT: maksymalna liczba wyników.
Przykład 1. Wybór pól
SELECT Name, Industry
FROM Account
Co zwróci: wszystkie firmy, bo nie ma warunku WHERE, ale tylko dwie wskazane kolumny. Pozostałe pola, np. miasto i przychód, nie trafią do wyniku.
Wynik (6 rekordów):
| Name | Industry |
|---|---|
| Acme Polska | Technology |
| Beta Finanse | Finance |
| Cyfrowy Dom | Technology |
| Delta Retail | Retail |
| Echo Software | Technology |
| Fala Media | Media |
Filtrowanie
W warunkach WHERE możesz używać m.in.:
- porównań:
=,!=,<,>,<=,>=, - dopasowania tekstu:
Name LIKE 'Acme%', - listy wartości:
Industry IN ('Technology', 'Finance'), - łączenia warunków:
AND,OR,NOT.
Przykład 2. Równość
SELECT Name, BillingCity
FROM Account
WHERE Industry = 'Technology'
Co zwróci: tylko firmy z branży Technology. Pozostałe rekordy odpadają już na etapie warunku.
Wynik (3 rekordy):
| Name | BillingCity |
|---|---|
| Acme Polska | Warszawa |
| Cyfrowy Dom | Gdańsk |
| Echo Software | Kraków |
Przykład 3. Porównanie liczb i puste pola
SELECT Name, AnnualRevenue
FROM Account
WHERE AnnualRevenue > 3000000
Co zwróci: firmy z przychodem powyżej 3 milionów. Uwaga na Fala Media: ma puste pole przychodu, a puste pole nie spełnia żadnego porównania liczbowego, więc nie trafi do wyniku.
Wynik (3 rekordy):
| Name | AnnualRevenue |
|---|---|
| Acme Polska | 5 000 000 |
| Beta Finanse | 12 000 000 |
| Delta Retail | 3 500 000 |
Jeśli chcesz znaleźć właśnie firmy bez przychodu, użyj warunku WHERE AnnualRevenue = null.
Przykład 4. Łączenie warunków
SELECT Name, Industry, BillingCity
FROM Account
WHERE BillingCity IN ('Warszawa', 'Kraków')
AND Industry != 'Retail'
Co zwróci: firmy z Warszawy lub Krakowa, z wyjątkiem branży Retail. Oba warunki muszą być spełnione jednocześnie, więc Delta Retail (Warszawa, ale Retail) odpada.
Wynik (4 rekordy):
| Name | Industry | BillingCity |
|---|---|---|
| Acme Polska | Technology | Warszawa |
| Beta Finanse | Finance | Kraków |
| Echo Software | Technology | Kraków |
| Fala Media | Media | Warszawa |
Daty
Przy datach przydają się literały dat, które Salesforce przelicza za Ciebie:
SELECT Name, CloseDate, Amount
FROM Opportunity
WHERE CloseDate = THIS_QUARTER
AND StageName = 'Closed Won'
Inne przydatne literały to TODAY, LAST_N_DAYS:30 czy THIS_YEAR. Szczegóły i więcej przykładów znajdziesz w lekcji o filtrowaniu.
Sortowanie i limit
Przykład 5. Sortowanie malejąco
SELECT Name, AnnualRevenue
FROM Account
ORDER BY AnnualRevenue DESC NULLS LAST
Co zwróci: wszystkie firmy, od najwyższego przychodu do najniższego. DESC oznacza sortowanie malejące, a NULLS LAST przenosi firmy z pustym przychodem na koniec listy.
Wynik (6 rekordów):
| Name | AnnualRevenue |
|---|---|
| Beta Finanse | 12 000 000 |
| Acme Polska | 5 000 000 |
| Delta Retail | 3 500 000 |
| Echo Software | 2 200 000 |
| Cyfrowy Dom | 800 000 |
| Fala Media | (puste) |
Przykład 6. Sortowanie po dwóch polach
SELECT Name, BillingCity
FROM Account
ORDER BY BillingCity, Name
Co zwróci: firmy posortowane najpierw alfabetycznie po mieście, a w ramach tego samego miasta po nazwie. Bez DESC sortowanie jest rosnące.
Wynik (6 rekordów):
| Name | BillingCity |
|---|---|
| Cyfrowy Dom | Gdańsk |
| Beta Finanse | Kraków |
| Echo Software | Kraków |
| Acme Polska | Warszawa |
| Delta Retail | Warszawa |
| Fala Media | Warszawa |
Przykład 7. Limit, czyli „pierwsze N”
SELECT Name, AnnualRevenue
FROM Account
ORDER BY AnnualRevenue DESC NULLS LAST
LIMIT 3
Co zwróci: trzy firmy z najwyższym przychodem. To samo zapytanie co w przykładzie 5, ale LIMIT 3 ucina wynik po trzecim rekordzie. Bez ORDER BY dostałbyś trzy przypadkowe firmy.
Wynik (3 rekordy):
| Name | AnnualRevenue |
|---|---|
| Beta Finanse | 12 000 000 |
| Acme Polska | 5 000 000 |
| Delta Retail | 3 500 000 |
Zapytania po relacjach
Przykład 8. Od dziecka do rodzica
Pola rekordu nadrzędnego pobierasz przez kropkę:
SELECT FirstName, LastName, Account.Name, Account.Industry
FROM Contact
Co zwróci: wszystkie kontakty, a przy każdym nazwę i branżę jego firmy. Marta Lewandowska nie ma firmy, więc jej pola firmy będą puste. Zapytanie nie zwróci błędu.
Wynik (5 rekordów):
| FirstName | LastName | Account.Name | Account.Industry |
|---|---|---|---|
| Anna | Nowak | Acme Polska | Technology |
| Piotr | Kowalski | Acme Polska | Technology |
| Ewa | Wiśniewska | Beta Finanse | Finance |
| Jan | Zieliński | Echo Software | Technology |
| Marta | Lewandowska | (puste) | (puste) |
Pól rodzica możesz też używać w warunkach. Po dopisaniu WHERE Account.Industry = 'Technology' zostaną tylko Anna Nowak, Piotr Kowalski i Jan Zieliński.
Przykład 9. Od rodzica do dzieci
Rekordy podrzędne pobierasz podzapytaniem, w którym używasz nazwy relacji w liczbie mnogiej:
SELECT Name, (SELECT FirstName, LastName FROM Contacts)
FROM Account
WHERE BillingCity = 'Warszawa'
Co zwróci: firmy z Warszawy, a przy każdej listę jej kontaktów. Podzapytanie nie filtruje firm: Delta Retail i Fala Media nie mają kontaktów, ale i tak są w wyniku, tylko z pustą listą.
Wynik (3 rekordy):
| Name | Contacts (podzapytanie) |
|---|---|
| Acme Polska | Anna Nowak, Piotr Kowalski |
| Delta Retail | (brak kontaktów) |
| Fala Media | (brak kontaktów) |
W relacjach niestandardowych nazwa relacji kończy się na __r, np. Seller__r.Name albo podzapytanie FROM Offers__r. Dokładną nazwę relacji sprawdzisz w ustawieniach pola w Object Manager.
Agregacje
Funkcje agregujące nie zwracają pojedynczych rekordów, tylko podsumowania: liczby, sumy, średnie. GROUP BY dzieli rekordy na grupy i liczy wynik dla każdej z nich.
Przykład 10. Liczenie w grupach
SELECT Industry, COUNT(Id) liczba
FROM Account
GROUP BY Industry
Co zwróci: po jednym wierszu na każdą branżę i liczbę firm w tej branży. liczba to alias, czyli własna nazwa kolumny wyniku. W SOQL piszesz go bez słowa AS.
Wynik (4 wiersze):
| Industry | liczba |
|---|---|
| Technology | 3 |
| Finance | 1 |
| Retail | 1 |
| Media | 1 |
Przykład 11. Suma w grupach
SELECT BillingCity, SUM(AnnualRevenue) przychod
FROM Account
GROUP BY BillingCity
Co zwróci: łączny przychód firm z każdego miasta. SUM pomija puste wartości: w Warszawie sumują się tylko Acme Polska i Delta Retail, bo Fala Media nie ma przychodu.
Wynik (3 wiersze):
| BillingCity | przychod |
|---|---|
| Warszawa | 8 500 000 |
| Kraków | 14 200 000 |
| Gdańsk | 800 000 |
Przykład 12. Filtrowanie grup: HAVING
SELECT BillingCity, COUNT(Id) liczba
FROM Account
GROUP BY BillingCity
HAVING COUNT(Id) > 1
Co zwróci: tylko miasta, w których jest więcej niż jedna firma. WHERE filtruje pojedyncze rekordy przed grupowaniem, a HAVING filtruje gotowe grupy. Gdańsk ma jedną firmę, więc odpada.
Wynik (2 wiersze):
| BillingCity | liczba |
|---|---|
| Warszawa | 3 |
| Kraków | 2 |
SOQL w kodzie Apex
W Apex zapytanie wpisujesz w nawiasach kwadratowych, a zmienne przekazujesz z dwukropkiem:
String branza = 'Technology';
List<Account> konta = [
SELECT Id, Name
FROM Account
WHERE Industry = :branza
LIMIT 10
];
System.debug(konta.size());
Taka zmienna (bind variable) chroni też przed wstrzykiwaniem niebezpiecznych wartości do zapytania.
Ćwiczenie
Korzystając z obiektów Nieruchomość (Property__c) i Oferta (Offer__c) z modułu 2 kursu Podstawy Salesforce, napisz zapytania, które:
- Zwracają wszystkie nieruchomości z ceną wyższą niż 500 000, posortowane od najdroższej.
- Zwracają nieruchomości o statusie Dostępna, które są dostępne od dnia przypadającego w tym roku.
- Dla każdej nieruchomości zwracają nazwisko sprzedającego i listę ofert z kwotami.
Podpowiedź do zadania 3: zacznij od
SELECT Name, Seller__r.LastName, (SELECT ... FROM Offers__r) FROM Property__c. Kwotę oferty zapisuje poleAmount__c.
Sprawdź się
Przewidź wynik na przykładowych danych z początku lekcji, a dopiero potem rozwiń odpowiedź.
1. Które firmy zwróci to zapytanie?
SELECT Name FROM Account WHERE BillingCity = 'Warszawa' AND AnnualRevenue > 1000000
Pokaż odpowiedź
Acme Polska i Delta Retail. Fala Media też jest z Warszawy, ale ma puste pole przychodu, więc nie spełnia porównania liczbowego.
2. Co zwróci to zapytanie?
SELECT Industry, COUNT(Id) liczba FROM Account WHERE BillingCity != 'Gdańsk' GROUP BY Industry
Pokaż odpowiedź
WHERE usuwa firmę Cyfrowy Dom z Gdańska jeszcze przed grupowaniem, więc w branży Technology zostają dwie firmy:
| Industry | liczba |
|---|---|
| Technology | 2 |
| Finance | 1 |
| Retail | 1 |
| Media | 1 |
3. Nazwiska których kontaktów zwróci to zapytanie?
SELECT LastName FROM Contact WHERE Account.BillingCity = 'Kraków'
Pokaż odpowiedź
Wiśniewska i Zieliński, bo ich firmy (Beta Finanse i Echo Software) są z Krakowa. Lewandowska odpada, bo nie ma przypisanej firmy.
Podsumowanie
- SOQL tylko odczytuje dane i zawsze wymaga wskazania pól.
WHEREfiltruje rekordy,ORDER BYustala kolejność, aLIMITucina wynik. BezORDER BYkolejność nie jest gwarantowana.- Puste pola nie spełniają porównań w
WHERE, a funkcje takie jakSUMje pomijają. - Relacje obsługujesz kropką (do rodzica) albo podzapytaniem (do dzieci). Podzapytanie nie usuwa rodziców bez dzieci.
- Agregacje z
GROUP BYzwracają podsumowania zamiast rekordów, aHAVINGfiltruje gotowe grupy.
Następny krok: zainstalujesz Salesforce Inspector, w którym przećwiczysz wszystkie zapytania z tego kursu. Każdy temat z tej lekcji, czyli filtrowanie, relacje i agregacje, rozwijamy potem w osobnej lekcji.