Salesforce get all objects that changed after some date - salesforce

I would like to keep an updated copy of some salesforce data in a database.
e.g. a table with all contacts
However, it is impractical to truncate the table and to query all data again on a frequent basis.
Is there some way to only query changed contacts since the last sync?
e.g. I would run an hourly job that gets all contacts that changed within the last hour.
In addition, how could I deal with deleted contacts. I assume that if there is a way to get changed ones this might not include deletions.

To query all contacts modified since a particular date/time:
Datetime OneHourAgo = System.now().addHours(-1);
List<Contact> AllContactsModfiedSinceDateTimeX = [SELECT Id FROM Contact WHERE SystemModStamp >= : OneHourAgo];
Same query but including all deleted contacts:
Datetime OneHourAgo = System.now().addHours(-1);
List<Contact> AllDeletedContactsModfiedSinceDateTimeX = [SELECT Id FROM Contact WHERE SystemModStamp >= : OneHourAgo AND isDeleted = TRUE ALL ROWS]; //"ALL ROWS" must be included when using isDeleted = TRUE

Related

Look for records related to another related records within specific criteria

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;

Salesforce Apex Trigger - Calculate the sum of amount field values and update Opportunity field

My title for this post might be little confusing but i will try to make it as clear as possible. I am running into an issue with Apex trigger. We have a custom object called Receivables (Managed Packaged). Each Opportunity relates with one or more receivable record. Master Detailed Relationship is not an option since Receivable object is managed packaged.
Here is my logic:
Create a trigger on Opportunity (insert and/or update) > Loop all receivables which have matching id with triggered opportunity id and Receivable Opportunity field id (This is an Opportunity look up field in Receivables) >
Use aggregated to sum the amount > Auto Populate Total Commission field.
Trigger does not throw any error but it is not auto populating as well.
trigger newRecaivables on Opportunity (after insert, after update)
{
set<Id> oppid = new set<id>();
list<opportunity> opplist = [select id from opportunity where id in : oppid ];
for(Opportunity Opp : trigger.new)
{
List<aggregateResult> results = [select Fees_Received_Category__c ,sum(McaApp__Amount__c) total from McaApp__Receivable__c Where McaApp__Opportunity__c in:oppid group by Fees_Received_Category__c];
for(AggregateResult ar : results)
{
if (String.valueOf(ar.get('Fees_Received_Category__c'))=='Received')
{
Opp.Total_Commission__c = String.valueOf(ar.get('total'));
}
}
}
}
Any help would be appreciated.
Your trigger should fire on before insert, before update.
Since you're operating on the trigger.new enumeration, that will set the proper value when the object is either first created or updated separately.

Filtering issue with multiple forloop in apex | salesforce

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...

Salesforce - Apex - query accounts based on Activity History

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);
}
}

Salesforce:Add record to a field which is dependent on the input of other field

I have an object named 'Salary'. There are three fields in it- 'Add Salary', 'Month' and 'Available Salary'. Also there is a lookup relationship from Salary object to 'User Name' object. For every user there is a salary record for every month. Whenever salary is added to a particular user's record, the available salary should show the sum of salaries of previous months. How can I do that?? Please suggest me....Thanks.
The easiest way would be to change the Lookup Relationship to a Master-Detail Relationship and use a Roll-Up Summary field on the User object (Setup > Customize > Users > Fields > User Custom Fields > New).
Alternatively, you could use a Trigger on the Salary object, but only do that if you absolutely need additional functionality that cannot be accomplished with a Roll-Up Summary or other configuration.
Here's an example of using a Trigger. I haven't tried compiling it, so there will inevitably be some compile errors, but it's a place to start.
trigger AddSalary on Salary__c (after update) {
// create a set of all the unique User Ids
Map<Id,List<Salary__c>> SalaryByUserId = new Map<Id,List<Salary__c>>();
for(Salary__c s : Trigger.new)
{
List<Salary__c> SalariesForUser = SalaryByUserId.get(s.User__c);
if(SalariesForUser == null)
{
SalaryByUserId.put(s.User__c,new Salary__c[]{s});
}
else
{
SalariesForUser.add(s);
SalaryByUserId.put(s.User__c,SalariesForUser);
}
}
// query for all the User records for the unique UserIds in the records
// create a map for a lookup / hash table for the User info
Map<Id,User> Users = new Map<Id,User>(
[Select Id, Username, Available_Salary__c From User Where Id IN SalaryByUserId.keyset()]);
// iterate over the list of records being processed in the Trigger and add the Salaries to the Users
for (Id i : SalaryByUserId.keyset())
{
User u = Users.get(i);
Decimal TotalSalary = 0;
for(Salary__c s : SalaryByUserId.get(u.Id))
{
TotalSalary += s.Monthly_Salary__c;
}
Users.get(u.Id).Total_Salary__c = TotalSalary;
}
update Users;
}

Resources