Module 12 Queries
Module 12 Queries
Module 12 Queries
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.
12 - 1
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.
12 - 2
Module 12: Queries
The Query Designer is tabular. Each row represents an element of a query, such as a column
of a resulting dataset. For each row in the Query Designer window, you can define the
following important properties.
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:
12 - 3
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
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.
Use the Field Menu to insert multiple fields.
12 - 4
Module 12: Queries
Demonstration Steps
12 - 5
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
12 - 6
Module 12: Queries
The “Simple Item Query Results Preview” figure shows the results of the Simple Item Query
in the preview mode.
12 - 7
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
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.
12 - 8
Module 12: Queries
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.
DataItemLinkType Defines how the
resulting dataset
should handle the
rows from the
current data item if
there is no match in
between values that
were specified in the
data item link, and
data items that are
higher in the data
model hierarchy.
You can select from the following values:
Use Default Values if No Match – If there
is no match, the column values of the upper
data item is set to default values for the
column data type.
Exclude Row If No Match – If there is no
match, the row is excluded from the
resulting dataset.
SQL Advanced Options – Uses the value of
the SQLJoinType property to determine
how the data is handled if there is no
match.
Additional Reading: To learn more about joining tables through SQL Advanced
Options, refer to the SQL Advanced Options for Data Item Link Types topic in Microsoft
Dynamics Developer and IT Pro Help.
12 - 9
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
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.
n. In the first empty row, in the Type column, select DataItem.
o. In the Data Source column, enter “Vendor”.
15. Add columns for the Name and City fields to the Vendor data item.
a. Select the first empty row.
p. On the View menu, click Field Menu.
q. Select the Name and City fields.
r. Click OK.
12 - 10
Module 12: Queries
s. In the confirmation dialog box, click Yes.
t. In the Name column for the Name field, enter “Vendor_Name”.
u. In the Name column for the City field, enter “Vendor_City”.
17. Add columns for the Currency Code and Direct Unit Cost fields.
a. Select the first empty row.
w. On the View menu, click Field Menu.
x. Select the Currency Code and Direct Unit Cost fields.
y. Click OK.
z. In the confirmation dialog box, click Yes.
aa. In the Name column for the Direct Unit Cost field, enter “Price”.
12 - 11
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
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.
gg. Click OK to accept changes and close the DataItem Link window.
hh. Close the Properties window.
19. Join the Purchase Price data item to the Item and Vendor data items.
a. Select the Purchase_Price data item.
ii. On the View menu, click Properties.
jj. In the DataItemLink property, click the AssistEdit button to open the
DataItem Link window.
kk. In the Field column, select the Item No. field.
ll. In the Reference DataItem column, select the Item data item.
mm. In the Reference Field column, select the No. column.
nn. In the next row, in the Field column, select the Vendor No. field.
oo. In the Reference DataItem column, select the Vendor data item.
pp. In the Reference Field column, select the No. column.
12 - 12
Module 12: Queries
20. Save and run the query, then view the results.
a. On the File menu, click Save.
ss. In the Save dialog box, make sure that the Compiled check box is selected,
and then click OK.
tt. On the File menu, click Run.
12 - 13
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
Note: This is because of the DataItemLinkType property value on the Vendor data item.
It is set to the default value of Use Default Values if No Match. There are rows in the Item
table where the Vendor No. field is blank. Therefore, no matching vendor is found, and any
fields from the Vendor table are blank.
21. 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.
vv. On the View menu, click Properties.
ww. In the DataItemLinkType property, select Exclude Row If No Match.
xx. Close the Properties window.
22. 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.
yy. On the View menu, click Properties.
zz. In the DataItemLinkType property, select Exclude Row If No Match.
aaa. Close the Properties window.
23. Save and run the query, then view the results.
a. On the File menu, click Save.
bbb.In the Save dialog box, make sure that the Compiled check box is selected,
and then click OK.
ccc. On the File menu, click Run.
12 - 14
Module 12: Queries
ddd.Notice that only those rows that have a matching vendor and are listed in
the Purchase Price table are shown.
Note: This is because of the DataItemLinkType property value on the Purchase Price
data item. This is set to the Exclude Row if No Match. There are only a few rows in the
Purchase Price table, and only those items are shown that are represented in the Purchase
Price table.
24. 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.
eee. On the View menu, click Properties.
fff. In the DataItemLinkType property, select Use Default Values if No
Match.
ggg.Close the Properties window.
25. Save and run the query, and then view the results.
a. On the File menu, click Save.
hhh.In the Save dialog box, make sure that the Compiled check box is selected,
and then click OK.
iii. On the File menu, click Run.
12 - 15
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
Filtering Data
There are several ways to filter the data in resulting datasets of queries:
DataItemTableFilter Property
You use the DataItemTableFilter property on data items to apply conditions on one or more
fields of the table to limit the records in the resulting dataset of the query. You can filter on
any field in the table, not just those fields that are included as columns in the resulting dataset.
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
You use the ColumnFilter property on a column to apply a filter condition on a single field.
The ColumnFilter property resembles the DataItemTableFilter property, but there are
differences. The ColumnFilter property has the following behaviors:
Unlike filters that are set by the DataItemTableFilter property, filters that are set
by the ColumnFilter property can be overwritten at run time by calling the
SETFILTER or SETRANGE functions from C/AL code.
If the ColumnFilter property specifies a filter on the same field as the
DataItemTableFilter property, then the filters of the two properties are
combined. To be included in the query dataset, records must meet the condition
of both the filters. For example, if the DataItemTableFilter property sets a filter
on a field to include values less than fifty (<50) and the ColumnFilter property
sets a filter on the same field to include values greater than twenty (>20), then
the resultant filter on the field includes values that are greater than twenty and
less than fifty.
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.
12 - 16
Module 12: Queries
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.
ColumnFilter Specifies the set of predefined filters that are
applied to the field that is specified in the
DataSource property if the user or C/AL code
do not override the value of the filter.
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
12 - 17
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
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.
kkk.Select the Item data item. It is the first row in Query Designer.
lll. On the View menu, click Properties.
mmm. In the DataItemTableFilter property, click the AssistEdit button.
nnn.In the Field column, select the Replenishment System field.
ooo.In the Type column, select CONST.
ppp.In the Value column, enter “Purchase”.
26. 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.
sss. On the View menu, click Properties.
ttt. In the ColumnFilter property, click the AssistEdit button to open the
Column Filter window.
uuu.In the Column field, make sure that the Unit_Cost value is present.
vvv.In the Type field, select FILTER.
www. In the Value field, enter “<>0”.
12 - 18
Module 12: Queries
27. 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.
zzz. On the Edit menu, click New.
aaaa. In the Type column, select Filter.
bbbb. In the Data Source column, select the Vendor No. field.
cccc. Select the Name field under the Vendor data item.
dddd. On the Edit menu, click New.
eeee. In the Type column, select Filter.
ffff. In the Data Source column, select the Vendor Posting Group field.
12 - 19
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
selected, and then click OK.
hhhh. In Object Designer, select query 123456701, Simple Item Query,
and then click Run.
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
In a query, you use a totals method to perform a calculation on a column and return the
calculated value in the resulting dataset. This calculation is frequently called aggregation.
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.
12 - 20
Module 12: Queries
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.
You can also type values directly in the Value column of the OrderBy property in the
Properties window. To sort on multiple columns, separate each column with a comma.
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.
12 - 21
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
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
1. In the column definition for a Date or DateTime column, set the MethodType
property to Date.
30. In the Method property, select the appropriate date method, depending on which
date part you want to retrieve.
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.
The differences in day, month, or year occur when date and time values are retrieved from the
Microsoft Dynamics NAV database table. These values are converted from the regional
settings of the Microsoft Dynamics NAV solution to the UTC date and time. The day, month,
or year is calculated on the SQL server, and then returned to the query dataset as an integer.
This integer does not consider the regional settings of the 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.
12 - 22
Module 12: Queries
Demonstration Steps
1. Order the Simple Item Query by vendor name in alphabetical order, and by
price from highest to lowest.
a. In Object Designer, select query 123456701, Simple Item Query, and
then click Design.
iiii. Select the first blank row, and then on the View menu, click Properties.
jjjj. In the OrderBy property, click the AssistEdit button to open the Order By
window.
kkkk. In the Column field on the first row, select the Vendor_Name
column. Make sure that Direction is set to Ascending.
llll. In the Column field on the second row, select the Price column. Make sure
that Direction is set to Descending.
12 - 23
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
32. Save, compile, close, and then run the query. Then, view the results.
a. On the File menu, click Save.
pppp. In the Save dialog box, make sure that the Compiled check box is
selected, and then click OK.
qqqq. Close the Query Designer.
rrrr. In Object Designer, select query 123456701, Simple Item Query, and
then click Run.
12 - 24
Module 12: Queries
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.
12 - 25
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
34. Select table 18, Customer as the first data item.
a. In the Query Designer window, make sure that Type property is
DataItem.
vvvv. In the DataSource property, select table 18, Customer.
36. Set the properties for Cust_Ledger_Entry data item to link to the Customer data
item, where the Customer No. field of Cust_Ledger_Entry is equal to the No.
field of the Customer table, and to exclude the customers for which there are no
ledger entries.
a. Select the Cust_Ledger_Entry data item, on the View menu click
Properties.
xxxx. In the Properties window for the Cust_Ledger_Entry data item, in
the DataItemLink property click the AssistEdit button.
yyyy. In the DataItem Link window, select Customer No. as Field,
Customer as Reference DataItem, and No. as Reference Field.
zzzz. Click OK.
aaaaa. In the Properties window for the Cust_Ledger_Entry data item,
select Exclude Row If No Match in the DataItemLinkType property.
12 - 26
Module 12: Queries
37. Filter the data item to show only entries of type Invoice and Credit Memo.
a. In the Properties window for the Cust_LedgerEntry data item, in the
DataItemTableFilter property, click the AssistEdit button.
bbbbb. In the Table Filter window, in the Field column select Document
Type, in the Type column select FILTER, and then in the Value column
enter “Invoice|Credit Memo”.
ccccc. Click OK.
ddddd. Close the Properties window for the Cust_Ledger_Entry data
item.
40. Add a column for field Amount (LCY) to the Cust_Ledger_Entry data item.
a. In the Query Designer window, select the Cust_Ledger_Entry data item.
hhhhh. On the View menu, click Field Menu.
iiiii. In the Field Menu window, select the Amount (LCY) field.
jjjjj. Click OK.
41. Specify the Sum totaling for the Amount (LCY) column.
a. In the Query Designer window, select the Amount_LCY column.
kkkkk. Select Totals as the Method Type property.
lllll. Make sure that Sum is selected as the Method property.
12 - 27
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
indicator is shown.
mmmmm. On the View menu, click Properties.
nnnnn. In the OrderBy property, click the AssistEdit button.
ooooo. Select Sum_Amount_LCY as Column, and Descending as
Direction.
ppppp. Click OK
.
43. Set the query properties to return only the top 10 rows.
a. In the Properties window for the query, specify “10” as
TopNumberOfRows.
qqqqq. Close the Properties window for the query.
12 - 28
Module 12: Queries
Results
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.
12 - 29
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
Detailed Steps
1. Set the new chart ID to 123456702-01 and name it as Top 10 Cust. by Revenue.
a. In the Chart Setup Card page, in the ID field, enter “123456702-01”.
uuuuu. In the Name field, enter “Top 10 Cust. by Revenue”.
51. 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.
vvvvv. 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.
12 - 30
Module 12: Queries
12 - 31
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
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.
CLOSE
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:
12 - 32
Module 12: Queries
If you call the OPEN function on a query variable that is currently open
If you call the SETFILTER or SETRANGE functions on a query variable that
is currently open
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.
12 - 33
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
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.
12 - 34
Module 12: Queries
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;
Note: Because no data is retrieved before the query is open, referencing columns in any
way, including for specifying values of filtering functions, is not allowed. Therefore, in this
example, the SETRANGE function is called on the Status column by providing the integer,
instead of option values. If you specify the range by using
SETRANGE(Status,PendingProdOrder.Status::Planned,PendingProdOrder.Status::Released
) before the query is open, a run-time error occurs.
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.
12 - 35
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
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 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.
Both SAVEASCSV and SAVEASXML functions return a Boolean value that indicates
whether the query was successfully saved. If you omit this optional return value and the query
wasn’t successfully saved, then a run-time error occurs.
The following example shows how to export a top number of rows in the resulting dataset of a
query to an XML file.
12 - 36
Module 12: Queries
// 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.
12 - 37
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
12 - 38
Module 12: Queries
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.
12 - 39
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
57. Save the codeunit as 50111, Reset Top 10 Cust. Cred. Limit.
a. On the File menu, click Save.
jjjjjj. In the Save As dialog box, in the ID field, enter “50111”.
kkkkkk. In the Name field, enter “Reset Top 10 Cust. Cred. Limit”, and
then click OK.
Detailed Steps: You can also enter “123456702” in the Subtype property.
63. Declare a global variable for table 18, Customer and make it temporary.
a. In the C/AL Globals window, declare a new variable, and set its Name to
CustTmp.
oooooo. Set its Type to Record, and then set its Subtype to Customer.
pppppp. Select the CustTmp variable, and then on the View menu click
Properties.
qqqqqq. In the Properties window for the CustTmp variable, in the
Temporary property select Yes.
rrrrrr. Close the Properties window.
64. 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.
ssssss. Set the Name of the text constant to Text001.
12 - 40
Module 12: Queries
tttttt. Set the ConstValue of the text constant to “Do you want to reset
the %1 to %2 for these customers?”
65. 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.
uuuuuu. Set the Name of the text constant to Text002.
vvvvvv. Set the ConstValue of the text constant to “Action completed
successfully.”
wwwwww. Close the C/AL Globals window.
Top10Cust.SETFILTER(Sum_Amount_LCY,'>%1',0);
Top10Cust.OPEN;
END;
Top10Cust.CLOSE;
69. Write code so that each iteration cycle copies the customer information into the
CustTmp temporary table.
a. In the C/AL Editor window, enter the following code to the BEGIN/END
block of the iteration.
Cust.GET(Top10Cust.No);
CustTmp := Cust;
CustTmp.INSERT;
12 - 41
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
Task 4: Apply the business rule
IF CustTmp.FINDSET THEN
REPEAT
Cust.GET(CustTmp."No.");
Cust.MODIFY;
UNTIL CustTmp.NEXT = 0;
MESSAGE(Text002);
2. Add a function that asks for a confirmation by showing the text constant
Text001. If it is confirmed, it runs the ResetCreditLimit function. Set the
function name to ConfirmReset.
a. In the C/AL Editor window, on the View menu, click C/AL Globals.
aaaaaaa. In the Functions tab, declare a new function named ConfirmReset.
bbbbbbb. Close the C/AL Globals window.
ccccccc. Enter the following code in the ConfirmReset function trigger.
IF CONFIRM(Text001,
FALSE,
12 - 42
Module 12: Queries
0)
THEN
ResetCreditLimit;
73. 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.
12 - 43
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
ConfirmReset;
12 - 44
Module 12: Queries
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.
12 - 45
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
The following table shows the comparison between record and query iteration loops.
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.
12 - 46
Module 12: Queries
Reading from multiple Query A query translates into a
tables single Transact-SQL
statement that returns a
single dataset. Reading from
multiple tables with records
requires multiple, usually
nested, iterations. These
iterations frequently
decrease performance.
Reading a limited subset of Query FIND(‘-‘) and FINDSET
fields from multiple tables, retrieve and return all fields
especially if Microsoft SQL from the table. This makes
Server can use a covering them slower and requires
index strategy more resources. Query only
retrieves and returns those
fields that are declared as
columns in the query data
model. A covering index
includes all of the fields that
a query requires, so
Microsoft SQL Server can
only access the index
without even accessing the
table itself.
Reading summarized data Query Queries can take advantage
(filtered and aggregated of Transact-SQL
data) aggregation functions and
other capabilities to return
summarized data more
efficiently than reading and
iterating through the sets to
perform aggregations.
Handling large quantities of Query When you read large
data in read-only mode quantities of data, queries
provide better performance
than records.
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.
12 - 47
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
SELECT Row of Type Column in the Query Designer
window
FROM Row of Type DataItem in the Query Designer
window
JOIN type DataItemLinkType and SQLJoinType query
properties
ON DataItemLink data item property
WHERE DataItemTableFilter data item property
ColumnFilter property of columns and filters
Row of Type Filter
HAVING ColumnFilter property of columns and filters,
when aggregation is used
GROUP BY Automatically switched on for each row of Type
Column, when aggregation is used
ORDER BY OrderBy query property
TOP TopNumberOfRows query property
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.
12 - 48
Module 12: Queries
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
12 - 49
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
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?
( ) Source for pages or data items on reports; data export through XMLports;
iterating through rows of data in C/AL.
( ) 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?
3. How do you specify that the query should only return the year from a date column?
12 - 50
Module 12: Queries
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
6. You can programmatically filter query results by using SETRANGE and SETFILTER
functions.
( ) True
( ) False
7. Which function do you use to save query results into an XML file?
8. Which function do you use to save query results into a delimited text file?
12 - 51
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
( ) Source for pages or data items on reports; data export through XMLports;
iterating through rows of data in C/AL.
( ) 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
12 - 52
Module 12: Queries
(√) OnBeforeOpen
( ) OnBeforeOpenQuery
( ) OnOpen
( ) OnRun
( ) OnBeforeRun
6. You can programmatically filter query results by using SETRANGE and SETFILTER
functions.
(√) 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
12 - 53
C/SIDE Introduction in Microsoft Dynamics® NAV 2013
12 - 54