AX / D365FO – Delete_from syntax examples

You can delete multiple records from a database table by using a delete_from statement. This can be more efficient and faster than deleting one record at a time by using the xRecord .delete method in a loop.

If you have overridden the delete method, the system interprets the delete_from statement into code that calls the delete method one time for each row that is deleted.

Delete_From to Delete Multiple Records

The following X++ code example is an efficient way to delete multiple records.

static void DeleteMultiRow1aJob(Args _args)

{
MyWidgetTable tabWidget;
;
delete_from tabWidget
where tabWidget .quantity <= 100;
}

Delete Method Plus ForUpdate Keyword

The following X++ code example is inefficient. It issues a separate SQL delete call to the database server for each record. The xRecord .delete method never deletes more than one record per call.

static void DeleteMultiRow1bJob(Args _args)

{
MyWidgetTable tabWidget; // extends xRecord.
;
ttsBegin;
while select
forUpdate
tabWidget
where tabWidget .quantity <= 100
{
tabWidget .delete();
}
ttsCommit;
}

Delete Method Plus Inefficient Inner Join Logic

The following X++ code example is inefficient. It issues a separate SQL delete call to the database server for each record.

static void DeleteInnerJoin2aJob(Args _args)

{
MyWidgetTable tabWidget; // extends xRecord.
;
ttsBegin;
while select
forUpdate
tabWidget
join tabGalaxy
where
tabWidget .GalaxyRecId == tabGalaxy .RecId
&& tabGalaxy .isTrusted == 0
{
tabWidget .delete();
}
ttsCommit;
}

Delete_From Plus Efficient Inner Join Logic

The following X++ code example is relatively efficient. It issues a separate delete_from statement for each loop iteration. However, each delete_from statement can delete multiple records, a subset of all the records that the job deletes.

static void DeleteInnerJoin2bJob(Args _args)

{
MyWidgetTable tabWidget; // extends xRecord.
;
ttsBegin;
while select
from tabGalaxy
where tabGalaxy .isTrusted == 0
{
delete_from tabWidget
where tabWidget .GalaxyRecId ==
tabGalaxy .RecId;
}
ttsCommit;
}

Delete_From Notexists Join

You can use the notexists join keyword pair in a delete_from statement.

The delete_from statements in the following X++ code example are efficient. The notexists join clause enables the delete_from statement to delete a specific set of rows. In this example the delete_from statement removes all the parent order header rows for which there are no child order line rows.

static void DeleteFromNotexists3bJob(Args _args)

{
GmTabOrderHeader tabOHeader;
GmTabOrderLine tabOLine;
AddressState tabAddressState;
str 127 sOH_Info;
str 127 sOL_Data;
int64 i64OHRecId;
;
delete_from tabOLine;
delete_from tabOHeader;

// Inserts into parent table.

sOH_Info = "Albert needs tires.";
insert_recordset tabOHeader
(OH_Info)
select firstOnly sOH_Info from tabAddressState;

sOH_Info = "Benson wants plastic.";
insert_recordset tabOHeader
(OH_Info)
select firstOnly sOH_Info from tabAddressState;

// Obtain a OrderHeader RecId,
// use it to insert one child row.

sOL_Data = "4 re-treads.";
while select firstOnly tabOHeader
order by OH_Info
where tabOHeader .OH_Info like "A*"
{
i64OHRecId = tabOHeader .RecId;
insert_recordset tabOLine
(OL_Data ,OrderHeaderRecId)
select firstOnly
sOL_Data ,i64OHRecId
from tabAddressState;
break;
}

// Before the delete notexists.
// Display all parent, and then all child rows.

while select tabOHeader
order by OH_Info
{
info(strFmt(
"Before: OHeader: OH_Info==%1 , RecId==%2"
,tabOHeader .OH_Info ,tabOHeader .RecId
));
}
while select tabOLine
order by OL_Data
{
info(strFmt(
"Before: OLine: OL_Data==%1 , OrderHeaderRecId==%2"
,tabOLine .OL_Data ,tabOLine .OrderHeaderRecId
));
}

// Delete_From NotExists Join, to remove from the
// parent table all order headers without children.

delete_from tabOHeader
notexists join tabOLine
where tabOHeader .RecId ==
tabOLine .OrderHeaderRecId;


info(strFmt
("%1 is the number of childless OHeader records deleted."
,tabOHeader.rowCount()));

// After the delete notexists.
// Display all parent, and then all child rows.

info("- - - - - - - - - - - - - - -");
while select tabOHeader
order by OH_Info
{
info(strFmt(
"After: OHeader: OH_Info==%1 , RecId==%2"
,tabOHeader .OH_Info ,tabOHeader .RecId
));
}
while select tabOLine
order by OL_Data
{
info(strFmt(
"After: OLine: OL_Data==%1 , OrderHeaderRecId==%2"
,tabOLine .OL_Data ,tabOLine .OrderHeaderRecId
));
}
/************** Actual Infolog output
Message (12:54:14 pm)
Before: OHeader: OH_Info==Albert needs tires. , RecId==5637144608
Before: OHeader: OH_Info==Benson wants plastic. , RecId==5637144609
Before: OLine: OL_Data==4 re-treads. , OrderHeaderRecId==5637144608
1 is the number of childless OHeader records deleted.
- - - - - - - - - - - - - - -
After: OHeader: OH_Info==Albert needs tires. , RecId==5637144608
After: OLine: OL_Data==4 re-treads. , OrderHeaderRecId==5637144608
**************/
}

Leave a comment