8

Is this possible? I would like to do the following directly:

Set<String> titles = new Set<String>([Select Title From SObject]); 
1
  • 3
    this functionality doesn't exist unfortunately. You will have to iterate over the list of SObjects and manually add the title fields to the set. Sep 5, 2018 at 14:15

3 Answers 3

14

No it is not possible except for Set<Id>. With other types, you need a for loop:

Set<String> names = new Set<String>();
for (MyObject__c record : [SELECT Name FROM MyObject__c])
    names.add(record.Name);

The special case is that with a record's own Id, you can use this Map constructor:

Set<Id> ids = new Map<Id, SObject>([/*query*/]).keySet();

You can abuse this shortcut and field alias functionality in aggregate queries to get a collection of parent Ids also.

Set<Id> parentIds = new Map<Id, SObject>([
    SELECT Parent__c Id FROM MyObject__c GROUP BY Parent__c
//                   ^^ you can now call .get('Id') on a result record
]).keySet();
6
  • Missing comma between Parent__c and Id in the SOQL query.
    – Tad
    Sep 5, 2018 at 17:15
  • 1
    No. That is the whole point of including that query. What it was actually missing is the GROUP BY clause.
    – Adrian Larson
    Sep 5, 2018 at 17:17
  • I don't understand. You're saying you intentionally left out the comma between Parent__c and Id in your example. This query as is won't work without a comma between the fields. SELECT Parent__c Id FROM MyObject__c GROUP BY Parent__c Adding a comma will make it work. SELECT Parent__c, Id FROM MyObject__c GROUP BY Parent__c If I'm not following then it might be that your explanation needs a bit more clarification as to why you left it out.
    – Tad
    Sep 5, 2018 at 17:20
  • 2
    I didn't leave anything out. I am not showing how to query two separate fields. I am using alias functionally.
    – Adrian Larson
    Sep 5, 2018 at 17:21
  • Ahhhh... I see now. My fault. Interesting solution.
    – Tad
    Sep 5, 2018 at 17:22
6

Expanding on Adrian's answer of using the aggregate field alias to unpack a parent Id into a Set.

Adrian's version:

Set<Id> parentIds = new Map<Id, SObject>([
    SELECT Parent__c Id FROM MyObject__c GROUP BY Parent__c
//                   ^^ you can now call .get('Id') on a result record
]).keySet();

I came across this expanded version by @mattandneil - Building a Set from any field

Matt's version:

Set<String> names = new Map<String,SObject>([
    SELECT Name Id
    FROM User
    GROUP BY Name
]).keySet();

The key different being that the aliased field doesn't actually have to be an Id. It could be a String, or Date. You just need to be able to GROUP BY it and adjust the map key accordingly.

As noted by the current Apex PM Chris Peterson, if you use this in production ensure that it is covered by Apex test cases that the hammer tests will see.

1
  • So this approach works for String and Date fields but no other types? Interesting.
    – Adrian Larson
    Apr 14 at 20:50
3

You can do it fairly easily for the Set of Id use case by passing the SOQL to the constructor of an Id to Sobject Map and then grabbing the keyset from this;-

Set<Id> Ids = new Map<Id, Sobject>([SELECT Id FROM SObject]).keySet();

Other than that though there isn't a direct way to do it for non-Id fields. Your best bet would probably to create a reusable worker method to handle this.

Depending on what you need this for aggregate SOQL functions may help as they will produce a list of all unique values for the aggregated field.

Set<String> titles = new Set<String>();
for(AggregateResult ar : [SELECT Title FROM SObject GROUP BY Title]){
   titles.add((String)ar.get('Title'));
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .