You do a sub-select, e.g:
Select Amount,CloseDate,Name, (Select PricebookEntry.Product2Id, TotalPrice, UnitPrice, ListPrice From OpportunityLineItems) From Opportunity WHERE StageName = 'Closed' ORDER BY Amount DESC NULLS LAST
Opportunity Products (OpportunityLineItem) is a Detail to the Master Opportunity, i.e. 1:n between Opportunity and Product lines. Products belong to a Pricebook, thus you have to traverse the PricebookEntry relationship to retrieve the Product ID (if you need it).
You can also query having OpportunityLineItem as the Primary object and referencing Opportuinty via the Opportunity relationship:
Select Select PricebookEntry.Product2Id, TotalPrice, Opportunity.Amount, Opportunity.CloseDate, Opportunity.Name From OpportunityLineItem WHERE Opportunity.StageName = 'Closed' ORDER BY Opportunity.Amount
You can't go directly from Product2 to Opportunity because there is no direct relationship between the two, i.e. the relationship is via PricebookEntry.
A useful tool in discovering relationships between objects is to use the Force.com Eclipse plugin. You can double click on the salesforce.schema item and it will open a GUI for building queries:
You should be able to do something like:
List<Contact> contacts = [
SELECT
Id, Name, Phone
FROM
Contact
WHERE
Id IN (
SELECT
ContactId
FROM
CampaignMember
WHERE
CampaignId = :campaignId AND ContactId != null
)
];
List<Lead> leads = [
SELECT
Id, Name, Phone
FROM
Lead
WHERE
Id IN (
SELECT
LeadId
FROM
CampaignMember
WHERE
CampaignId = :campaignId
AND LeadId != null
)
];
Best Answer
If you want all the child metadata, you can loop through the
getChildRelationships
results like so:If you want to get the child data, you'll need to build a dynamic query using the above results from the
getRelationshipName
method.Building dynamic queries in an elegant way is perhaps beyond the scope of this question. Below is a simple example of what it might look like.