Hey Salesforce experts,
I have a question on query account information efficiently. I would like to query accounts based on the updates in an activityHistory object. The problem I'm getting is that all the accounts are being retrieved no matter if there's "complete" activeHistory or not. So, Is there a way I can write this query to retrieve only accounts with activeHistory that has status="complete" and Type_for_reporting='QRC'?
List<Account> AccountsWithActivityHistories = [
SELECT
Id
,Name
,( SELECT
ActivityDate
,ActivityType
,Type_for_Reporting__c
,Description
,CreatedBy.Name
,Status
,WhatId
FROM ActivityHistories
WHERE Status ='complete' and Type_for_Reporting__c = 'QRC'
)
FROM Account
];
You have a WHERE clause on the histories but you still miss one on the Account level.
For example this would return only Accounts that have Contacts:
SELECT Id, Name
FROM Account
WHERE Id IN (SELECT AccountId FROM Contact) // try with NOT IN too
With Activities it's trickier because they don't like to be used in WHERE in that way.
http://www.salesforce.com/us/developer/docs/officetoolkit/Content/sforce_api_calls_soql_select.htm
The following objects are not currently supported in subqueries:
ActivityHistory
Attachments
Event
EventAttendee
Note
OpenActivity
Tags (AccountTag, ContactTag, and all other tag objects)
Task
Additionally the fine print at the bottom of ActivityHistory definition is also a bit discouraging.
The following restrictions on users who don’t have “View All Data” permission help prevent performance issues:
In the main clause of the relationship query, you can reference only
one record. For example, you can’t filter on all records where the
account name starts with ‘A’; instead, you must reference a single
account record.
You can’t use WHERE clauses.
You must specify a limit of 499 or fewer on the number of rows returned in the list.
You must sort on ActivityDate in ascending order and LastModifiedDate in descending order; you can display nulls last. For
example: ORDER BY ActivityDate ASC NULLS LAST, LastModifiedDate DESC.
Looks like you will need multiple queries. Go for Task (or Event, depending for which the custom field is visible), compose a set of AccountIds and then query the Accounts?
Or you can manually filter through list from your original query, copying accounts to helper list:
List<Account> finalResults = new List<Account>();
for(Account a : [SELECT...]){
if(!a.ActivityHistories.isEmpty()){
finalResults.add(a);
}
}
Related
I am trying to create a SOQL query (and later a report) in Salesforce that generates the following data:
Count of Child records grouped by Parent records where the Parent does not have child records created in the past year.
I tried this first; however, salesforce returned an error stating 'Nesting of semi join sub-selects is not supported'.
SELECT Id, Name, Training_Course__c
FROM Training_Record__c
WHERE Training_Course__c IN (
SELECT Id
FROM Training_Course__c
WHERE Id NOT IN (
SELECT Training_Course__c
FROM Training_Record__c
WHERE CreatedDate != Last_n_Days:365
)
)
The requirements are to use a single query to obtain the data requested without forcing them to run two reports and use Excel to get the data. I'm not sure if that's possible given Salesforce's constraints.
Is this possible in SOQL? If so, what can I do differently?
This is not perfect but a decent start, you'd need to manually call count/size/length on the child records (exact method depends on your client application's language). In a SF report you can group by parent Id and call it a day. Read about "cross filters" in SF reports.
SELECT Id, Name,
(SELECT Id FROM Opportunities)
FROM Account
WHERE Id NOT IN (SELECT AccountId FROM Opportunity WHERE CloseDate = LAST_N_DAYS:365)
LIMIT 100
This will not compile:
SELECT AccountId, COUNT(Id)
FROM Opportunity
WHERE AccountId NOT IN (SELECT AccountId FROM Opportunity WHERE CloseDate = LAST_N_DAYS:365)
Error: The inner and outer selects should not be on the same object type
but if you really need something like that you could experiment, do it in 2 steps. Create helper field on account, tick the checkbox for eligible accs (with some nightly batch job maybe), then query based on that.
(normally you could do it with rollup summary field from opps to account but rollups have to be based on solid data, "deterministic". "LAST 365 DAYS", "TODAY" etc can't be used as rollup criteria)
I need a help in SOQL. I am new to this, so please bear with me.
I have to do a downwards traverse in SOQL.
SELECT Id, (SELECT Name from Contacts WHERE CreatedDate > YESTERDAY AND LastModifiedDate > YESTERDAY) from Account where CreatedDate > YESTERDAY AND LastModifiedDate > YESTERDAY
I want to get all records from Account and Contact where created date or last modified date is within a certain range. I want records where there are no changes in Account Object but changes are there in records in Contact Object.
But this query will not fetch any records if there are any changes in only Contact and no change in Account. How can I possibly do that.
Please help!
You're doing a Parent-Child SOQL query. The Contact subquery only matches Contacts associated with Accounts that match the primary query's filters.
You'll need to run one query on Account and a separate, non-relationship-based query on Contact.
Probably the following answer might help someone.
Query:
SELECT Id, Name, LastModifiedDate,(SELECT Name,LastModifiedDate from Contacts WHERE LastModifiedDate >= YESTERDAY) from Account where LastModifiedDate < YESTERDAY AND Id IN (SELECT AccountId FROM Contact WHERE LastModifiedDate >= YESTERDAY).
Explanation:
Assuming the certain range of date is yesterday, we want to retrieve all accounts that have contacts which are modified yesterday and after yesterday but the accounts should not have been modified in the above specified range.
The above query is parent-to-child query. In the sub-query we are checking for contacts that have been modified yesterday and after that. In the outer query we are checking that accounts that might have been modified before yesterday.
Now if we stop here and do not include the IN clause the results fetched will be a outer join that is along with required results it fetches accounts that have been modified before yesterday even if they do not have a contact that has been modified yesterday or after that. See attached pic. Outer Join results
So We have to include another check in the outer query ensuring that accounts that have contacts that have satisfied the specified date range are only returned and this is ensured using IN clause. See attached pic. Inner Join results.
Please mark this as useful if it helps.
Thanks
I am trying to created a set of records based on some criteria and i need to figure out the best way to do this.
I want to create a record for every object A and B that has an specific Account object. object A needs to have a status of "DONE", and B a status of "READY" in order to create the record (which will be an Object A with an "Active" status) the fields on the new Object A will copy from some of the Object A and B fields.
This is a process im not triggering from user action but a set of records i need to already dump in the database. I do have a sandbox to start working on and testing then rolling out.
Please let me know the easiest way to do this.
I appreciate the help!
You didn't provide enough info, we don't know how the relations look like. Are A and B related lists under Account? Are they independent or is there some link from one to another?
I'll write what I would do as a script (if needed you could make a batch job out of it or perhaps you'll be more comfortable with Data Loader, reports with cross filters, MS Excel and orgy of VLOOKUPs...)
To identify all "candidate" accounts you can try with this skeleton of a query
SELECT Id, Name
FROM Account
WHERE Id IN (SELECT Account__c FROM A__c WHERE Status__c = 'Done')
AND Id IN (SELECT Account__c FROM B__c WHERE Status__c = 'Ready')
LIMIT 10000
Now, the question about amounts of data. Will it return 10K (which is limit of records you can insert/update/modify in single transaction), if more - you might have to chunk it somehow... Maybe ORDER BY Id, record Id of last processed Account and in next iteration add AND Id > '001....'
Anyway, we got a "candidate", well, maybe he already has an Active A record, we wouldn't want to make a duplicate. And besides we need to pull some fields from B so they'd be copied across. So let's modify the query a bit, to add "subqueries" (think of them as related lists or LEFT INNER JOINs if that helps)
SELECT Id, Name,
(SELECT Id FROM As__r WHERE Status__c = 'Active' LIMIT 1),
(SELECT SomeField__c, SomeOtherField__c FROM Bs__r WHERE Status__c = 'Ready' LIMIT 1)
FROM Account
WHERE Id IN (SELECT Account__c FROM A__c WHERE Status__c = 'Done')
AND Id IN (SELECT Account__c FROM B__c WHERE Status__c = 'Ready')
LIMIT 10000
Nice. So now you need to loop through accounts, see if they contain that at least 1 active record (and if they do - skip). If they don't - create new one.
List<A__c> toInsert = new List<A__c>();
for(Account a : [SELECT...]){
if(a.As__r.isEmpty() && !a.Bs__r.isEmpty()){
toInsert.add(new A__c(
Account__c = a.Id,
Status__c = 'Active',
Foo__c = a.Bs__r[0].SomeField__c,
Bar__c = a.Bs__r[0].SomeOtherField__c + 7
));
}
}
insert toInsert;
I would like to use a SOQL Query to load what is displayed at a user record, what I want to get is the:
Permission Set Assignments Related list records
Public Group Membership Related list records
Queue Membership Related list Records
I am currently able to retrieve the permission set Related list records for a particular user but I am unable to get the public group and the queue membership related list records,
Here is my query:
SELECT Id, name, (select PermissionSet.Name, AssigneeId
FROM PermissionSetAssignments) from user
Could you please help me adding the missing part in the query to get the queues and the public groups,
Thanks for your help.
You will not get Public group and Queue membership details directly from user object. You need additional query.
SELECT Id, GroupId, UserOrGroupId
FROM GroupMember
WHERE UserOrGroupId IN (SELECT Id FROM User)
Since queue is a public group you don't need additional query to get queue membership. This single query is enough.
I have a scenario where multiple loopings are causing the system resource error.
I need some help with map of map syntax or coding sample for this requirement.
Requirement is:
Account has 1 or more ReportCard records.
ReportCard has Account and Contact.
Now i need to get the list of ReportCards and filter by 1 per contact and recently created records only.
If ReportCard has 2 records with same contact, include only recently created.
// get list of unique accounts from the set
list<Account> accList = new list<Account >([SELECT Id,Average_of_Pulse_Check_Recommend_Score_N__c,Average_of_Recommend_Score_Lanyon_N__c,Average_of_Touchpoint_Recommend_Score_N__c,Average_of_Touch_Point_Satisfaction_N__c FROM Account WHERE Id in:AccIds]);
list<ReportCard__c> allRCList = new list<ReportCard__c>([SELECT Id,Net_Promoter_text__c,CreatedDate, Contact__c, Account__c, RecordTypeID, Touchpoint_Satisfaction_text__c FROM ReportCard__c WHERE Account__c in:accList Order By Account__c, CreatedDate Desc]);
List<ReportCard__c> rcListbyAccounts = new List<ReportCard__c>();
for(Account acc:accList)
{
Any help would be appreciated.
Thanks
I'm not sure I understand your situation correctly. You've skipped the for loop - I strongly suspect any issues you have there sit in the loop rather than in the queries.
Looks like you should read about using relationship queries (salesforce versions of JOIN in regular database): http://www.salesforce.com/us/developer/docs/soql_sosl/Content/sforce_api_calls_soql_relationships.htm
Pay special attention to subqueries (which behave similar to how a related list behaves on record's detail page).
From what I see I'd say you don't need to query for Accounts at all, or at least not like that. This will work equally well:
SELECT Id,Net_Promoter_text__c,CreatedDate, Contact__c, Account__c, ...
FROM ReportCard__c
WHERE Account__c in:accIds
ORDER BY Account__c, CreatedDate Desc
Now lets attack this:
List of ReportCards and filter by 1 per contact and recently created
records only. If ReportCard has 2 records with same contact, include
only recently created.
I'd reverse it - I'd start the query from Contact level, go down to the related list of Report Cards and pick the latest one. That way it eliminates the issue with duplicate contacts for you. Something like this:
SELECT Id, Name, Email,
(SELECT Id, Net_Promoter_text__c, CreatedDate, Account__c, Account__r.Name, Account__r.Average_of_Pulse_Check_Recommend_Score_N__c
FROM ReportCards__r
WHERE Account__c IN :accIds
ORDER BY CreatedDate DESC
LIMIT 1)
FROM Contact
WHERE AccountId IN :accIds
This goes from Contact "down" to Report Cards (via the relationship name ReportCards__r) and then "up" from Card to Account via Account__r.Name, Account__r.Average_of_Pulse_Check_Recommend_Score_N__c...