Query Limit on Batchable Class
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty{ margin-bottom:0;
}
up vote
1
down vote
favorite
What is the best practice with governor limits with Batchable classes and queries inside of the Batchable class?
I am running into query limits with a Batchable
class because I have too many AggregateResult
queries. I have a query that returns 100 results and I need to run 3 SUM()
queries on each one of those results. I add each record into a list and do one update at the end. This will be called from a scheduler twice a day so I don't want to have to limit the returned results.
I am not sure how to handle this. Does anyone have any suggestions?
global class PaymentAgreementMonitor implements Database.Batchable<sObject> {
global Database.QueryLocator start(Database.BatchableContext BC){
//Query for all Payment Agreements where Status = Active
String status = 'Active';
String Query = 'SELECT Id, Balance_Paid__c, Total_Expected_Balance_Today__c, Ownership__c,Recovery__c,Start_Date__c,Matter__c,' +
'Contingency_Payout_Method__c, Balance_Paid_Last_Updated__c FROM Payment_Agreement__c WHERE Status__c ='' + status + ''';
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<Payment_Agreement__c> scope){
system.debug('scope:: ' + scope);
scheduler(scope);
}
global void finish(Database.BatchableContext BC){
system.debug('finished batchable PaymentAgreementSchedule');
}
public static void scheduler(List<Payment_Agreement__c> payment_agreements){
List<Id>paListError = new List<Id>();
List<Payment_Agreement__c> paList = new List<Payment_Agreement__c>();
for (Payment_Agreement__c pa : payment_agreements) {
for(AggregateResult schPay : [SELECT SUM(Amount__c)sumAmt
FROM Scheduled_Payment__c
WHERE Payment_Agreement__c = :pa.Id
AND Scheduled_Date__c <=TODAY AND Amount__c != NULL]){
Decimal decimalAmount = (Decimal)schPay.get('sumAmt');
if(decimalAmount !=null) {
pa.Total_Expected_Balance_Today__c = math.abs(decimalAmount); }
}
Decimal decimalAmount;
for(AggregateResult schPay : [SELECT SUM(Amount__c)sumAmt
FROM Recovery_Payment__c
WHERE Recovery__c = :pa.Recovery__c
AND Date__c >= :pa.Start_Date__c]) {
decimalAmount = (Decimal)schPay.get('sumAmt');
}
//Calculate and insert the value for current Balance_Paid__c
if (pa.Ownership__c == 'In House') {
if(decimalAmount != null) {
pa.Balance_Paid_Last_Updated__c = DateTime.now();
pa.Balance_Paid__c = math.abs(decimalAmount);
}
} else if (pa.Ownership__c == 'Local Counsel' && pa.Contingency_Payout_Method__c == 'Contingency Paid to Local Counsel') {
if(decimalAmount != null) {
pa.Balance_Paid_Last_Updated__c = DateTime.now();
pa.Balance_Paid__c = math.abs(decimalAmount);
system.debug('Payment Agreement Contigency Paiid to Local Counsel -Balance_Paid__c:: ' + pa.Balance_Paid__c);
}
} else if (pa.Ownership__c == 'Local Counsel' && pa.Contingency_Payout_Method__c == 'Net Paid to National Funding') {
Decimal sumAverageRecoveryPaymentsLocalNF = 0;
Decimal sumAverageExpenseAmount = 0;
if(decimalAmount != null) {
sumAverageRecoveryPaymentsLocalNF = decimalAmount ;
}
for(AggregateResult schPay : [SELECT SUM(advpm__Expense_Amount__c)sumExp
FROM advpm__Expense__c
WHERE advpm__Matter__c = :pa.Matter__c
AND advpm__Category__c = 'Contingency Fees']){
Decimal sumExpenseDecimal = (Decimal)schPay.get('sumExp');
if(decimalAmount != null){
sumAverageExpenseAmount = math.abs(sumExpenseDecimal);
}
}
Decimal sumRecoveryAndExpenses = sumAverageExpenseAmount + sumAverageRecoveryPaymentsLocalNF;
if(sumRecoveryAndExpenses != 0){
pa.Balance_Paid_Last_Updated__c = DateTime.now();
pa.Balance_Paid__c = math.abs(sumRecoveryAndExpenses);
}
} else{
pa.Total_Expected_Balance_Today__c = null;
pa.Balance_Paid_Last_Updated__c = null;
paListError.add(pa.Id);
}
paList.add(pa);
}
if(paListError.size() > 0 ){
NFLogger.logError('PaymentAgreementMonitor.cls', 'Payment Agreement record(s): ' + paListError + ' have incorrect data in Ownership__c or Contingency_Payout_Method__c fields.');
}
update paList;
}
}
apex batch scheduled-apex governorlimits schedulebatch
add a comment |
up vote
1
down vote
favorite
What is the best practice with governor limits with Batchable classes and queries inside of the Batchable class?
I am running into query limits with a Batchable
class because I have too many AggregateResult
queries. I have a query that returns 100 results and I need to run 3 SUM()
queries on each one of those results. I add each record into a list and do one update at the end. This will be called from a scheduler twice a day so I don't want to have to limit the returned results.
I am not sure how to handle this. Does anyone have any suggestions?
global class PaymentAgreementMonitor implements Database.Batchable<sObject> {
global Database.QueryLocator start(Database.BatchableContext BC){
//Query for all Payment Agreements where Status = Active
String status = 'Active';
String Query = 'SELECT Id, Balance_Paid__c, Total_Expected_Balance_Today__c, Ownership__c,Recovery__c,Start_Date__c,Matter__c,' +
'Contingency_Payout_Method__c, Balance_Paid_Last_Updated__c FROM Payment_Agreement__c WHERE Status__c ='' + status + ''';
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<Payment_Agreement__c> scope){
system.debug('scope:: ' + scope);
scheduler(scope);
}
global void finish(Database.BatchableContext BC){
system.debug('finished batchable PaymentAgreementSchedule');
}
public static void scheduler(List<Payment_Agreement__c> payment_agreements){
List<Id>paListError = new List<Id>();
List<Payment_Agreement__c> paList = new List<Payment_Agreement__c>();
for (Payment_Agreement__c pa : payment_agreements) {
for(AggregateResult schPay : [SELECT SUM(Amount__c)sumAmt
FROM Scheduled_Payment__c
WHERE Payment_Agreement__c = :pa.Id
AND Scheduled_Date__c <=TODAY AND Amount__c != NULL]){
Decimal decimalAmount = (Decimal)schPay.get('sumAmt');
if(decimalAmount !=null) {
pa.Total_Expected_Balance_Today__c = math.abs(decimalAmount); }
}
Decimal decimalAmount;
for(AggregateResult schPay : [SELECT SUM(Amount__c)sumAmt
FROM Recovery_Payment__c
WHERE Recovery__c = :pa.Recovery__c
AND Date__c >= :pa.Start_Date__c]) {
decimalAmount = (Decimal)schPay.get('sumAmt');
}
//Calculate and insert the value for current Balance_Paid__c
if (pa.Ownership__c == 'In House') {
if(decimalAmount != null) {
pa.Balance_Paid_Last_Updated__c = DateTime.now();
pa.Balance_Paid__c = math.abs(decimalAmount);
}
} else if (pa.Ownership__c == 'Local Counsel' && pa.Contingency_Payout_Method__c == 'Contingency Paid to Local Counsel') {
if(decimalAmount != null) {
pa.Balance_Paid_Last_Updated__c = DateTime.now();
pa.Balance_Paid__c = math.abs(decimalAmount);
system.debug('Payment Agreement Contigency Paiid to Local Counsel -Balance_Paid__c:: ' + pa.Balance_Paid__c);
}
} else if (pa.Ownership__c == 'Local Counsel' && pa.Contingency_Payout_Method__c == 'Net Paid to National Funding') {
Decimal sumAverageRecoveryPaymentsLocalNF = 0;
Decimal sumAverageExpenseAmount = 0;
if(decimalAmount != null) {
sumAverageRecoveryPaymentsLocalNF = decimalAmount ;
}
for(AggregateResult schPay : [SELECT SUM(advpm__Expense_Amount__c)sumExp
FROM advpm__Expense__c
WHERE advpm__Matter__c = :pa.Matter__c
AND advpm__Category__c = 'Contingency Fees']){
Decimal sumExpenseDecimal = (Decimal)schPay.get('sumExp');
if(decimalAmount != null){
sumAverageExpenseAmount = math.abs(sumExpenseDecimal);
}
}
Decimal sumRecoveryAndExpenses = sumAverageExpenseAmount + sumAverageRecoveryPaymentsLocalNF;
if(sumRecoveryAndExpenses != 0){
pa.Balance_Paid_Last_Updated__c = DateTime.now();
pa.Balance_Paid__c = math.abs(sumRecoveryAndExpenses);
}
} else{
pa.Total_Expected_Balance_Today__c = null;
pa.Balance_Paid_Last_Updated__c = null;
paListError.add(pa.Id);
}
paList.add(pa);
}
if(paListError.size() > 0 ){
NFLogger.logError('PaymentAgreementMonitor.cls', 'Payment Agreement record(s): ' + paListError + ' have incorrect data in Ownership__c or Contingency_Payout_Method__c fields.');
}
update paList;
}
}
apex batch scheduled-apex governorlimits schedulebatch
Can the recovery Date be ever less that start date of Payment_Agreement__c?
– Pranay Jaiswal
4 hours ago
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
What is the best practice with governor limits with Batchable classes and queries inside of the Batchable class?
I am running into query limits with a Batchable
class because I have too many AggregateResult
queries. I have a query that returns 100 results and I need to run 3 SUM()
queries on each one of those results. I add each record into a list and do one update at the end. This will be called from a scheduler twice a day so I don't want to have to limit the returned results.
I am not sure how to handle this. Does anyone have any suggestions?
global class PaymentAgreementMonitor implements Database.Batchable<sObject> {
global Database.QueryLocator start(Database.BatchableContext BC){
//Query for all Payment Agreements where Status = Active
String status = 'Active';
String Query = 'SELECT Id, Balance_Paid__c, Total_Expected_Balance_Today__c, Ownership__c,Recovery__c,Start_Date__c,Matter__c,' +
'Contingency_Payout_Method__c, Balance_Paid_Last_Updated__c FROM Payment_Agreement__c WHERE Status__c ='' + status + ''';
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<Payment_Agreement__c> scope){
system.debug('scope:: ' + scope);
scheduler(scope);
}
global void finish(Database.BatchableContext BC){
system.debug('finished batchable PaymentAgreementSchedule');
}
public static void scheduler(List<Payment_Agreement__c> payment_agreements){
List<Id>paListError = new List<Id>();
List<Payment_Agreement__c> paList = new List<Payment_Agreement__c>();
for (Payment_Agreement__c pa : payment_agreements) {
for(AggregateResult schPay : [SELECT SUM(Amount__c)sumAmt
FROM Scheduled_Payment__c
WHERE Payment_Agreement__c = :pa.Id
AND Scheduled_Date__c <=TODAY AND Amount__c != NULL]){
Decimal decimalAmount = (Decimal)schPay.get('sumAmt');
if(decimalAmount !=null) {
pa.Total_Expected_Balance_Today__c = math.abs(decimalAmount); }
}
Decimal decimalAmount;
for(AggregateResult schPay : [SELECT SUM(Amount__c)sumAmt
FROM Recovery_Payment__c
WHERE Recovery__c = :pa.Recovery__c
AND Date__c >= :pa.Start_Date__c]) {
decimalAmount = (Decimal)schPay.get('sumAmt');
}
//Calculate and insert the value for current Balance_Paid__c
if (pa.Ownership__c == 'In House') {
if(decimalAmount != null) {
pa.Balance_Paid_Last_Updated__c = DateTime.now();
pa.Balance_Paid__c = math.abs(decimalAmount);
}
} else if (pa.Ownership__c == 'Local Counsel' && pa.Contingency_Payout_Method__c == 'Contingency Paid to Local Counsel') {
if(decimalAmount != null) {
pa.Balance_Paid_Last_Updated__c = DateTime.now();
pa.Balance_Paid__c = math.abs(decimalAmount);
system.debug('Payment Agreement Contigency Paiid to Local Counsel -Balance_Paid__c:: ' + pa.Balance_Paid__c);
}
} else if (pa.Ownership__c == 'Local Counsel' && pa.Contingency_Payout_Method__c == 'Net Paid to National Funding') {
Decimal sumAverageRecoveryPaymentsLocalNF = 0;
Decimal sumAverageExpenseAmount = 0;
if(decimalAmount != null) {
sumAverageRecoveryPaymentsLocalNF = decimalAmount ;
}
for(AggregateResult schPay : [SELECT SUM(advpm__Expense_Amount__c)sumExp
FROM advpm__Expense__c
WHERE advpm__Matter__c = :pa.Matter__c
AND advpm__Category__c = 'Contingency Fees']){
Decimal sumExpenseDecimal = (Decimal)schPay.get('sumExp');
if(decimalAmount != null){
sumAverageExpenseAmount = math.abs(sumExpenseDecimal);
}
}
Decimal sumRecoveryAndExpenses = sumAverageExpenseAmount + sumAverageRecoveryPaymentsLocalNF;
if(sumRecoveryAndExpenses != 0){
pa.Balance_Paid_Last_Updated__c = DateTime.now();
pa.Balance_Paid__c = math.abs(sumRecoveryAndExpenses);
}
} else{
pa.Total_Expected_Balance_Today__c = null;
pa.Balance_Paid_Last_Updated__c = null;
paListError.add(pa.Id);
}
paList.add(pa);
}
if(paListError.size() > 0 ){
NFLogger.logError('PaymentAgreementMonitor.cls', 'Payment Agreement record(s): ' + paListError + ' have incorrect data in Ownership__c or Contingency_Payout_Method__c fields.');
}
update paList;
}
}
apex batch scheduled-apex governorlimits schedulebatch
What is the best practice with governor limits with Batchable classes and queries inside of the Batchable class?
I am running into query limits with a Batchable
class because I have too many AggregateResult
queries. I have a query that returns 100 results and I need to run 3 SUM()
queries on each one of those results. I add each record into a list and do one update at the end. This will be called from a scheduler twice a day so I don't want to have to limit the returned results.
I am not sure how to handle this. Does anyone have any suggestions?
global class PaymentAgreementMonitor implements Database.Batchable<sObject> {
global Database.QueryLocator start(Database.BatchableContext BC){
//Query for all Payment Agreements where Status = Active
String status = 'Active';
String Query = 'SELECT Id, Balance_Paid__c, Total_Expected_Balance_Today__c, Ownership__c,Recovery__c,Start_Date__c,Matter__c,' +
'Contingency_Payout_Method__c, Balance_Paid_Last_Updated__c FROM Payment_Agreement__c WHERE Status__c ='' + status + ''';
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<Payment_Agreement__c> scope){
system.debug('scope:: ' + scope);
scheduler(scope);
}
global void finish(Database.BatchableContext BC){
system.debug('finished batchable PaymentAgreementSchedule');
}
public static void scheduler(List<Payment_Agreement__c> payment_agreements){
List<Id>paListError = new List<Id>();
List<Payment_Agreement__c> paList = new List<Payment_Agreement__c>();
for (Payment_Agreement__c pa : payment_agreements) {
for(AggregateResult schPay : [SELECT SUM(Amount__c)sumAmt
FROM Scheduled_Payment__c
WHERE Payment_Agreement__c = :pa.Id
AND Scheduled_Date__c <=TODAY AND Amount__c != NULL]){
Decimal decimalAmount = (Decimal)schPay.get('sumAmt');
if(decimalAmount !=null) {
pa.Total_Expected_Balance_Today__c = math.abs(decimalAmount); }
}
Decimal decimalAmount;
for(AggregateResult schPay : [SELECT SUM(Amount__c)sumAmt
FROM Recovery_Payment__c
WHERE Recovery__c = :pa.Recovery__c
AND Date__c >= :pa.Start_Date__c]) {
decimalAmount = (Decimal)schPay.get('sumAmt');
}
//Calculate and insert the value for current Balance_Paid__c
if (pa.Ownership__c == 'In House') {
if(decimalAmount != null) {
pa.Balance_Paid_Last_Updated__c = DateTime.now();
pa.Balance_Paid__c = math.abs(decimalAmount);
}
} else if (pa.Ownership__c == 'Local Counsel' && pa.Contingency_Payout_Method__c == 'Contingency Paid to Local Counsel') {
if(decimalAmount != null) {
pa.Balance_Paid_Last_Updated__c = DateTime.now();
pa.Balance_Paid__c = math.abs(decimalAmount);
system.debug('Payment Agreement Contigency Paiid to Local Counsel -Balance_Paid__c:: ' + pa.Balance_Paid__c);
}
} else if (pa.Ownership__c == 'Local Counsel' && pa.Contingency_Payout_Method__c == 'Net Paid to National Funding') {
Decimal sumAverageRecoveryPaymentsLocalNF = 0;
Decimal sumAverageExpenseAmount = 0;
if(decimalAmount != null) {
sumAverageRecoveryPaymentsLocalNF = decimalAmount ;
}
for(AggregateResult schPay : [SELECT SUM(advpm__Expense_Amount__c)sumExp
FROM advpm__Expense__c
WHERE advpm__Matter__c = :pa.Matter__c
AND advpm__Category__c = 'Contingency Fees']){
Decimal sumExpenseDecimal = (Decimal)schPay.get('sumExp');
if(decimalAmount != null){
sumAverageExpenseAmount = math.abs(sumExpenseDecimal);
}
}
Decimal sumRecoveryAndExpenses = sumAverageExpenseAmount + sumAverageRecoveryPaymentsLocalNF;
if(sumRecoveryAndExpenses != 0){
pa.Balance_Paid_Last_Updated__c = DateTime.now();
pa.Balance_Paid__c = math.abs(sumRecoveryAndExpenses);
}
} else{
pa.Total_Expected_Balance_Today__c = null;
pa.Balance_Paid_Last_Updated__c = null;
paListError.add(pa.Id);
}
paList.add(pa);
}
if(paListError.size() > 0 ){
NFLogger.logError('PaymentAgreementMonitor.cls', 'Payment Agreement record(s): ' + paListError + ' have incorrect data in Ownership__c or Contingency_Payout_Method__c fields.');
}
update paList;
}
}
apex batch scheduled-apex governorlimits schedulebatch
apex batch scheduled-apex governorlimits schedulebatch
asked 4 hours ago
Olivia
1,252420
1,252420
Can the recovery Date be ever less that start date of Payment_Agreement__c?
– Pranay Jaiswal
4 hours ago
add a comment |
Can the recovery Date be ever less that start date of Payment_Agreement__c?
– Pranay Jaiswal
4 hours ago
Can the recovery Date be ever less that start date of Payment_Agreement__c?
– Pranay Jaiswal
4 hours ago
Can the recovery Date be ever less that start date of Payment_Agreement__c?
– Pranay Jaiswal
4 hours ago
add a comment |
1 Answer
1
active
oldest
votes
up vote
4
down vote
You do not need to query these aggregates within your loops. It's not really any different than most other queries, with one notable exception: with aggregate queries you can use field alias functionality to use the built in Map<Id, SObject>(List<SObject>)
constructor.
Map<Id, AggregateResult> scheduledPayments = new Map<Id, AggregateResult([
SELECT SUM(Amount__c) amount, Payment_Agreement__c Id
FROM Scheduled_Payment__c
WHERE Payment_Agreement__c IN :payment_agreements
AND Scheduled_Date__c <=TODAY AND Amount__c != NULL
GROUP BY Payment_Agreement__c
]);
for (Payment_Agreement__c record : payment_agreements)
{
Decimal amount;
AggregateResult scheduledPayment = scheduledPayments.get(record.Id);
if (scheduledPayment != null)
{
amount = (Decimal)scheduledPayment.get('amount');
}
if (amount != null)
{
// further logic here
}
}
The process will be quite similar for your other aggregations, with the exception of your Start_Date__c
filtering, which will involve a bit more thought. You may want to look at pre-computing that value as a rollup via trigger.
this is a good idea but I am concerned that if I bring in 200 records, then I can only have one query in the entire method. Would a better route be to write some handling withgetQueries()
and if we are at 199 then I would add the rest of the record Ids to a list, exit the method, and some how run the process again on the list? I am not entirely sure I will execute this, but something along those lines.
– Olivia
3 hours ago
You're over thinking it. For the queries where you filter onId
, you can run one query to get all of the data.
– Adrian Larson♦
3 hours ago
I am not entirely sure how I would achieve that with my query on advpm__Expense__c and Recovery_Payment__c as I am not just querying on ID.
– Olivia
3 hours ago
@Olivia You can group by and filter by multiple filters. AggregateResult example, as shown by Adrian here, means you can take the queries out of the loops you have. Also, you need an update map so you can associate the values with the records correctly. More maps, less lists.
– sfdcfox
24 mins ago
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
You do not need to query these aggregates within your loops. It's not really any different than most other queries, with one notable exception: with aggregate queries you can use field alias functionality to use the built in Map<Id, SObject>(List<SObject>)
constructor.
Map<Id, AggregateResult> scheduledPayments = new Map<Id, AggregateResult([
SELECT SUM(Amount__c) amount, Payment_Agreement__c Id
FROM Scheduled_Payment__c
WHERE Payment_Agreement__c IN :payment_agreements
AND Scheduled_Date__c <=TODAY AND Amount__c != NULL
GROUP BY Payment_Agreement__c
]);
for (Payment_Agreement__c record : payment_agreements)
{
Decimal amount;
AggregateResult scheduledPayment = scheduledPayments.get(record.Id);
if (scheduledPayment != null)
{
amount = (Decimal)scheduledPayment.get('amount');
}
if (amount != null)
{
// further logic here
}
}
The process will be quite similar for your other aggregations, with the exception of your Start_Date__c
filtering, which will involve a bit more thought. You may want to look at pre-computing that value as a rollup via trigger.
this is a good idea but I am concerned that if I bring in 200 records, then I can only have one query in the entire method. Would a better route be to write some handling withgetQueries()
and if we are at 199 then I would add the rest of the record Ids to a list, exit the method, and some how run the process again on the list? I am not entirely sure I will execute this, but something along those lines.
– Olivia
3 hours ago
You're over thinking it. For the queries where you filter onId
, you can run one query to get all of the data.
– Adrian Larson♦
3 hours ago
I am not entirely sure how I would achieve that with my query on advpm__Expense__c and Recovery_Payment__c as I am not just querying on ID.
– Olivia
3 hours ago
@Olivia You can group by and filter by multiple filters. AggregateResult example, as shown by Adrian here, means you can take the queries out of the loops you have. Also, you need an update map so you can associate the values with the records correctly. More maps, less lists.
– sfdcfox
24 mins ago
add a comment |
up vote
4
down vote
You do not need to query these aggregates within your loops. It's not really any different than most other queries, with one notable exception: with aggregate queries you can use field alias functionality to use the built in Map<Id, SObject>(List<SObject>)
constructor.
Map<Id, AggregateResult> scheduledPayments = new Map<Id, AggregateResult([
SELECT SUM(Amount__c) amount, Payment_Agreement__c Id
FROM Scheduled_Payment__c
WHERE Payment_Agreement__c IN :payment_agreements
AND Scheduled_Date__c <=TODAY AND Amount__c != NULL
GROUP BY Payment_Agreement__c
]);
for (Payment_Agreement__c record : payment_agreements)
{
Decimal amount;
AggregateResult scheduledPayment = scheduledPayments.get(record.Id);
if (scheduledPayment != null)
{
amount = (Decimal)scheduledPayment.get('amount');
}
if (amount != null)
{
// further logic here
}
}
The process will be quite similar for your other aggregations, with the exception of your Start_Date__c
filtering, which will involve a bit more thought. You may want to look at pre-computing that value as a rollup via trigger.
this is a good idea but I am concerned that if I bring in 200 records, then I can only have one query in the entire method. Would a better route be to write some handling withgetQueries()
and if we are at 199 then I would add the rest of the record Ids to a list, exit the method, and some how run the process again on the list? I am not entirely sure I will execute this, but something along those lines.
– Olivia
3 hours ago
You're over thinking it. For the queries where you filter onId
, you can run one query to get all of the data.
– Adrian Larson♦
3 hours ago
I am not entirely sure how I would achieve that with my query on advpm__Expense__c and Recovery_Payment__c as I am not just querying on ID.
– Olivia
3 hours ago
@Olivia You can group by and filter by multiple filters. AggregateResult example, as shown by Adrian here, means you can take the queries out of the loops you have. Also, you need an update map so you can associate the values with the records correctly. More maps, less lists.
– sfdcfox
24 mins ago
add a comment |
up vote
4
down vote
up vote
4
down vote
You do not need to query these aggregates within your loops. It's not really any different than most other queries, with one notable exception: with aggregate queries you can use field alias functionality to use the built in Map<Id, SObject>(List<SObject>)
constructor.
Map<Id, AggregateResult> scheduledPayments = new Map<Id, AggregateResult([
SELECT SUM(Amount__c) amount, Payment_Agreement__c Id
FROM Scheduled_Payment__c
WHERE Payment_Agreement__c IN :payment_agreements
AND Scheduled_Date__c <=TODAY AND Amount__c != NULL
GROUP BY Payment_Agreement__c
]);
for (Payment_Agreement__c record : payment_agreements)
{
Decimal amount;
AggregateResult scheduledPayment = scheduledPayments.get(record.Id);
if (scheduledPayment != null)
{
amount = (Decimal)scheduledPayment.get('amount');
}
if (amount != null)
{
// further logic here
}
}
The process will be quite similar for your other aggregations, with the exception of your Start_Date__c
filtering, which will involve a bit more thought. You may want to look at pre-computing that value as a rollup via trigger.
You do not need to query these aggregates within your loops. It's not really any different than most other queries, with one notable exception: with aggregate queries you can use field alias functionality to use the built in Map<Id, SObject>(List<SObject>)
constructor.
Map<Id, AggregateResult> scheduledPayments = new Map<Id, AggregateResult([
SELECT SUM(Amount__c) amount, Payment_Agreement__c Id
FROM Scheduled_Payment__c
WHERE Payment_Agreement__c IN :payment_agreements
AND Scheduled_Date__c <=TODAY AND Amount__c != NULL
GROUP BY Payment_Agreement__c
]);
for (Payment_Agreement__c record : payment_agreements)
{
Decimal amount;
AggregateResult scheduledPayment = scheduledPayments.get(record.Id);
if (scheduledPayment != null)
{
amount = (Decimal)scheduledPayment.get('amount');
}
if (amount != null)
{
// further logic here
}
}
The process will be quite similar for your other aggregations, with the exception of your Start_Date__c
filtering, which will involve a bit more thought. You may want to look at pre-computing that value as a rollup via trigger.
answered 4 hours ago
Adrian Larson♦
103k19111233
103k19111233
this is a good idea but I am concerned that if I bring in 200 records, then I can only have one query in the entire method. Would a better route be to write some handling withgetQueries()
and if we are at 199 then I would add the rest of the record Ids to a list, exit the method, and some how run the process again on the list? I am not entirely sure I will execute this, but something along those lines.
– Olivia
3 hours ago
You're over thinking it. For the queries where you filter onId
, you can run one query to get all of the data.
– Adrian Larson♦
3 hours ago
I am not entirely sure how I would achieve that with my query on advpm__Expense__c and Recovery_Payment__c as I am not just querying on ID.
– Olivia
3 hours ago
@Olivia You can group by and filter by multiple filters. AggregateResult example, as shown by Adrian here, means you can take the queries out of the loops you have. Also, you need an update map so you can associate the values with the records correctly. More maps, less lists.
– sfdcfox
24 mins ago
add a comment |
this is a good idea but I am concerned that if I bring in 200 records, then I can only have one query in the entire method. Would a better route be to write some handling withgetQueries()
and if we are at 199 then I would add the rest of the record Ids to a list, exit the method, and some how run the process again on the list? I am not entirely sure I will execute this, but something along those lines.
– Olivia
3 hours ago
You're over thinking it. For the queries where you filter onId
, you can run one query to get all of the data.
– Adrian Larson♦
3 hours ago
I am not entirely sure how I would achieve that with my query on advpm__Expense__c and Recovery_Payment__c as I am not just querying on ID.
– Olivia
3 hours ago
@Olivia You can group by and filter by multiple filters. AggregateResult example, as shown by Adrian here, means you can take the queries out of the loops you have. Also, you need an update map so you can associate the values with the records correctly. More maps, less lists.
– sfdcfox
24 mins ago
this is a good idea but I am concerned that if I bring in 200 records, then I can only have one query in the entire method. Would a better route be to write some handling with
getQueries()
and if we are at 199 then I would add the rest of the record Ids to a list, exit the method, and some how run the process again on the list? I am not entirely sure I will execute this, but something along those lines.– Olivia
3 hours ago
this is a good idea but I am concerned that if I bring in 200 records, then I can only have one query in the entire method. Would a better route be to write some handling with
getQueries()
and if we are at 199 then I would add the rest of the record Ids to a list, exit the method, and some how run the process again on the list? I am not entirely sure I will execute this, but something along those lines.– Olivia
3 hours ago
You're over thinking it. For the queries where you filter on
Id
, you can run one query to get all of the data.– Adrian Larson♦
3 hours ago
You're over thinking it. For the queries where you filter on
Id
, you can run one query to get all of the data.– Adrian Larson♦
3 hours ago
I am not entirely sure how I would achieve that with my query on advpm__Expense__c and Recovery_Payment__c as I am not just querying on ID.
– Olivia
3 hours ago
I am not entirely sure how I would achieve that with my query on advpm__Expense__c and Recovery_Payment__c as I am not just querying on ID.
– Olivia
3 hours ago
@Olivia You can group by and filter by multiple filters. AggregateResult example, as shown by Adrian here, means you can take the queries out of the loops you have. Also, you need an update map so you can associate the values with the records correctly. More maps, less lists.
– sfdcfox
24 mins ago
@Olivia You can group by and filter by multiple filters. AggregateResult example, as shown by Adrian here, means you can take the queries out of the loops you have. Also, you need an update map so you can associate the values with the records correctly. More maps, less lists.
– sfdcfox
24 mins ago
add a comment |
Thanks for contributing an answer to Salesforce Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsalesforce.stackexchange.com%2fquestions%2f241720%2fquery-limit-on-batchable-class%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Can the recovery Date be ever less that start date of Payment_Agreement__c?
– Pranay Jaiswal
4 hours ago