Delete Operations
BCCL provides two tasks for deleting records from Business Central tables: DELETEDATA for removing specific records identified by primary key, and DELETEALL for bulk-deleting all records that match a view filter. Both operations permanently remove data, so you should use them with care.
Choosing the Right Delete Task
| Task | Use When | Input Required |
|---|---|---|
| DELETEDATA | You have a list of specific records to delete | Input file with primary key values |
| DELETEALL | You want to remove all records matching a filter | View filter parameter |
If you know exactly which records to remove (for example, from a CSV list of customer numbers), use DELETEDATA. If you want to clear out a range of records based on a filter condition, use DELETEALL.
DELETEDATA -- Delete Specific Records
The DELETEDATA task deletes individual records by looking up their primary key values from an input file. For each row in the input file, BCCL finds the corresponding record in Business Central and deletes it.
How It Works
- BCCL reads the input file and the mapping file.
- For each record in the input file, it extracts the primary key field values using the mapping.
- It looks up the record in the target table by primary key.
- If the record is found, it is deleted.
- BCCL returns the total count of deleted records.
Only the primary key fields from the input file are used for the lookup. Any additional fields in the input file are ignored during the find operation.
Required Parameters
| Parameter | Description |
|---|---|
-t deletedata |
Specifies the DELETEDATA task |
-s table=N |
The Business Central table number |
-i filename |
Path to the input file with primary key values |
-m mapping.json |
Path to the mapping file (optional -- if omitted, all fields are auto-mapped) |
Input File Formats
DELETEDATA supports all input formats that BCCL handles:
| Format | Notes |
|---|---|
| CSV | Each row provides primary key values for one record |
| JSON | Array of objects, each containing primary key fields |
| XML | XML document with record elements containing primary key fields |
| Excel | Spreadsheet with primary key values (use -x and -y parameters) |
The input file only needs to contain the primary key fields. You do not need to include every field in the table.
Example: Deleting Customers by Number
Step 1: Create the Input File
Create a CSV file named delete-list.csv containing the customer numbers to delete:
custno
"90001"
"90002"
"90003"
"90004"
"90005"
Step 2: Create the Mapping File
Create a mapping file delete-map.json that maps the CSV column to the primary key field (field 1, No., in the Customer table):
[
{
"FieldNo": 1,
"FieldName": "No.",
"MappedName": "custno",
"Validate": false
}
]
Step 3: Run the Delete
bccl -t deletedata -s table=18 -i delete-list.csv -m delete-map.json
Step 4: Review the Result
{
"Table": 18,
"Deleted": 5
}
The Deleted count tells you how many records were actually removed. If a record in your input file does not exist in the table, it is simply skipped and not counted.
Validation on Delete
You can enable validation during deletion so that Business Central triggers run when each record is deleted. This is important when delete triggers contain business logic such as cascading deletes, posting checks, or audit logging.
To enable validation, use the ValidateOnDelete setting. When validation is enabled, BCCL calls Record.Delete(true) instead of Record.Delete(false).
If a validated delete fails for a particular record (for example, because a trigger raises an error), that record is not deleted and is not included in the Deleted count.
Tables with Compound Primary Keys
For tables with multi-field primary keys, your input file and mapping must include all primary key fields. For example, to delete Sales Lines (table 37), you need both the Document Type, Document No., and Line No. fields:
[
{
"FieldNo": 1,
"FieldName": "Document Type",
"MappedName": "doctype",
"Validate": false
},
{
"FieldNo": 3,
"FieldName": "Document No.",
"MappedName": "docno",
"Validate": false
},
{
"FieldNo": 4,
"FieldName": "Line No.",
"MappedName": "lineno",
"Validate": false
}
]
Auto-Mapping Without a Mapping File
If you omit the -m parameter, BCCL auto-maps all fields in the table. In this case, your input file column names must match the Business Central field names exactly (with spaces replaced by underscores). For delete operations, only the primary key fields actually matter, but all field names must still be resolvable.
Using an explicit mapping file is recommended because it gives you control over exactly which columns are expected.
Integration Events
The DELETEDATA codeunit publishes integration events for AL developers:
| Event | When It Fires |
|---|---|
OnBeforeDeleteData |
Once, before any records are processed |
OnBeforeDelete |
Before each individual record is deleted |
OnAfterDelete |
After each individual record is deleted |
OnAfterDeleteData |
Once, after all records have been processed |
DELETEALL -- Bulk Delete by Filter
The DELETEALL task deletes every record that matches a view filter. Unlike DELETEDATA, it does not require an input file -- the view filter alone determines which records are removed.
How It Works
- BCCL opens the target table and applies the view filter.
- It counts the matching records.
- It calls
DeleteAllon the filtered record set. - It returns the count of deleted records.
Required Parameters
| Parameter | Description |
|---|---|
-t deleteall |
Specifies the DELETEALL task |
-s table=N |
The Business Central table number |
-s view=WHERE(...) |
A view filter selecting which records to delete |
The View Filter Is Mandatory
As a safety measure, BCCL requires a view filter for DELETEALL. If you omit the view parameter, BCCL returns an error:
The view parameter is required when using DELETEALL
This prevents accidental deletion of an entire table. You must always provide a filter that limits which records are affected.
Optional: Validation on Delete
You can enable validation by adding the validate setting:
bccl -t deleteall -s table=18 "view=where(No.=filter(90000..99999))" -s validate=true
When validate is set to true or yes, BCCL calls DeleteAll(true), which fires the OnDelete trigger for each record. When omitted or set to false, BCCL calls DeleteAll(false), which is faster but skips trigger logic.
Example: Deleting a Range of Test Customers
bccl -t deleteall -s table=18 "view=where(No.=filter(90000..99999))"
This deletes all customers with numbers from 90000 through 99999. The response confirms the count:
{
"Table": 18,
"Deleted": 47
}
Example: Deleting by Multiple Criteria
You can use more complex filters to target records precisely:
bccl -t deleteall -s table=18 "view=where(No.=filter(T*),Blocked=filter(<>0))"
This deletes all customers whose number starts with T and whose Blocked field is not zero.
Example: Deleting with Validation
bccl -t deleteall -s table=50000 "view=where(Status=filter(Obsolete))" -s validate=true
This deletes records with an Obsolete status from a custom table, running the OnDelete trigger for each record.
Integration Events
The DELETEALL codeunit publishes integration events for AL developers:
| Event | When It Fires |
|---|---|
OnBeforeDeleteAll |
Before the bulk delete operation begins |
OnAfterDeleteAll |
After the bulk delete operation completes |
Comparing DELETEDATA and DELETEALL
| Feature | DELETEDATA | DELETEALL |
|---|---|---|
| Selection method | Input file with primary keys | View filter |
| Input file required | Yes | No |
| Mapping file | Optional (recommended) | Not used |
| View filter | Not used | Required |
| Validation support | Via ValidateOnDelete |
Via -s validate=true |
| Granularity | Per-record (from file) | All matching records |
| Best for | Deleting a known list of records | Clearing records by range or condition |
Safety Guidelines
Delete operations are permanent. Business Central does not provide a built-in undo for record deletions. Follow these practices to protect your data:
Before You Delete
- Export the records first. Use the GETDATA task with the same filter to export the records you are about to delete. Save this export as a backup.
bccl -t getdata -s table=18 "view=where(No.=filter(90000..99999))" -f csv -o backup.csv
- Verify your filter. Run a GETDATA with your intended filter and check that it returns only the records you want to delete. A misconfigured filter could match records you did not intend to remove.
- Test in a sandbox. When possible, test delete operations in a sandbox or test environment before running them in production.
During Deletion
- Use validation when business logic matters. If the table has OnDelete triggers that perform cascading cleanup (such as deleting related records or posting reversal entries), enable validation to ensure that logic runs.
- Use verbose mode for troubleshooting. Add
-vto your command to see detailed request and response information if something goes wrong.
After Deletion
- Check the Deleted count. Compare the returned
Deletedcount against your expectations. If it is higher or lower than expected, investigate before proceeding. - Keep your backup files. Retain the exported backup until you have confirmed that the deletion was correct and complete.
Tips and Best Practices
- Use DELETEDATA when you have a specific list of records from an external source (such as a list of obsolete account numbers from a spreadsheet).
- Use DELETEALL when cleaning up records by range, status, or date -- any condition expressible as a Business Central view filter.
- For DELETEALL, always double-check your filter by running a GETDATA with the same filter first.
- When deleting from tables with complex relationships, enable validation to ensure referential integrity is maintained.
- Remember that the
Deletedcount for DELETEDATA reflects only records that were found and successfully deleted. Records in your input file that do not exist in the table are silently skipped.