Nav2013 Enus Csintro 12
Nav2013 Enus Csintro 12
Nav2013 Enus Csintro 12
Module Overview
Queries specify datasets from the Microsoft Dynamics® NAV 2013 database for
retrieval in a fast and efficient way. You can use queries to retrieve data from one
or more tables as a single flat result set. You can specify how to join multiple
tables in the result set, and how to order, group, aggregate, and filter the resulting
data.
Queries retrieve data efficiently because they are always translated into a single
SELECT statement, and are executed against the underlying Microsoft SQL Server
database. Data is selected, joined, grouped, ordered, aggregated, and filtered at
the SQL Server level. This makes sure that there is a minimum effect on
performance.
Objectives
• Present the Query Designer and its features.
• Explain the principles of the query design process.
• Show how to select, join, filter, aggregate, and order data.
• Show how to access queries from C/AL code.
• Explain how to export data from queries.
Query Design
A query describes a dataset of Microsoft Dynamics NAV data. Queries retrieve
records from one or more tables and combine the records into rows and columns
in a single dataset. You create queries in the Microsoft Dynamics NAV 2013
Development Environment by using Query Designer.
Query Designer lets you model the query definition that Microsoft Dynamics NAV
2013 translates to a Transact-SQL statement. Microsoft SQL Server uses Transact-
SQL statements to retrieve data.
In Microsoft Dynamics NAV 2013, you can use queries for the following purposes:
• Structuring multiple tables into simple datasets for fast and efficient
data access from C/AL code. For example, page 9126, Lot Numbers
by Bin FactBox, uses query 7300, Lot Numbers by Bin Code, to
populate the fact box with temporary data from the dataset.
• Defining data sources for charts in a RoleTailored client. For example,
query 760, Trailing Sales Order Qry, joins the information from
tables 36, Sales Header, and 37, Sales Line, to be shown in the
Trailing Sales Orders part of the Sales Order Processor role center.
• Publishing as OData web services to be used as data sources for
Microsoft PowerPivot data analysis add-in for Microsoft Office Excel
2010.
• Exporting the datasets as CSV or XML.
Query Designer
You model queries in the Query Designer. To model a query, you specify the
tables from which to collect data and how to link them together to create the
resulting dataset. You also specify the fields that should be included. You can
perform many other operations, such as filtering, aggregating, and grouping.
Property Description
Type Determines the type of the row. It can be one
of the following:
• DataItem
• Column
• Filter
The following “Query Designer Window” figure shows the query 760, Trailing Sales
Order Qry, in the Query Designer window:
When the query is executed, Microsoft Dynamics NAV 2013 translates its data
model into a Transact-SQL SELECT statement and runs it against the underlying
Microsoft SQL Server database.
Selecting Data
To select the data, you must define the tables from which you want to retrieve the
data, and the fields that you want to include from those tables. When modeling a
query in the Query Designer, a data item corresponds to a table; columns
correspond to a field in the table.
To define a new data item, insert a new row, and set Type to DataItem. Then
specify the source table in the Data Source column, by entering either the table ID
or name, or by selecting the table from the list of available tables.
The Name of the data item is automatically set to the name of the source table. If
the table name contains characters that are not supported by the Common
Language Specification, those characters are trimmed or replaced with an
underscore, depending on their location in the table name. You can replace the
name with one of your choice, as long as it complies with the Common Language
Specification.
Note: When a row is of the DataItem type, the Data Source column directly
corresponds to the DataItemTable property. When you enter the table name in
DataItemTable property in the Properties window, it is the same as entering it in
the Data Source column in the Query Designer window.
Defining Columns
For each field that you want to include in the resulting dataset, you must define a
column in the query data model. To define a column, insert a new row under the
data item and set Type to Column. To specify fields, do any the following:
• Type the field name or number directly in the Data Source column.
• Select the field from the list of available fields in the Data Source
column.
Demonstration Steps
The “Simple Item Query Results Preview” figure shows the results of the Simple
Item Query in the preview mode.
Note: The preview mode shows up to 1000 rows. Use this mode as a quick
validation, but not as a final output result.
Joining Data
The biggest advantage of queries comes from their ability to join data from
multiple tables into a single resulting dataset. Therefore, you usually model
queries to include multiple data items that are joined to combine the data from
multiple tables into a single resulting dataset.
You join a data item to another data item by indenting it under another data
item. The data item under which you have indented another data item becomes
the parent data item. Each parent data item can have only one child data item.
Note: You almost never have to use the indentation buttons, because Query
Designer indents new data items automatically. When you insert a new row in the
query data model, it automatically indents under its parent. This behavior applies to
data items, columns, and filters.
When you indent data items under one another, you only specify that data from
one table will be joined to the data from another table. You have not defined how
the data will be joined. To define the data joining rules, use the following data
item properties.
Property Description
DataItemLink Sets a reference between one or more
fields of the source table of the current
data item and fields of one or more source
tables of the data item or data items that
are higher in the data model hierarchy.
This demonstration shows how to define multiple data items and join them to
create a single resulting dataset.
To prepare for this demonstration, you must change several items, and define
several purchase prices. To do this, follow these steps:
Demonstration Steps
1. Add a data item for the Vendor table to the Simple Item Query
query.
a. In Object Designer, select query 123456701, Simple Item Query,
and then click Design.
b. In the first empty row, in the Type column, select DataItem.
c. In the Data Source column, enter “Vendor”.
2. Add columns for the Name and City fields to the Vendor data item.
a. Select the first empty row.
b. On the View menu, click Field Menu.
c. Select the Name and City fields.
d. Click OK.
4. Add columns for the Currency Code and Direct Unit Cost fields.
a. Select the first empty row.
b. On the View menu, click Field Menu.
c. Select the Currency Code and Direct Unit Cost fields.
d. Click OK.
e. In the confirmation dialog box, click Yes.
f. In the Name column for the Direct Unit Cost field, enter “Price”.
Note: This joins the Vendor and Item data items so that each item displays
vendors that have the same value in the No. field as the value of the Vendor No.
field in the Item table. Because the No. field in the Vendor table is also its primary
key, there can be only one vendor per item.
6. Join the Purchase Price data item to the Item and Vendor data
items.
a. Select the Purchase_Price data item.
b. On the View menu, click Properties.
c. In the DataItemLink property, click the AssistEdit button to open
the DataItem Link window.
d. In the Field column, select the Item No. field.
e. In the Reference DataItem column, select the Item data item.
f. In the Reference Field column, select the No. column.
g. In the next row, in the Field column, select the Vendor No. field.
h. In the Reference DataItem column, select the Vendor data item.
i. In the Reference Field column, select the No. column.
FIGURE 12.11: DATAITEM LINK FOR THE PURCHASE PRICE DATA ITEM
j. Click OK to accept changes and close the DataItem Link window.
k. Close the Properties window.
8. Configure the join on the Vendor data item to only show those rows
from the Item table that have a matching row in the Vendor table,
and then run the query.
a. Select the Vendor data item.
b. On the View menu, click Properties.
c. In the DataItemLinkType property, select Exclude Row If No
Match.
d. Close the Properties window.
9. Configure the join on the Purchase Price data item to only show
those rows from the Item table that have a matching row in the
Purchase Price table.
a. Select the Purchase_Price data item.
b. On the View menu, click Properties.
c. In the DataItemLinkType property, select Exclude Row If No
Match.
d. Close the Properties window.
10. Save and run the query, then view the results.
a. On the File menu, click Save.
b. In the Save dialog box, make sure that the Compiled check box
is selected, and then click OK.
c. On the File menu, click Run.
11. Reconfigure the join on the Purchase Price data item to show default
values if there is no match. This displays the purchase price list that
has all items that have a vendor, but without price information if a
purchase price is not defined.
a. Select the Purchase_Price data item.
b. On the View menu, click Properties.
c. In the DataItemLinkType property, select Use Default Values if
No Match.
d. Close the Properties window.
12. Save and run the query, and then view the results.
a. On the File menu, click Save.
b. In the Save dialog box, make sure that the Compiled check box
is selected, and then click OK.
c. On the File menu, click Run.
Filtering Data
There are several ways to filter the data in resulting datasets of queries:
DataItemTableFilter Property
To set up filters, you can enter either the filter syntax directly in the Value column
for the DataItemTableField property in the Properties window or click the
AssistEdit button in the Value column, and then use the Table Filter window to
set up the filters.
Note: The Table Filter window works exactly the same way as with pages,
reports, or XMLports.
The filters you define in the DataItemTableFilter property are static. Users or C/AL
code cannot override them.
ColumnFilter Property
Note: The SETFILTER and SETRANGE functions overwrite any filter on the
same field that is set on a column or filter row by the ColumnFilter property in
Query Designer. If a SETFILTER or SETRANGE function filters on the same field as
a filter on a data item, as specified by the DataItemTableFilter property, then the
function filter and DataItemTableFilter property filter are combined.
Filter Rows
You use rows for type Filter to enable dynamic filtering of the resulting dataset on
fields that you do not want to include in the resulting dataset of a query. For
example, you might want to let users or developers to filter on a date range.
However, you do not want to include the date in the dataset.
To define a filter, insert a new row under the data item for which you want to add
a filter. Select Type of Filter, and then select the field from the table on which you
want to enable filtering.
Note: You cannot use Field Menu to create rows of type Filter. You can only
create new filter rows by defining them individually.
Property Description
DataSource Specifies the field to be used as a filter.
For rows of Type Filter, defining this
property has the same effect as defining
the Data Source property in the Query
Designer window.
Note: The ColumnFilter property of filter rows behaves the same way as with
the columns.
OnBeforeOpen Trigger
The OnBeforeOpen trigger runs before its model is translated into a Transact-SQL
statement and is executed against the underlying Microsoft SQL Server database.
You can use the OnBeforeOpen trigger to set filters on the query by using the
SETFILTER or SETRANGE C/AL functions. When you use C/AL, you can only filter
the query on columns or filters that are defined in the query. You cannot filter on
any other fields that are present in any of the data items that you have not added
to the query model as either a column or a filter.
The following example filters the query to include only those rows where
Unit_Cost is not 0.
CurrQuery.SETFILTER(Unit_Cost,'<>%1',0);
Demonstration Steps
1. Filter the Simple Item Query to only show items that use the purchase
replenishment system by defining the DataItemTableFilter property
on a data item.
a. In Object Designer, select query 123456701, Simple Item
Query, and then click Design.
b. Select the Item data item. It is the first row in Query Designer.
2. Filter the query to only show those items that have unit cost defined
by setting the ColumnFilter property on a column.
a. Select the Unit_Cost column.
b. On the View menu, click Properties.
c. In the ColumnFilter property, click the AssistEdit button to open
the Column Filter window.
d. In the Column field, make sure that the Unit_Cost value is
present.
e. In the Type field, select FILTER.
f. In the Value field, enter “<>0”.
3. Enable users to dynamically filter the query on the Vendor No. and
Vendor Posting Group fields without including the fields in the
resulting dataset.
a. Select the No. field under the Item data item.
b. On the Edit menu, click New.
c. In the Type column, select Filter.
d. In the Data Source column, select the Vendor No. field.
e. Select the Name field under the Vendor data item.
f. On the Edit menu, click New.
g. In the Type column, select Filter.
h. In the Data Source column, select the Vendor Posting Group
field.
Note: The query now only shows those records where the Replenishment
System field in the Item table is set to Purchase, and where Unit Cost field is
different from 0. The query does not include Vendor_No and Vendor_Posting_Group
information. However, you can dynamically filter on this information through C/AL
code.
Aggregating Data
You typically use aggregations with grouping to find totals for specified groups of
columns. For example, you can sum the values in the Amount field per G/L
account in the G/L Entry table or find the average Quantity per item in the Item
Ledger Entry table. Totals methods in Microsoft Dynamics NAV 2013 queries
correspond directly to Microsoft SQL Server aggregate functions.
To set the totaling methods in a Microsoft Dynamics NAV 2013 query, follow
these steps:
Note: When you apply a totals method to a column, and you have not
changed the Name from the default, the Name of the column is automatically
prefixed with the name of the totals method that is being applied. It reflects the fact
that the column is aggregated. For example, when you apply the Average method
to the Amount column, the name is automatically changed to Average_Amount.
The column must be of type Decimal.
Ordering Data
You can order the data in a resulting dataset of a query by any number of
columns that are contained in the query. To define the sorting order, set the
OrderBy property on the query.
To access the OrderBy property, in Query Designer, select the first blank line, and
then, on the View menu, click Properties.
To modify the OrderBy property, you can click the AssistEdit button next to the
property. In the Order By window, you add a column and set its direction to
ascending or descending. You can sort on multiple columns by adding additional
columns to the Order By window. The query will sort the results by the first
column in the Order By window, then by the second column, and so on.
Note: You cannot sort by a column that is not present in the resulting dataset.
If you want to order by such a column, you must first add it to the query model, and
then include it in the OrderBy property.
Date Methods
When retrieving Date or DateTime fields from a Microsoft Dynamics NAV 2013
database, you may want to retrieve only the year, month or day, instead of the
entire date. This is especially true when you group and total the data. For
example, you may want to group revenue by customer and by year, or find
average consumption of a production BOM component by month. You can
achieve this by selecting a date method for a Date or DateTime column in the
Query Designer.
• Day
• Month
• Year
Note: When you apply a date method to a Date or DateTime column, and
you have not changed the Name from the default, the Name of the column is
automatically prefixed with the name of the date method that is being applied. For
example, when you apply the Year date method to the Posting Date column, the
name is automatically changed to Year_Posting_Date.
On the SQL server, date and time values are processed by using Coordinated
Universal Time (UTC). If Microsoft Dynamics NAV solution uses a time zone other
than UTC and the field on which you apply the date method has a data type of
DateTime, then there might be a difference between the date value that is
returned in the dataset for the field, and the actual day, month, or year for the
field in the table. This occurs when the corresponding UTC date for a field falls on
the next day or previous day because of the time of day and the time zone of
Microsoft Dynamics NAV solution.
To avoid this condition, you should use the date method on fields that have a
Date data type instead of a DateTime data type when possible. You can also
return the DateTime value and implement post processing for the day, month,
and year as needed.
The following demonstration shows how to aggregate the data and order the
resulting dataset of a query.
Demonstration Steps
FIGURE 12.18: THE ORDER BY WINDOW FOR THE SIMPLE ITEM QUERY
f. Click OK to accept changes and close the Order By window.
g. Close the Properties window.
Susan, the sales order processor at CRONUS International Ltd., needs a chart that
shows the top ten customers by revenue. She wants to access this chart from her
Role Center.
Isaac and Simon, the consultants at the ISV company that implements Microsoft
Dynamics NAV 2013 for CRONUS International Ltd., will help Susan by creating
and customizing the necessary objects, and then configure Microsoft Dynamics
NAV 2013 according to Susan’s requirements.
Objectives
Isaac, the business software developer, creates a new query object that selects the
data that Susan wants to see in a chart part on her role center. The query will join
the data from the Customer and Cust. Ledger Entries tables, show only those
customers who have ledger entries of type Invoice or Credit Memo, and display
the Amount (LCY) column totaled by the Sum method.
Detailed Steps
1. Create a new query object.
a. On the Tools menu, click Object Designer.
b. In the Object Designer window, click Query.
c. Click New to open the Query Designer.
Detailed Steps
1. Select table 21, Cust. Ledg. Entry as the second data item, indented
under Customer.
a. In the Query Designer window, move to the last row until the
new row indicator is shown.
b. Set Type to DataItem, and in the DataSource property select
table 21, Cust. Ledg. Entry.
Detailed Steps
1. Add columns for the No., Name and Customer Posting Group fields
to the Customer data item.
a. In the Query Designer window, select the Customer data item.
b. On the View menu, click Field Menu.
c. In the Field Menu window, select the No., Name and Customer
Posting Group fields.
d. Click OK.
Detailed Steps
1. Set the query properties to order the results by sum of Amount (LCY)
in descending order.
a. In the Query Designer window, move to the last row until the
new row indicator is shown.
b. On the View menu, click Properties.
c. In the OrderBy property, click the AssistEdit button.
d. Select Sum_Amount_LCY as Column, and Descending as
Direction.
e. Click OK
.
2. Set the query properties to return only the top 10 rows.
a. In the Properties window for the query, specify “10” as
TopNumberOfRows.
b. Close the Properties window for the query.
Detailed Steps
1. Save the newly defined query object as 123456701, Top 10 Cust. by
Revenue.
a. In the Query Designer window, on the File menu, click Save.
b. In the Save As dialog box, in the ID text box, enter “123456702”.
c. In the Name text box, enter “Top 10 Cust. By Revenue”, and then
click OK.
A new query object, 123456702, Top 10 Cust. by Revenue, that joins the data from
the Customer and Cust. Ledger Entry tables
Simon, the consultant, creates a new chart setup record in Microsoft Dynamics
NAV 2013, to show the data from the query that was created by Isaac in the
previous exercise. The chart will be a column chart, and will show
Sum_Amount_LCY as a measure that is aggregated by the Sum method over the
customer number as the X-axis dimension.
Detailed Steps
1. Open the Microsoft Dynamics NAV 2013 client for Windows.
a. On the Start menu, click Microsoft Dynamics NAV 2013.
2. Set the data source of the chart to query 123456702, Top 10 Cust. by
Revenue.
a. In the Chart Setup Card window, in the Source Type field, select
Query.
b. In the Source ID field, enter “123456702”.
Results
A new chart setup record that shows data from query 123456702, Top 10 Cust. by
Revenue.
Susan customizes her Role Center to include the chart part that Simon configured
in the previous exercise.
Detailed Steps
1. Customize the Role Center.
a. In the Microsoft Dynamics NAV 2013 client for Windows, click
Home to navigate to the Role Center.
b. Click the Application menu, then click Customize > Customize
This Page.
c. In the Customize the Role Center window, in Role Center
Layout, click Microsoft Outlook.
d. In the Available Parts list, click Chart Part, and then click
Add>>.
e. Click Customize Part.
f. In the Customize Chart window, select chart 123456702-01 Top
10 Cust. by Revenue, and then click OK.
g. Click OK to close the Customize the Role Center window.
Detailed Steps
1. Restart the Microsoft Dynamics NAV 2013 client for Windows.
a. Close the Microsoft Dynamics NAV 2013 client for Windows.
b. Start the Microsoft Dynamics NAV 2013 client for Windows.
Running Queries
You can run a query C/AL to iterate through the resulting dataset
programmatically. Even though the principles of accessing a query resemble those
of accessing tables, there is a different set of functions on a query object.
OPEN
The OPEN function runs a query object and generates a dataset that you can
read. It also puts the query in the reading state.
The OPEN function returns a Boolean value. This indicates whether the query
opened successfully. If you omit this optional return value and if the query does
not open successfully, then a run-time error occurs. If you include a return value,
then no run-time error occurs when the OPEN function is called and you will
handle any errors.
If the OPEN function fails, you cannot call other functions or access the data in
the query. If you try to do this, a run-time error occurs.
Note: The OPEN function only runs the query object and generates a dataset.
It does not return the first row of the result set. To access any row, you must call
READ.
READ
The READ function reads a single row from the resulting dataset of a query. The
function returns a Boolean value that indicates if a row was retrieved.
When you call the READ function, the next row in the dataset query is retrieved.
When the query is in the reading state, you can access the values of columns in
the row in the same manner that you access the fields in a record variable.
You can call the READ function multiple times after the OPEN function to read
consecutive rows in the dataset. The first READ function call retrieves the first row
from the resulting dataset. Each successive READ function call retrieves the next
row from the dataset.
The CLOSE function closes a query dataset and returns the query to the initialized
state. It lets the NAV Server know that you are finished using this object.
Calling CLOSE explicitly is optional. This function is called implicitly in any of the
following situations:
The CLOSE function does not clear any filters that you set on the query
programmatically. If you want to clear such filters, then you must call the CLEAR
function.
The following example shows how to open a query, iterate through it, and then
close it from C/AL code.
// Do some logic
END;
CLOSE;
END;
END;
Column Access
You can access the columns of a query on a query variable in a manner that is
similar to accessing the fields of a table on a record variable. When you read
values from columns C/AL, you reference columns exactly as you reference record
fields.
The following example shows how to read a value from the Price column of the
Simple Item Query.
ItemPrice := SimpleItemQery.Price;
Programmatically, you can only access those columns that are been defined in the
query, but not any other fields that exist in the tables from which the query is
constructed.
You can see the list of all columns of a query in the Symbol Menu.
Filtering Queries
You can filter the data in queries to narrow the resulting datasets. You can only
filter a query on a field which is included as a column or a filter in the query. You
use the SETRANGE and SETFILTER functions to set filters on a query variable.
When you use the SETFILTER and SETRANGE functions to define a filter on the
same field that is already filtered through the ColumnFilter property in Query
Designer, then the filter that is defined in the ColumnFilter property is replaced
by the filter that you set in the C/AL code.
If you use SETFILTER or SETRANGE functions on the same field that is included in
the DataItemTableFilter property of a data item, then the function filter and
DataItemTableFilter property filter are combined.
The following example shows how to use the SETFILTER and SETRANGE
functions to filter the resulting dataset of a query.
PendingProdOrders.SETRANGE(Status,1,3);
PendingProdOrders.SETFILTER(Due_Date,'>0D|<%1',WORKDATE);
IF PendingProdOrders.OPEN THEN
Item.GET(PendingProdOrders.Item_No);
Item.TESTFIELD(Blocked,FALSE);
END;
PendingProdOrders.CLOSE;
You can have multiple calls to the SETFILTER function. If the SETFILTER function
calls set filters on different columns, then the filters are combined and applied to
the dataset. If consecutive SETFILTER function calls set filters on the same column,
then the last SETFILTER function call is applied to the column.
TOPNUMBEROFROWS
When you design a query, you can set the limit for the number of rows that the
query returns by specifying its TopNumberOfRows property in the Query
Designer window. At run time, you can check or change the value of this property
by using the TOPNUMBEROFROWS function. If you limit the number of rows by
defining the TopNumberOfRows property, the TOPNUMBEROFROWS function
overwrites the TopNumberOfRows property.
The following example shows how to programmatically limit the number of rows
that are returned from a query to 10 rows.
Calling TOPNUMBEROFROWS
SimpleItemQuery.TOPNUMBEROFROWS := 10;
Note: You can call filtering and the TOPNUMBEROFROWS functions on the
CurrQuery variable from the OnBeforeOpen trigger in the query object. CurrQuery
variable is implicit in the C/AL code of the query object. You do not have to
reference it directly.
You can save the resulting dataset of the query to an external file from C/AL. You
can use the SAVEASCSV function to save the results to a comma-separated values
(CSV) file, and use the SAVEASXML function to save the results to an XML file.
You can always call SAVEASCSV and SAVEASXML functions directly, without
calling the OPEN, READ or CLOSE functions first. When SAVEASCSV or
SAVEASXML functions are called, the query is implicitly opened, read and then
closed. If you call SAVEASCSV or SAVEASXML functions on a query that is
already opened, then the dataset is first retrieved again from the Microsoft
Dynamics NAV 2013 database. After the dataset is saved to the file, the query is
left in the closed state. This makes any later call to the READ function invalid. You
must reopen the query to continue reading the data.
The following example shows how to export a top number of rows in the resulting
dataset of a query to an XML file.
// Text001 is ‘The file was not saved, but execution continues. The problem was:
%1’
Top10ProdOrders.TOPNUMBEROFROWS(5);
MESSAGE(Text001,GETLASTERRORTEXT);
Saving to CSV
A CSV file stores the data in a plain text format. The files created through the
SAVEASCSV function resemble the variable text format files that are exported
from an XMLport. Each row of data in a CSV file resides in a separate line. The first
line of a CSV file that is created through the SAVEASCSV function always contains
the column names of the query. The column names are specified in the Name
property of each column in the definition of the query.
Note: CSV files follow a fixed set of rules that make it easy to import them in
other applications, such as Microsoft Office Excel.
Saving to XML
Unlike the XML files that are exported from XMLports, the structure of the XML
files that are created by SAVEASXML function always follows the same fixed
structure. The data in the resulting XML document does not belong to a
namespace, the root element is always <DataSet>, and each row is represented as
a <Result> element. Columns are represented as child elements of the <Result>
element. The name of each element that represents a column is equal to the
name of the column as specified in its Name property. The XSD schema that
describes the format of the resulting XML file is embedded in the file.
The “XML File Created by SAVEASXML” figure shows the XML file that is created
by the SAVEASXML function. This includes the embedded schema.
Isaac, the business software developer at the ISV company that implements
Microsoft Dynamics NAV 2013 for CRONUS International Ltd., will create and
customize the necessary objects to meet Julia’s requirements.
Objectives
Isaac, the business developer, creates a codeunit that iterates through the Top 10
Cust. by Revenue query. This codeunit populates a temporary Customer table,
and then shows the Customer List page over this temporary table. When the
Customer List page is closed, the confirmation dialog box is displayed. The dialog
box asks whether the credit limit should be reset to zero. If the user confirms by
clicking Yes, the codeunit applies the new credit limit to the selected customers.
Detailed Steps
1. Create a new codeunit.
a. On the Tools menu, click Object Designer.
b. In the Object Designer window, click Codeunit.
c. Click New.
Detailed Steps
1. Declare a global variable for query 123456702, Top 10 Cust. by
Revenue.
a. In the C/AL Editor window for the Codeunit 50111, on the View
menu, click C/AL Globals.
b. In the C/AL Globals window, declare a new variable and set its
Name to Top10Cust.
c. Set its Type to Query, and then set its Subtype to Top 10 Cust. by
Revenue.
Detailed Steps: You can also enter “123456702” in the Subtype property.
4. Declare a global text constant Text001, and set its value to “Do you
want to reset the %1 to %2 for these customers?”
a. In the C/AL Globals window, on the Text Constants tab, declare
a new text constant.
b. Set the Name of the text constant to Text001.
c. Set the ConstValue of the text constant to “Do you want to reset
the %1 to %2 for these customers?”
5. Declare a global text constant Text002, and set its value to “Action
completed successfully.”
a. In the C/AL Globals window, on the Text Constants tab, declare
a new text constant.
b. Set the Name of the text constant to Text002.
c. Set the ConstValue of the text constant to “Action completed
successfully.”
d. Close the C/AL Globals window.
Detailed Steps
1. Write code that filters the Top10Cust variable to only include those
rows which have Sum_Amount_LCY higher than zero.
a. In the C/AL Editor window, add the following code to the OnRun
trigger:
Top10Cust.SETFILTER(Sum_Amount_LCY,'>%1',0);
Top10Cust.OPEN;
END;
Top10Cust.CLOSE;
Cust.GET(Top10Cust.No);
CustTmp := Cust;
CustTmp.INSERT;
Detailed Steps
1. Add a function that resets the credit limit for all customers in the
CustTmp temporary variable, and then displays the Text002 as an
information message. Set the function name to ResetCreditLimit.
a. In the C/AL Editor window, on the View menu, click C/AL
Globals.
b. In the Functions tab, declare a new function named
ResetCreditLimit.
c. Close the C/AL Globals window.
d. Enter the following code in the ResetCreditLimit function
trigger.
IF CustTmp.FINDSET THEN
REPEAT
Cust.MODIFY;
UNTIL CustTmp.NEXT = 0;
MESSAGE(Text002);
IF CONFIRM(Text001,
FALSE,
0)
THEN
ResetCreditLimit;
3. Show the top ten customer list as a modal page. If the user clicks OK
in the page, run the ConfirmReset function.
a. Append the following code to the end of the OnRun trigger.
ConfirmReset;
Detailed Steps
1. Run the codeunit to verify its functionality.
a. In Object Designer, select the codeunit 50111, Reset Top 10 Cust.
Cred. Limit.
b. Click Run.
c. Verify that the confirmation dialog is displayed. Click Yes.
d. Verify that the information message is displayed. Click OK.
When you are retrieving data, you can use records and queries and iterate
through datasets in a similar manner. The C/AL functions that you use with
records and queries are not the same. However, they achieve the same goal.
The following table shows a side-by-side comparison of the C/AL functions that
you use when you access data with records and queries.
Retrieving data with records and queries is very different. With records, the
FIND(‘-‘) and FINDSET functions also retrieve the first record, whereas with
queries, the OPEN function merely translates the query model into a Transact-SQL
statement and runs it against Microsoft SQL Server. With records, after the initial
FIND(‘-‘) or FINDSET, the record is already retrieved, and you can immediately
access the fields. With queries, you must call READ one time before you can
access the columns. Because of this, you write the iteration loops differently. With
records, you use the REPEAT..UNTIL compound statement. With queries, you use
the WHILE..DO compound statement.
Except for the syntactical differences in how you iterate through datasets with
records and queries, there are also functional differences between retrieving
records by using FIND(‘-‘) or FINDSET, and using queries. Because of those
differences, you cannot directly replace traditional record-based iteration with
queries.
The following table summarizes different data access scenarios, and makes
recommendations about the data access feature of Microsoft Dynamics NAV 2013
that you should use.
When Microsoft Dynamics NAV 2013 runs a query, it first translates it into a
Transact-SQL statement, and then runs that statement against the underlying
Microsoft SQL Server database. One benefit of queries is that they enable you to
model a dataset in a user-friendly way. Queries do not require knowledge of
Transact-SQL querying language, or expertise in Microsoft SQL Server.
However, if you are familiar with Transact-SQL, you may want to understand
exactly how the query features of Microsoft Dynamics NAV 2013 map to Transact-
SQL.
The following table summarizes the elements and properties of query objects, and
how they relate to Transact-SQL.
You can use SQL Server Profiler that is included with Microsoft SQL Server to
analyze queries and how they translate to Transact-SQL.
The “Query 760, Trailing Sales Order Qry.” figure shows the data model of the
query 760, Trailing Sales Order Qry. in the Query Designer window.
When you run this query, Microsoft Dynamics NAV 2013 translates the query data
model into a Transact-SQL SELECT statement and executes it against the
underlying Microsoft SQL Server database.
You can use SQL Server Profiler to capture the Transact-SQL translation of the
query 760. Simplified, the Transact-SQL translation of this query looks as follows.
SELECT
"Sales_Header"."Currency Code" AS "CurrencyCode",
SUM("Sales_Line"."Amount") AS "Amount"
FROM
"CRONUS International Ltd_$Sales Header" AS "Sales_Header"
JOIN
"CRONUS International Ltd_$Sales Line" AS "Sales_Line"
ON
("Sales_Line"."Document Type"="Sales_Header"."Document Type" AND
"Sales_Line"."Document No_"="Sales_Header"."No_")
WHERE
("Sales_Header"."Document Type"= 1) AND
("Sales_Line"."Amount"<> 0)
GROUP BY
"Sales_Header"."Currency Code"
ORDER BY
"Sales_Header"."Currency Code" ASC
Module Review
Module Review and Takeaways
There are many situations in which iterative data access is incorrect. Microsoft
Dynamics NAV 2013 can tap into the powerful relational database management
engine of Microsoft SQL Server to select complex, multi-table sets of data in a fast
and efficient way.
The Query object of Microsoft Dynamics NAV 2013 enables you to define
relational data models that are translated into efficient SELECT statements.
Microsoft SQL Server can execute these statements as single data retrieval
operations. This guarantees optimal performance and minimal pressure on system
resources.
In Microsoft Dynamics NAV 2013, you can use queries to do any of the following:
1. Which of the following examples are valid use case scenarios for queries?
( ) Table relations in tables, source for pages, source for Charts in the
RoleTailored client.
2. What property do you need to set and to what value, to specify that a row in
the parent data item is skipped if it contains no child rows?
4. Which is not the valid Totals method for a Decimal column in a query?
( ) Sum
( ) Count
( ) Average
( ) Min
( ) Exists
( ) OnBeforeOpen
( ) OnBeforeOpenQuery
( ) OnOpen
( ) OnRun
( ) OnBeforeRun
( ) True
( ) False
7. Which function do you use to save query results into an XML file?
1. Which of the following examples are valid use case scenarios for queries?
( ) Table relations in tables, source for pages, source for Charts in the
RoleTailored client.
(√) Source for Charts in the RoleTailored client, source of OData web
services, iterating through rows of data in C/AL, and exporting result
sets as XML or text.
2. What property do you need to set and to what value, to specify that a row in
the parent data item is skipped if it contains no child rows?
MODEL ANSWER:
3. How do you specify that the query should only return the year from a date
column?
MODEL ANSWER:
4. Which is not the valid Totals method for a Decimal column in a query?
( ) Sum
( ) Count
( ) Average
( ) Min
(√) Exists
(√) OnBeforeOpen
( ) OnBeforeOpenQuery
( ) OnOpen
( ) OnRun
( ) OnBeforeRun
(√) True
( ) False
7. Which function do you use to save query results into an XML file?
MODEL ANSWER:
SAVEASXML
8. Which function do you use to save query results into a delimited text file?
MODEL ANSWER:
SAVEASCSV