Salesforce coding lessons for the 99%
Finally, Apex tutorials for point-and-click admins! Written by a self-taught Google engineer.
  • Beginner Tutorials
    • Apex
    • Certifications
    • Career Info
    • Technical Architect
    • Visualforce
    • Videos
  • Apex Academy
  • Success Stories
  • About Me
  • Misc
    • Mailbag
    • Challenges
    • Links
    • Login to my Org
Follow @dvdkliuor SUBSCRIBE!

Apex Video Tutorial: SOQL & Core Apex

July 2, 2014

Preface: This video is part 2 of the Official #Apex4Admins series presented by Salesforce and I!

Learn fundamental Apex tools and SOQL!

  1. How to write a SOQL query!
  2. Core Apex: variables, IF statements, loops!
  3. Write a new Salesforce trigger!

View slides

Basic SOQL

[SELECT Id, Name, Website, Sells_Chocolate__c FROM Account];

Cross-object

[SELECT Account.Owner.Manager.Needs_Chocolate__c FROM Contact];

WHERE

[SELECT Id, Name FROM Contact WHERE Eats_Chocolate__c = true];

Operators

[SELECT Id, Title FROM Lead WHERE Favorite_Chocolate__c != null];

AND

[SELECT Id, Name, Email, Birthdate, Account.Name FROM Contact 
  WHERE Eats_Chocolate__c   = true
AND Allergic_to_Nuts__c = false AND Chocolate_Rehab__c = false];

Mixing ANDs & ORs

[SELECT Id, Name, Email, Birthdate, Account.Name FROM Contact 
  WHERE Eats_Chocolate__c  = true
AND (Milk_Chocolate__c = true OR Dark_Chocolate__c = true)];

Text, Picklist, IDs

[SELECT Id, Name, Email, Birthdate, Account.Name FROM Contact 
  WHERE Eats_Chocolate__c     = true
AND Favorite_Chocolate__c = 'Snickers' AND OwnerId = '005i0000000OAOO'];

Numbers

[SELECT Id, Name, Email, Birthdate, Account.Name FROM Contact 
  WHERE Eats_Chocolate__c          = true
AND Chocolate_Bars_Consumed__c > 10 OR Broccoli_Consumed__c <= 1];

Dates

[SELECT Id, Name, Email, Birthdate, Account.Name FROM Contact 
  WHERE Eats_Chocolate__c  = true    
    AND Diet_Start_Date__c = null
OR Diet_Start_Date__c > TODAY];

Fuzzy Matching

[SELECT Id, Name, Email, Birthdate, Account.Name FROM Contact 
  WHERE Eats_Chocolate__c   = true
AND Preferred_Fillings__c LIKE '%Caramel%'];

Sorting

[SELECT Id, Name, Email, Birthdate, Account.Name FROM Contact 
  WHERE Eats_Chocolate__c = true    
    AND Last_Chocolate_Consumption__c < 2014-01-01
ORDER BY LastName ASC];

Limiting Results

[SELECT Id, Name, Email, Birthdate, Account.Name FROM Contact 
  WHERE Eats_Chocolate__c = true    
    AND Last_Chocolate_Consumption__c = YESTERDAY
LIMIT 10];

Apex FUNdamentals

Variables

// Text
String favoriteMovie = 'Frozen';

// Numbers
Integer timesWatched     = 8;
Decimal merchandiseSpend = 55.20;

// True or False
Boolean ownsTheSoundtrack = true;

// Dates
Date dateLastWatched  = Date.newInstance(2014, 5, 20);
DateTime nextShowtime = DateTime.now().addHours(7);

// SObjects
Movie__c frozen = [SELECT Id FROM Movie__c WHERE Name = 'Frozen'];

IF Statements and Comparison Operators

// How to compare values
Greater than:  >      Less than:     <
Equals:        ==     Not Equals:    !=
AND:           &&     OR:            ||

// IF Statements
if (david.Twtr_Follows__c < leeAnne.Twtr_Follows__c) {
david.Emotions__c = 'Crushed.';
} else if (david.Twtr_Follows__c == leeAnne.Twtr_Follows__c) {
david.Emotions__c = 'Showdown! Last man standing!';
} else if (david.Twtr_Follows__c < 1200 || david.Tweets__c < 500){
david.Emotions__c = 'A petty victory.';
} else {
david.Emotions__c = 'Life is good.'; }

Loops

// FOR EACH Loop: Eat every Reeses in our trigger!
for (Chocolate__c choco : Trigger.new) {
if (choco.Name == 'Reeses') { choco.Status__c = 'In my belly!'; update choco; } } // FOR Loop: Eat 100 Reeses!
for (Integer i = 0; i < 100; i++) {
Chocolate__c choco = new Chocolate__c(); choco.Name = 'Reeses'; choco.Status__c = 'In my belly!'; insert choco; }
// Eat 10 Reeses every time you watch Frozen!
trigger Snacks on Movie__c (after insert) {
    // Loop through all records in the trigger
for (Movie__c movie : Trigger.new) {
if (movie.Name == 'Frozen') { // Loop a specific number of times
for (Integer i = 0; i < 10; i++) {
Chocolate__c choco = new Chocolate__c(); choco.Name = 'Reeses'; choco.Status__c = 'In my belly!'; insert choco; } } } }

Final “Non-Profit” Trigger:

trigger AutoCreateOpp on Account (after insert) {
    // Every trigger has this loop!
for (Account a : Trigger.new) {
// Check if it's a 'Prospect' Account
if (a.Type == 'Prospect') {
// Create a new Opp (but don't save yet) Opportunity o = new Opportunity(); o.Name = 'Big Deal'; o.StageName = 'Prospecting'; o.CloseDate = Date.today().addDays(30); o.AccountId = a.Id; // Set the Opp amount based on the Industry
if (a.Industry == 'Technology') {
o.Amount = 5000000;
} else if (a.Industry == 'Non-Profit') {
o.Amount = 1000;
} else {
o.Amount = 5000; } // Double the Opp amount if there are many employees!
Integer bigCompanyMultiplier = 2; if (a.NumberOfEmployees > 1000) { o.Amount = o.Amount * bigCompanyMultiplier; }
// Don't forget to save! insert o; } } }

Continue to Part 3: Combine SOQL & Apex!

11 Comments
appiee
March 30, 2015 @ 7:34 am

hey david
i am a huge fan of your’s i started learning salesforce here just a few weeks ago.. you are doing a great job i must say i am
always afraid of coding and now i am trying to learn apex from this site.. i just wanted to ask you a very normal question for an interview as a fresher which type of coding can a company expect ?? i mean if you are a beginner and just know the basics is that enough ?? and i wanted to ask you the soql queries you wrote here… where should i do the practice on ?? my developer console isn’t working and opened your account as well but it’s not working.. i opened the developer console and and then click to debug and then write my code on the open execute anonymous window it doesn’t shows anything… i don’t know what’s wrong :(

Reply
SkottieGee (@skottiegee)
October 9, 2014 @ 6:48 am

Hi David,

If I wanted the trigger below to bit a bit more conditional i.e. if the movie is Frozen the trigger inserts 10 Reeses but if I wanted to have another IF condition to say if the Movie is Batman then insert 10 skittles how could I do that. I have attempted a few times with what seems logical to me but it wasnt compiling, complaining about brackets in the wrong places etc …

trigger MovieAI on Movie__c (after insert) {

for(Movie__c movie : trigger.new) {

if (movie.Name == ‘Frozen’) {

for (Integer i = 0; i < 10; i++) {

Snack__c nomnoms = new Snack__c();
nomnoms.Name = 'Reeses';
nomnoms.Status__c = 'In my belly!';
nomnoms.Movie__c = movie.id;
insert nomnoms;

}

}

}

}

Reply
    David Liu
    October 9, 2014 @ 8:05 pm

    The logic in what you have looks good =)

    As to the errors, it’s just a matter of counting your brackets =)

    Post the whole code if you need more detailed help!

    David

    Reply
Dean
July 13, 2014 @ 10:53 am

Hi David,

I copied the same trigger. I created a new account, type:prospect,indusry:non-profit, emp: 20K. However I get amount as 10,000. weird..

trigger AutoCreateOpp on Account (after insert) {
// Every trigger has this loop!
for (Account a : Trigger.new) {
// Check if it’s a ‘Prospect’ Account
if (a.Type == ‘Prospect’) {
// Create a new Opp (but don’t save yet)
Opportunity o = new Opportunity();
o.Name = ‘Big Deal’;
o.StageName = ‘Prospecting’;
o.CloseDate = Date.today().addDays(30);
o.AccountId = a.Id;

// Set the Opp amount based on the Industry
if (a.Industry == ‘Technology’) {
o.Amount = 5000000;
} else if (a.Industry == ‘Non-Profit’) {
o.Amount = 1000;
} else {
o.Amount = 5000;
}

// Double the Opp amount if there are many employees!
Integer bigCompanyMultiplier = 2; if (a.NumberOfEmployees > 1000) { o.Amount = o.Amount * bigCompanyMultiplier; }

// Don’t forget to save!
insert o;
}
}
}

Reply
    David Liu
    July 15, 2014 @ 10:10 pm

    Check out this post to debug!
    https://www.sfdc99.com/2014/02/22/debug-your-code-with-system-debug/

    Reply
Sebastian
July 9, 2014 @ 12:10 pm

Shouldn’t the final trigger ‘Autocreatopp’ write the new opportunities to the list, then ‘try’ to insert the list after closing the for loop? If 300 Accounts were inserted at once, you would hit limits with 300 insert DML statements, correct? Like this:

trigger AutoCreateOpp on Account (after insert) {
// Every trigger has this loop!
list oppsToInsert = new list ();
for (Account a : Trigger.new) {
// Check if it’s a ‘Prospect’ Account
if (a.Type == ‘Prospect’) {
// Create a new Opp (but don’t save yet)
Opportunity o = new Opportunity();
o.Name = ‘Big Deal’;
o.StageName = ‘Prospecting’;
o.CloseDate = Date.today().addDays(30);
o.AccountId = a.Id;

// Set the Opp amount based on the Industry
if (a.Industry == ‘Technology’) {
o.Amount = 5000000;
} else if (a.Industry == ‘Non-Profit’) {
o.Amount = 1000;
} else {
o.Amount = 5000;
}

// Double the Opp amount if there are many employees!
Integer bigCompanyMultiplier = 2;
if (a.NumberOfEmployees > 1000) {
o.Amount = o.Amount * bigCompanyMultiplier;
}

// Don’t forget to save!
oppsToInsert.add(o);
}
}
try {
insert oppsToInsert;
} catch (system.DmlException e) {
system.debug (e);
}
}

Reply
    David Liu
    July 10, 2014 @ 10:39 pm

    Great observation Sebastian!!

    You’re ahead of the curve – we cover this topic in Chapter 5!

    Reply
Anonymous
July 4, 2014 @ 9:10 pm

Thanks Dave :)

Reply
Nitin
July 4, 2014 @ 12:44 am

Please let me know how can I improve this Test Class on non-profit Trigger ? Its working fine and test results have covered 100% Trigger code

@isTest
public class TestAutoCreateOpty{
static testMethod void tester() {

//Create a list of Accounts
List-Account listOfAccounts = new List-Account();

//Create Technology Account as Prospect having less than 1000 emp
Account Techno = new Account();
Techno.Name = ‘Moserbaer’;
Techno.Industry = ‘Technology’;
Techno.Type = ‘Prospect’;
Techno.NumberOfEmployees = 999;
listOfAccounts.add(Techno);

//Create a Non-Profit Account as Prospect having 1000 emp
Account nonProf = new Account();
nonProf.Name = ‘RGV’;
nonProf.Industry = ‘Non-Profit’;
nonProf.Type = ‘Prospect’;
nonProf.NumberOfEmployees = 1000;
listOfAccounts.add(nonProf);

//Create an Agriculture Account as Prospect having more than 1000 emp
Account Agri = new Account();
Agri.Name = ‘BASF’;
Agri.Industry = ‘Agriculture’;
Agri.Type = ‘Prospect’;
Agri.NumberOfEmployees = 1001;
listOfAccounts.add(Agri);

//Create an Agriculture Account as Prospect having more than 1000 emp
Account App = new Account();
App.Name = ‘Nike’;
App.Industry = ‘Apparel’;
App.Type = ‘Other’;
App.NumberOfEmployees = 1002;
listOfAccounts.add(App);

insert listOfAccounts;

//System.AssertEquals(5000000, listOfAccounts[0].Opportunity__r.Amount);
//System.AssertEquals(1000, listOfAccounts[1].Opportunity__r.Amount);
//System.AssertEquals(10000, listOfAccounts[2].Opportunity__r.Amount);
//System.AssertEquals(null, listOfAccounts[3].Opportunity__r.Amount);

//Get the values in a List
List-Account check = [SELECT Id, Type, NumberOfEmployees, (SELECT Amount FROM Opportunities)
FROM Account
WHERE Name IN (‘Moserbaer’, ‘RGV’, ‘BASF’, ‘Nike’)];

//Assert the results
for (Account abc : check) {
for (Opportunity o : abc.Opportunities) {
if (abc.Type == ‘Prospect’) {
System.debug(‘Amount alloted =’ + o.Amount);
} else {
System.AssertEquals(null, o.Amount);
}
}

}
}
}

Reply
    David Liu
    July 4, 2014 @ 4:24 pm

    LOVE IT!!!!! Amazing work Nitin, you are learning very well!!!!

    Reply
    thematthewandersblog
    May 28, 2017 @ 9:33 am

    Nitin,

    Thanks for asking for this as I needed it too to reverse engineer. Still learning by reading on the tests as I get lost very quickly. Amazing work doing this on your own Nitin!

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *


*

*

Theme: Simple Style by Fimply