SOQL query with subquery - salesforce

I'm having trouble getting the results I want from a Salesforce/Apex/SOQL query.
I want: A list of Contact objects containing only contacts who are CampaignMembers of a set of campaigns; and they should have the data from that Campaign member easily accessible.
(my eventual goal is a VF page with a list of all Contacts connected to any of these campaigns with a grid indicating their status for each campaign.)
These work:
Campaign[] cams = [SELECT id, name
FROM Campaign
WHERE parentid = '70170000000LRIe'];
System.debug(cams);
// returns ~4 Campaign objects
CampaignMember[] cmembers = [SELECT id, status, contactid, campaignid
FROM CampaignMember
WHERE campaignid in :cams];
System.debug(cmembers);
// returns about 40 CampaignMember objects.
Here's my problem:
Contact[] members = [SELECT id, firstname, lastname,
(SELECT id, status, comment__c, campaignid
FROM Contact.CampaignMembers
WHERE campaignid in :cams)
FROM Contact];
System.debug(members);
// contains ALL Contacts in the DB, but I wanted filtered results.
System.debug(members[x].CampaignMembers);
// this is a contact I've verified has a qualifying CampaignMember, but the list is empty.
// UPDATE: CampaignMembers are now being returned, not sure what changed...
Why aren't any CampaignMember objects being returned from the subquery?
Why isn't the Contact list being filtered? (well, obviously b/c there's no WHERE clause in it, but what WHERE clause provides what I want?)
I know I could do this by doing the CampaignMember query on its own and looping through it to prep a Contact query, but that seems like a lot of extra processing when a subquery should work.
Thanks!
Update
The CampaignMember objects are now showing up - oddly - I must have fixed some small typo without noticing (and yes, they're returning multiple columns and that seems to be fine).
I still can't figure out how to filter the Contact query, though...

You could use a semi-join on contacts to filter the contacts to the set you want, something like this
[select id, firstname, lastname,
(select id, status, comment__c, campaignid from CampaignMembers)
from contact where id in
(select contactId from campaignMember where campaignId in :cams];
Another option would be to drive from campaignMmeber instead.
[select contact.id, contact.firstname, contact.lastname,
status, comment__c, campaignId from campaignMembers
where contactId !='' and campaignId in :cams];

Related

Get Contact Emails of Currently Active Account as List

Given: A Salesforce user is viewing an account page.
Desired Output: All Emails of Contacts related to the Account currently viewed as a List object.
My code:
SELECT Email FROM Contact WHERE Id IN (SELECT ContactId FROM AccountContactRelation WHERE AccountId = ApexPages.CurrentPage.getParameters().get('id'))
This does not retrieve any results. When using a fixed number instead of ApexPages.CurrentPage.getParameters().get('id'), the Emails are correctly returned.
I'm sort of new to Apex. Could anyone point out what I am doing wrong?
To achieve the desired output you need to use SOQL variable injection.
You can do this by creating a variable first and then referencing the variable inside the SOQL using : and the variable name:
String theAccountId = ApexPages.CurrentPage.getParameters().get('id');
List<Contact> theContacts = [SELECT Email FROM Contact WHERE Id IN (SELECT ContactId FROM AccountContactRelation WHERE AccountId = :theAccountId)];
You can use a static query with a bind variable to retrieve the correct results.
Additionally, the Contact object contains an AccountId field of its own. Therefore, depending on your setup, you may be able to eliminate your subquery. You may also want to filter out Email fields that are empty, since Email is not a required field.
The complete result could look something like this:
String accountId = ApexPages.CurrentPage.getParameters().get('id');
List<Contact> accountContactsEmailList = [
SELECT
Email
FROM
Contact
WHERE
Email != ''
AND AccountId = :accountId
];
for (Contact contact : accountContactsEmailList) {
System.debug(contact.Email);
}

SOQL Account query for custom object related to opportunities

I'm trying to figure out how to query a custom object that is related to opportunities.
The object name is McaApp__Offer__c
The lookup field for that object is McaApp__Opportunity__c (master-detail)
This is what I have, but I'mk missing something as this object is not related to accounts, what do I need to change?
SELECT id, Name,
(
Select Id, Name From Opportunities ORDER BY Id DESC LIMIT 1
),
(
SELECT McaApp__Funder__c, McaApp__Status__c FROM McaApp__Offers__r WHERE McaApp__Opportunity__c = 'oppidxxx'
)
FROM Account
WHERE id = 'acctidxxx'
You can't query McaApp__Offer__c from within Account as there is no direct relationship. Account < Opportunity < McaApp__Offer__c this is how it realted.
SOQL statements cannot query aggregate relationships more than 1 level
away from the root entity object.
You can do like this.
SELECT Id, Name, AccountId,
(SELECT McaApp__Funder__c, McaApp__Status__c
FROM McaApp__Offers__r)
FROM Opportunity
WHERE AccountId = 'acctidxxx'
LIMIT 1

Attachments in Apex SOQL Subquery

I have custom objects Team member and Employment, and there's a lookup relationship from employment(many) to team member(one), plus another lookup record on team member called current employment.
The employment record may have attachments.
I want a SOQL query, to run in an APEX class, which will return attachments information for specific team members.
So far I have this:
SObject[] results = [select id,(select id,name from Attachments) from Employment__c where id in (select Current_Employment__c from Team_Member__c where id=:id)];
Wnen I run the query in the schema browser, it works OK and I'm able to drill-down to the attachments, but when I run it in Apex (Anonymous), the result set does not contain the attachments:
for (SObject result : results) {
System.debug(result);
}
I can only see the Employment id in the results.
How can I get attachments in APEX?
You do following to get list of attachment related to that object.
Employment__c[] results = [select id,(select id,name from Attachments) from Employment__c where id in (select Current_Employment__c from Team_Member__c where id=:id)];
for (Employment__c result : results) {
if(result.Attachments!=null){
List<Attachment> AttachmentList=result.Attachments;
}
}

Salesforce SOQL Filter by child relationship

I have the following simple query which shows I can access the field I want to filter by:
SELECT Id, Name, (SELECT HC4__IsSearchableExternally__c FROM Contacts)
FROM Account
However, what I really want to do is return only the Id and Name properties for Accounts that have at least one Contact where HC4__IsSearchableExternally__c is true. Is this possible to do with a Salesforce query?
Basically, I want to do something like the following (nonfunctional query):
SELECT Id, Name
FROM Account
WHERE (SELECT COUNT(Id) FROM Contacts WHERE HC4__IsSearchableExternally__c = true) > 0
Thanks for any help you can provide!
You can do this with a semi-join, e.g:
select id, name from account
where id in (select accountId from contact where HC4__IsSearchableExternally__c = true)

Soql query to get all related contacts of an account in an opportunity

i have SOQL query which queries for some records based on a where condition.
select id, name,account.name ... <other fields> from opportunity where eventname__c='Test Event'
i also need to get the related contact details for the account in the opportunity. ie i need to add the email ids of contact who all are part of the account in the opportunity.
For each opportunity, i need to get all the contacts emailids who are associated with the account in opportunity.
I cant really figure out how to approach this.
referring the documentation i can get the contact info of a account using the query
SELECT Name,
(
SELECT LastName
FROM Contacts
)
FROM Account
How can i use this along with opportunity?
Thanks
The problem is that you are trying to traverse up from opportunity to its parent (account) and then back down to the children (contacts).
I think you will have to do it in two stages, e.g. roughly like:
id[] accountids = new id[]{};
for (opportunity opp : [select accountid from opportunity where eventname__c='Test Event'])
{
accountids.add (opp.accountid);
}
account[] acclist = [select name, (select email from contacts) from account where id in :accountIds];

Resources