home.social

#salesforcehowto — Public Fediverse posts

Live and recent posts from across the Fediverse tagged #salesforcehowto, aggregated by home.social.

  1. SOQL Basics for Salesforce Admins

    If you have spent any amount of time in the Salesforce ecosystem as an admin, you know this exact routine:

    A stakeholder asks for a dataset. You build a custom report type, drag and drop fields, apply filters, and hit Export. Then, because Salesforce reports cannot easily pull data across non-related branches or cross-reference two unconnected objects, you open Excel or Google Sheets. You waste 30 minutes writing nested VLOOKUP or XLOOKUP functions, cleaning up blank rows, and dealing with #N/A errors.

    What if you could bypass the Report Builder, skip Excel entirely, and extract precise, relational datasets straight from Salesforce in seconds?

    Meet SOQL: The Admin Query Tool Hiding in Plain Sight

    SOQL stands for Salesforce Object Query Language. It is a lightweight, declarative query syntax used to read data stored in your Salesforce database. Think of it as asking Salesforce a direct question: “Give me these specific fields, from this object, where these conditions are met.”

    While SOQL is often labeled as a “developer tool,” it is actually one of the most powerful super-skills a Salesforce Administrator can learn. In this guide, we will cover the basics of SOQL, demonstrate how to construct powerful queries with sorting and grouping, and show you how to leverage Salesforce Inspector to execute queries faster than you ever thought possible.

    Why SOQL Beats Standard Reports and Excel

    • No Report Limits: Standard Salesforce reports cap you at 2,000 rows in the UI, and multi-block joined reports can be clunky. SOQL lets you quickly inspect thousands of records at once.
    • Access “Hidden” Objects: Certain system objects, such as FieldPermissions, UserRecordAccess, ApexClass, or GroupMember, are impossible or difficult to query via standard report types. SOQL gives you direct visibility into almost every object in your org.
    • Say Goodbye to VLOOKUPs: Instead of exporting Contacts to Sheet A and Accounts to Sheet B to run a VLOOKUP, SOQL allows you to reach across relationships directly in a single line of query text.
    • Data Operations Ready: When you pull data via SOQL, you get precise 18-character Record IDs, making the export immediately formatted and ready for Data Loader or inline updates.

    Understanding SOQL Query Structure

    Every basic SOQL query relies on three core clauses: SELECT, FROM, and WHERE.

    SELECT Id, Name, StageName, Amount 
    FROM Opportunity 
    WHERE IsClosed = False

    Let’s break this down:

    • SELECT: The specific Field API Names you want to retrieve. (Tip: Always use API names, such as Custom_Field__c, not field labels).
    • FROM: The API Name of the Salesforce object you are querying (e.g., Account, Contact, Custom_Object__c).
    • WHERE: The filtering conditions. Only records meeting these criteria will be returned.

    Essential SOQL Clauses and Operators

    To make your queries more precise, you can append additional clauses:

    • ORDER BY: Sorts your records in ascending (ASC) or descending (DESC) order.
    • LIMIT: Restricts the maximum number of records returned (e.g., LIMIT 100).
    • IN: Filters against a list of values (e.g., WHERE StageName IN (‘Closed Won’, ‘Closed Lost’)).
    • LIKE: Performs wild-card searches using % (e.g., WHERE Email LIKE ‘%@gmail.com’).

    Master Sorting with ORDER BY (Ascending vs. Descending)

    When querying individual records, use ORDER BY with ASC (smallest to largest / A to Z) or DESC (largest to smallest / Z to A). If unspecified, SOQL defaults to ASC.

    When you add multiple fields separated by a comma after ORDER BY, it creates a primary sort and a secondary sort (tie-breaker).

    Example: Primary & Secondary Sorting (DESC / DESC)

    Goal: Pull open Opportunities, sorted so the highest-value deals appear at the top (DESC), followed by the most recently created deals (DESC).

    SELECT Id, Name, Amount, StageName, CloseDate 
    FROM Opportunity 
    WHERE IsClosed = False 
    ORDER BY Amount DESC, CloseDate DESC 
    LIMIT 50

    How Salesforce Evaluates Multi-Field Sorting Step-by-Step

    1. Primary Sort (Amount DESC): Salesforce first sorts all records by Amount from highest to lowest.
    2. Secondary Sort (CloseDate DESC): If two or more opportunities have the exact same Amount, Salesforce uses CloseDate to break the tie, placing the one with the most recent CloseDate higher up.

    Replacing VLOOKUPs with Relationship Queries

    The real magic of SOQL lies in traversing relationships. In Excel, you use VLOOKUP to match an Account ID on a Contact sheet to fetch the Account Owner’s email. In SOQL, you traverse the relationship directly using dot notation (Parent Queries) or subqueries (Child Queries).

    Parent Relationship Queries (Child-to-Parent)

    When querying a child object (like Contact), you can traverse “up” to the parent object (Account) using dot notation.

    Excel approach: Export Contacts, Export Accounts, run =VLOOKUP(C2, Accounts!A:D, 4, FALSE).

    SOQL approach:

    SELECT Id, FirstName, LastName, Account.Name, Account.Owner.Email, Account.Industry 
    FROM Contact 
    WHERE Account.Rating = 'Hot'

    Notice how Account.Owner.Email reaches up three levels (Contact > Account > Owner) in a single query. No spreadsheets required.

    Rule of Thumb for Custom Objects: For custom lookup fields, change the __c to an __r. For example, if you have a custom lookup Building__c on Contact, query it as Building__r.Name.

    Child Relationship Queries (Parent-to-Child)

    What if you want to pull a list of Accounts alongside all of their related Opportunities?

    SOQL approach (Subquery):

    SELECT Id, Name, AnnualRevenue, 
           (SELECT Id, Name, Amount, StageName FROM Opportunities) 
    FROM Account 
    WHERE Type = 'Customer - Direct'

    This returns every Direct Customer Account and embeds an array of its related Opportunities right inside the record row.

    Enter Salesforce Inspector: The Admin’s Best Friend

    While you can run SOQL inside the native Salesforce Developer Console, Web Console or VS Code, the absolute best tool for admins is Salesforce Inspector (or its popular community extension, Salesforce Inspector Reloaded).

    Salesforce Web Console

    Salesforce Inspector is a browser extension (available for Chrome, Firefox, and Edge) that adds a subtle overlay tab to your browser when logged into Salesforce.

    Why Use Salesforce Inspector for SOQL?

    1. Instant Access: You don’t need to open Setup or launch a heavy development environment. Just click the overlay, select Data Export, and start typing.
    2. Auto-Completion: As you type your SOQL query, Salesforce Inspector auto-completes object and field API names in real time, saving you from constantly checking the Object Manager.
    3. One-Click Export Options: Once your query executes, you can instantly copy the results as CSV, Excel, or JSON.
    4. Direct Record Navigation: Record IDs in the Inspector results grid are clickable links. Want to inspect a returned Account? Just click its ID to open the record directly in Salesforce.
    5. Inline Data Cleanup: If you find bad data in your query results, Salesforce Inspector allows you to update or delete those records right from the tool interface.
    Salesforce Inspector Reloaded

    Practical SOQL Recipes for Admins

    To help you get started, here are three real-world administrative tasks solved with a simple SOQL query instead of complex reports or spreadsheets:

    Recipe 1: Find Active Users with No Assigned Permission Sets

    Find out which active users are missing a key organizational permission set.

    SELECT Id, Name, Email, Profile.Name 
    FROM User 
    WHERE IsActive = True 
      AND Id NOT IN (
          SELECT AssigneeId 
          FROM PermissionSetAssignment 
          WHERE PermissionSet.Name = 'Sales_Operations_Admin'
      )

    Recipe 2: Audit Contacts with Inconsistent Address Data

    Locate contacts where the mailing country is missing, but the parent Account has a billing country populated.

    SELECT Id, FirstName, LastName, MailingCountry, Account.Id, Account.Name, Account.BillingCountry 
    FROM Contact 
    WHERE MailingCountry = NULL 
      AND Account.BillingCountry != NULL

    Recipe 3: Aggregate Pipeline Metrics with GROUP BY and ORDER BY

    Want a quick summary of your pipeline grouped by lead source without building a summary report? Combine aggregate functions like SUM() and COUNT() with GROUP BY and ORDER BY.

    The GROUP BY clause works like a Pivot Table in Excel. It collapses individual records into summary rows based on shared values in a specific field. When you group by LeadSource, Salesforce automatically organizes all open opportunities into distinct buckets (like “Partner Referral” or “Web”) and calculates aggregate metrics such as COUNT(Id) for total deal volume and SUM(Amount) for total pipeline value for each bucket in a single clean table.

    SELECT LeadSource, COUNT(Id) TotalDeals, SUM(Amount) TotalPipeline 
    FROM Opportunity 
    WHERE IsClosed = False 
    GROUP BY LeadSource 
    ORDER BY SUM(Amount) DESC
    Salesforce Inspector Reloaded SOQL Query Results

    Become a More Efficient Salesforce Admin with SOQL

    Learning SOQL is about becoming a dramatically more efficient Administrator. Once you get comfortable writing basic SELECT … FROM … WHERE queries in Salesforce Inspector, you will find yourself relying less on complex Excel formulas and spending far less time building disposable one-off reports.

    Install Salesforce Inspector or spin up the Web Console initially in a sandbox org, and run your first query today. Your future self (and your spreadsheets) will thank you.

    Explore related content:

    Can You Use DML or SOQL Inside the Loop?

    Slack Code: AI Coding Agents Have Entered the Team Chat

    Setup with Agentforce: What Admins Can Actually Do Right Now

    #Chrome #Code #LowCode #SalesforceDeveloper #SalesforceHowTo #SalesforceTutorial #SOQL
  2. Is Hardcoding Ids a Good Idea in Salesforce Flows?

    Every Salesforce admin and developer has been tempted by the quick fix. You are building a Flow, and you need it to route an automated email to a specific queue, assign a task to a generic system user, or refer to a specific Record Type.

    You open the record in your browser, copy the 15- or 18-character string from the URL (0058W00000Gxxxx), paste it directly into a Flow text variable, and click Save. It works perfectly in your sandbox. You deploy it. Everything seems fine.

    There are many situations this approach fails, though.

    Hardcoding Ids is one of the most common anti-patterns in Salesforce development. While it feels harmless in the moment, it creates fragile automation that is prone to catastrophic failure during deployments. Let’s break down exactly why this happens, how Salesforce handles Ids across environments, and the best-practice alternatives you should use instead.

    The Root of the Problem: Data vs. Metadata

    To understand why hardcoding fails, we have to look at how Salesforce separates Metadata (the structural bones of your org such as Flow definitions, custom fields, and page layouts) from Data (the actual records living inside those structures, like Accounts, Contacts, Users, and Queues).

    When you deploy a Flow using a Change Set, DevOps Center, or a CLI tool, you are deploying metadata.

    If your Flow contains a hardcoded Id pointing to a specific User or Queue record, you are embedding a data reference directly inside your metadata. The deployment tools will happily move your Flow structure to the target environment. But if that exact target environment doesn’t contain a record with that identical 18-character Id string, your Flow will throw an unhandled fault the second it runs.

    Sandbox Creation: When Do Ids Match?

    A common point of confusion is how Ids behave when you spin up or refresh a sandbox from your Production environment. Do the Ids copy over? Are they the same?

    The answer depends entirely on whether you are looking at data or metadata, and what type of sandbox you are creating.

    Metadata Ids (Record Types, Queues, Roles, Profiles)

    When you create any sandbox from Production (Developer, Developer Pro, Partial Copy, or Full), Salesforce replicates your metadata layout.

    Record Type Ids and DeveloperName values will match between Production and the newly created sandbox because Record Types are metadata.

    Queue and Public Group Ids will also match initially because their structural definitions are pulled directly from Production.

    Data Ids (Users, Accounts, Custom Object Records)

    This is where things diverge significantly:

    • Full Sandboxes: A Full Sandbox copies all metadata and all data records from Production. Consequently, the record Ids for your Accounts, Contacts, and Users will match Production exactly upon creation.
    • Partial Copy Sandboxes: These copy a sample of your data based on a sandbox template. The records that are copied will retain their original Production Ids.
    • Developer and Developer Pro Sandboxes: These environments copy zero data records from Production (except for standard Setup data like Users). If you create a brand-new Account record in a Developer Sandbox to test your Flow, it will generate a brand-new, completely unique ID that has absolutely no relationship to Production.

    The Danger Zone: Disconnected Environments and Scratch Orgs

    Even if you use a Full Sandbox where data Ids match Production perfectly, relying on hardcoded Ids is still a ticking time bomb. The risk skyrockets when your deployment pipeline introduces disconnected environments or scratch orgs.

    If your team utilizes modern DevOps strategies such as Salesforce DX and Scratch Orgs, your environments are spun up completely from source code repository configurations.

    A scratch org has absolutely no data relationship to your Production environment. When a scratch org is built, it is a completely blank canvas.

    If your Flow expects a hardcoded User Id like 0058W00000Gxxxx to exist, it will instantly fail in the scratch org because that User simply does not exist. The same issue occurs if you have to manually recreate test records in a clean Developer sandbox; the text strings will never align across the pipeline.

    Furthermore, if a record is accidentally deleted in Production and recreated by an admin, it receives a brand-new Id. Your hardcoded Flow will instantly break, requiring an emergency deployment just to update a text string.

    Best Practices: How to Avoid Hardcoding Ids

    How do you build robust, environment-agnostic Flows that seamlessly transition from a scratch org to a sandbox, and ultimately to Production? Use these three reliable alternatives:

    Use the Get Records Element (The Gold Standard)

    Instead of hardcoding a Record Type Id or a Queue Id, use a Get Records element at the beginning of your Flow to query the system dynamically using a unique developer name.

    Instead of: Filtering a record variable by RecordTypeId Equals 0128W000001xxxx

    Do this: Add a Get Records element looking at the Record Type object where SobjectType Equals 'Account' and DeveloperName Equals 'Corporate_Account'. Then, reference the Id dynamically from that query step.

    Developer names are metadata; they remain identical across all environments, making your query 100% safe during deployment.

    Leverage Custom Labels or Custom Metadata Types

    If you must reference a specific system user or external integration Id that cannot be queried easily via a developer name, store that Id outside of the Flow.

    Create a Custom Metadata Type or a Custom Label (e.g., Default_Task_Assignee_ID).

    Populate the label with the sandbox-specific Id in your sandbox, and reference that label inside your Flow using global variables: {!$Label.Default_Task_Assignee_Id}.

    When you deploy the Flow, the metadata structure moves safely. You can then update the text value inside the Custom Label in Production manually or via deployment scripts without touching the core Flow logic.

    Custom Settings can also be used for this purpose depending on your use case.

    Use Global Variables for Profiles and Roles

    If your Flow needs to validate a user’s Profile or Role, avoid hardcoding the Profile Id. Salesforce provides global system variables that let you look at the running user’s contextual information directly:

    • {!$Profile.Name} (e.g., Equals System Administrator)
    • {!$UserRole.Name} (e.g., VP of Global Sales)

    Using names rather than hardcoded alphanumeric Ids ensures your logic remains readable, maintainable, and completely deployable.

    A Quick Tip on Roles: Just like hardcoding IDs, checking {!$UserRole.Name} directly in Flow logic can be risky if someone renames the Role in Setup. Where possible, checking Custom Permissions using {!$Permission.Your_Custom_Permission} is an even safer, more maintainable alternative!

    Read our post on custom permissions HERE.

    Stop Hardcoding Ids: Build Deployment-Safe Flows Instead

    Is hardcoding Ids ever a good idea? No. Never.

    While it might save you two minutes during initial development, it passes an invisible technical debt down the line to your future self or your deployment team. By taking the extra moment to implement a dynamic query or reference a Custom Metadata Type, you ensure your Screen and Record-Triggered Flows remain unbreakable, no matter how complex your sandbox ecosystem or deployment pipeline becomes.

    Explore related content:

    Salesforce Flow Best Practices

    Should You Use Roll Back Records in Salesforce Screen Flows?

    Unanimous Flow Approvals – No More Workarounds

    Open a Page Action: Redirect Users After a Screen Flow

    #BestPractices #Code #LowCode #SalesforceAdmin #SalesforceDeveloper #SalesforceHowTo #SalesforceTutorial