ASQL
Introduction
This document provides an introduction to the Matrix42 query language ASQL and covers the most important functions in everyday use.
Within the Matrix42 Service Store, ASQL is used for defining:
- Column Definitions of Data Queries (see examples outlined in red in the screenshot below):
- Calculated fields (see example outlined in red in the screenshot below):
- Display expressions in Data Definitions and Configuration Items (see example outlined in red in the screenshot below):
- Filter criteria in the Dataset Views (see example outlined in red in the screenshot below):
- Structures for the Navigation Items (normally, in structures you don't see ASQL in the UI)
- Quick Filter
- Script Definition Parameter Expressions
We use ASQL expressions in two different contexts:
- To define the attributes we want to query from a class (the base class) and its related classes.
- To restrict the result of a query to a subset of the instances (rows) of the base class (e.g. have only incidents with status "Closed" displayed for you).
We call the first a display expression and the second a WHERE clause. These two share in principle the same syntax with four differences:
- A display expression contains, separated with commas, often more than one expression (for example,
ReactionTimeEscalated as ReactionTime, IncidentSolutionTimeEscalated as SolutionTime, [...]
. You will not see ASQL in the UI, such ASQL expressions will be created for you in the background), while a where clause always only contains one expression. - The expressions in a display expression must define an alias if they are not direct attributes of the base class. This alias is used to name the columns in the result and must be unique in the result. Have a look at this example:
lastname, firstname, T(SPSCommonClassBase).State.DisplayString as state
. In this example, lastname and firstname are direct attributes of the base class, while T(SPSCommonClassBase).State.DisplayString is an expression and it's not a direct attribute of the base class, so you must define an alias "state", the name of the column. - The expressions in a display expression must have unique results for each instance (row) of the base class. You cannot display the children of a 1-N relation, because there may be more than one child.
- A WHERE clause must always be of type Boolean expression (i.e. a WHERE clause must be true or false).
You will not see the ASQL code mentioned in the above paragraph in the UI. You are well advised to get your hands on our QueryAnalyzer tool.
Simple Queries for display expressions
An ASQL display expression serves to define the attributes we want to query from a class (the base class) and its related classes. It is built up of expressions containing:
- Identifiers of data definitions (classes) or attributes (including relation attributes)
- Functions
- Constants
- Operators
Example:
The simplest query for display expressions in ASQL is the query of attributes of an object type class base. The object type (configuration item) “Computer“ (SPSComputerType) has the class base SPSComputerClassBase.
Valid ASQL queries for e.g. being used for column definitions could be:
- ManagementTypeValue of computer attribute ManagementType
- ‘KA_’+ NameValue of computer attribute Name leaded by the string ‘KA’
- IsNull(IPAddress, ‘IP not available’)Value of computer attribute IPAddress if not Null, else the string ‘IP not available’
If you are already familiar with normal SQL, in most cases you just can imagine to place these ASQL queries between “SELECT” and “from SPSComputerClassBase” and you will get the according SQL query.
Simple Queries for WHERE clauses
An ASQL WHERE clause serves to restrict the result of a query to a subset of the instances (rows) of the according base class. It is built up of expressions containing:
- Identifiers of data definitions (classes) or attributes (including relation attributes)
- Functions
- Constants
- Operators
Example:
The simplest query for WHERE clauses in ASQL is the query of attributes of an object type class base. The object type (configuration item) “Computer“ (SPSComputerType) has the class base SPSComputerClassBase.
Valid ASQL queries for e.g. being used for quick filters could be:
- ManagementType=0 All Computers where ManagementType = 0 [manually]
- Name like ‘KA%‘ All Computers where the name starts with KA
- IPAddress IS NOT NULL All computers that have an IP address
If you are already familiar with normal SQL, in most cases you just can imagine to add “SELECT * from SPSComputerClassBase WHERE” at the beginning of these ASQL queries and you will get the according SQL query.
Queries across several Class Bases (Navigate relations)
By default, ASQL queries are always used in a defined context of an object type (configuration item) and one specific class base (data definition).
The simplest relation navigation mechanism is to access related classes defined in the data model as relations from the base class is to use the relation name. For navigating relations starting from the base class you can use the simple “.”-syntax:
<RelationName>.<AttributeName>
Examples (context SPSComputerClassBase):
AssignedAccounts.AccountName like ‘XYZ’
All computers which are assigned to the account XYZAssignedAccounts.Owner.ID IS NOT NULL
All computers which have a person assigned
But, additionally, an object type (configuration item) may have several class bases (data definitions) with attributes.
Example:
The object type SPSComputerType contains the following class bases:
- SPSComputerClassBaseClass base for computers
- SPSAssetClassBaseClass base for assets
- SPSlnventoryClassBaseClass base for inventory data
To access classes that are declared in an object type but are not the base class in context the T-Operator is used (see the following chapter for details).
In some special cases, like e.g. on defining Compliance Rule conditions, there is no specific class base in context, but just an object type. In these cases, you can navigate to all contained classes in the type in context using the expression:
Related<ClassName>.<AttributeName>
Examples (context SPSComputerType):
RelatedSPSAssetClassBase.lnventoryNumber
Inventory Number of the computerRelatedCommonClassBase.Location.Name
Location of the computerRelatedComputerClassBase.ManagementType=0
All computers where ManagementType = 0
T-Operator
You can reach attributes as well as relations for different DDs in CIs with the T-Operator.
Syntax:
T(<ClassName>).<AttributeName>
T(<ClassName>).<RelationName>.<AttributeName>
Examples (context SPSComputerClassBase):
-
T(SPSAssetClassBase).lnventoryNumber
Inventory number of a computer -
T(SPSCommonClassBase).Location.Name
Location name of a computer
In the above examples, lnventoryNumber is an attribute of the asset class base and the assigned Location is the name of the relation from the common class base to the location class base.
Relations only store the ID. For example, in the case of the principal user relation, the asset class base contains the ID of the user class base. The two classes [asset & user] are fully connected and by using the relation name, all attributes of the related class can be reached.
You can either simply define the target attribute you want to display or modify the display name by an expression.
Example:
Display of the first name of the main user:
T(SPSAssetClassBase).AssignedUser.FirstName
Create a display expression:
T(SPSAssetClassBase).AssignedUser[LastName + ISNULL(‘, ’+ FirstName,’’)]
If you do not define a target attribute, the system will show by default the display expression defined in the target class.
Directive Attributes
[Expression-ObjectID] - refers to object ID in current context;
[Display-Expression] - returns the diplay string of the object
Advanced
Refer to this section to learn about advanced ASQL in Matrix42.
Relation Brackets
Instead of the point notation to navigate relations, it is possible to change the context completely to the relation target data definition. The syntax element for this is the “[…]” element. Between the brackets, you can use the elements of the related element without the need to provide the full path. Best explained by an example.
You want to navigate from an account (SPSAccountClassBase) to the owner (relation attribute “owner”), that is the person that owns an account (SPSUserClassBase). And you want the lastname and the firstname of the person, combined by addition separated by a comma. (We assume both values are set).
Point Syntax
-
owner.LastName + ', ' + owner.FirstName
Bracket Syntax
-
Owner[LastName + ', ' + FirstName]
Forcing Inner Join
Relations in ASQL are normally implemented by left joins on the SQL layer. An expression like
owner.LastName = 'Smith'
will produce SQL code that looks similar to this
Select ..... From ... SPSUserClassBase [T-0] Left Join SPSAccountClassBase [T-1] on [T-0].ID=[T-1].Owner .... Where [T-1].LastName='Smith'
ASQL offers an alternative syntax to force the usage of inner joins on the SQL layer.
owner.=LastName = 'Smith'
A similar syntax exists for the relation bracket
Owner[=LastName + ', ' + FirstName]
There are very special cases where forcing inner join is beneficial (see the attention box in the subquery section), but normally you should avoid it. In general, it is not recommended to use it without a good reason as the side-effects might change your results in unexpected ways.
Aliases
The ASQL processor can inject special aliases into an expression.
Samples are
- the base alias in normal ASQL expressions, used to bind subqueries to the external scope (see subquery).
- Inside a subquery the alias for the BaseClass.
- The production and staging alias in the GDI matching or relation expressions.
An alias is used as the starting point for further expressions, in general if an alias is injected the empty scope is no longer available, all expressions must be based on some alias.
Example: get all persons with more than one account (using subquery and count), the aliases used here are base
and A
.
Subquery(SPSAccountClassBase as A, count(all, A.*), A.Owner =base.ID) > 1
Operators
- Arithmetic operators:
+, -,*,/
- Binary operators:
|, &, ^
- Compare operators:
=, <=, =<, =>, >=, <, >, <>, LIKE, IS [NOT] NULL
- Logical operators:
AND, OR, NOT
- Subquery operators:
IN, EXISTS
Literal Expressions
You can provide constants for nearly all valid datatypes in ASQL
- String
Starts and ends with a'
, if you need to escape a'
add a double''
'Smith''s'
- Datetime
Starts and ends with a # and has always a date part and an optional time part. The format is always#yyyy-MM-dd#
or#yyyy-MM-dd hh:mm:ss#
#1986-03-31 14:12:56#
- Guid
Guids are string literals of a special format.
'BEED92AB-5BBB-E811-CBB6-106530557A87'
Internally the system tries to cast guid literals to uniqueidentifiers, the corresponding data type in sql server. This is done to improve performance. But in case a guid is from an external sourcs and is stored as a string attribute (The SMS ID or the BIOS ID) you will have difficulties with compare operations between strings and uniqueidentifiers. To prevent the automatic cast add an N before the literal Guid.
N'BEED92AB-5BBB-E811-CBB6-106530557A87'
- Hexadecimal expressions
These are used for blob fields; a hex literal always starts with 0x and then an arbitrary number of hex digits.
0xafe4ed2389
- Numbers
Only simple integer or float numbers are possible. The decimal point for float numbers is always a point, independent of the cultural settings.
12894
3.14159
Functions
SUBQUERY Function
You can use a subquery in different ways in Matrix42. Normally, you can use a subquery in Column Definitions, and in WHERE Conditions. Use subqueries for performance reasons in Matrix42; subqueries often perform faster when used together with NM relations. Aggregate functions normally only work together with subqueries in Column Definitions.
Example from Matrix42 UI:
Below is the complete Value from the above screenshot:
ID in SUBQUERY([SchemaRelation-SPSSecurityClassRole2SPSUserClassBase] as roles, roles.=members.=T(SPSScRoleClassBase).=AddressedActivities.=ID, roles.MemberOf = CURRENTUSERID())
We use here the inner join syntax without any side-effects inside the subquery as it is independent of the outer scope, there is no base alias inside of the subquery.
Below is an example of how a subquery can be used in Display Expressions.
Shows the amount of accounts for persons:
SUBQUERY(
SPSAccountClassBase as account,
COUNT(all, account.*),
account.owner=base.ID)
Generally, the SUBQUERY function is used to query related classes or to limit the result set.
Syntax:
SUBQUERY (<BaseClass> AS <Alias>, <TargetAttribute>, <Filter>)
In which:
<BaseClass>
BaseClass for the SubQuery<Alias>
The alias will be used for the <TargetAttribute> and <Filter><TargetAttribute>
Defines the result set for the Subquery<Filter>
Limits the result set
The Subquery function can also be used as an argument for the in operator or an argument for the exists method.
Example:
We want a column in the list view for persons (SPSUserType
with SPSUserClassBase
) to show the number of assets they have assigned.
=SUBQUERY(SPSAssetClassBase AS ACB, Count(all, ACB.*), ACB.AssignedUser.ID=base.ID)
When you do counting (or you are using other aggregate functions) it is the best approach to count directly the Class you want to count, in this example SPSAssetClassBase
.
You might also use this
SUBQUERY(
SPSUserClassBase as user,
COUNT(all, user.AssignedAssets.*),
user.ID=base.ID)
but this will always count a minimum of 1 (even if there are no assets!) as there is always a user row in the subquery that has the same ID as the base user row. To understand this as someone familiar with SQL, ASQL will translate this to a Left Join, so the user row in the subquery is always part of the result set. You may solve this by using the inner join syntax
user.=AssignedAssets.*
but it is harder to understand and maintain than directly counting the SPSAssetClassBase. What you should always avoid is relation navigation on the base alias like this
ACB.ID=base.AssignedAssets.ID /*don't do this!*/
as it will introduce an additional join on the outer scope of the subquery and this might change the expected result and may even break your query. Best use the base alias with the ID or directly a physical existing relation attribute, never a virtual attribute! And don't navigate relations on the base alias, always navigate on the inner alias.
CASE Function
The CASE function allows you to discriminate between various cases depending on the values displayed.
Syntax:
CASE WHEN <attribute> = <value> THEN ‘Condition1 met‘ ... ELSE ‘No condition met‘ END
In our example we will use the SQL function DateDiff(), which calculates the time difference between an attribute and the current date (getdate()) in the context of SPSContractItemClassBase
.
=CASE WHEN DateDiff(month, getdate(), ValidUntil) < 0 THEN ‘expired’ ELSE ‘active’ END
Special Functions
- CurrentUserID()
CurrentUserID ( )
Returns the ID column of the SPSUserBaseClass for the current logged in user in Console. - InteractiveUserID()
InteractiveUserID ( )
Returns the ID column of the SPSUserBaseClass for the current logged in user in portal. - Recursive()
RECURSIVE ( relation_identifier )
Provides all object instances of an hierarchical tree structures that are part of a parent or child branch. Can be used only for the following classes (data definitions): SPSOrgUnitClassBase, SPSLocationClassBase, SPSScCategoryClassBase, SPSArticleCategoryClassBase.
Examples:Recursive(OUFor).T(SPSOrgUnitClassBase).Name='XYZ'
Context: SPSOrgUnitClassBase. Provides all Organization Units that are part of the parent branch of the Organization Unit XYZ.T(SPSCommonClassBase).Recursive(OU).
T(SPSOrgUnitClassBase).Name='XYZ'
Context: SPSOrgUnitClassBase. Provides all Organization Units that are part of the child branch of the Organization Unit XYZ.Recursive(Parent).Name='Service Desk'
Context: SPSScCategoryClassBase. Provides all Categories that are part of the parent branch of the Category Service Desk.
- Join()
JOIN( <TargetClass>, <Predicate>)
Defines a custom relational join between 2 data definitions. It can be used like a relation attribute, but the join condition can be defined. In the condition you can use all direct attributes from the left side (the context) with the alias L and all direct attributes from the TargetClass with the alias R.
Example:
Join(SPSAccountClassBase, R.AccountName like L.LastName + ’%,%’ + L.FirstName).ID IS NOT NULL
Context: SPSUserClassBase. A condition to find all users where an account exists with an account name like <lastname, firstname> - TypeContext()
TYPECONTEXT( <TargetCI> )
Defines an alias for a relation to the type class of a datadefinition. This is especially needed if you want to navigate from a commonclass to a type class. You cannot use the UsedInType column as the relation attribute is unspecific of the type. Normally you can use the T operator for this kind of navigation but for special cases like GDI staging classes you need to use this operator (The T operator is not supported for staging schemas)
Example:
TYPECONTEXT(SPSUserType).RelatedSPSUserClassBase.LastName
Context: SPSCommonClassBase. A way to navigate from the SPSCommonClassBase to the person CI and then to one of its memberclasses. - Combine()
COMBINE(<BaseClass> AS <Alias>, <TargetExpression>, <Filter>)
Provides a list of all concatenated TargetExpressions from the BaseClass that match the filter condition.
Example:SUBSTRING(COMBINE(SPSAccountClassBase as A, ', ' + A.AccountName, A.Owner = base.ID), 3, 100000)
Context: SPSUserClassBase. Provides a list of all accounts of a user with their names separated by a comma. You must remove the first comma by using a substring function.
In case you are using COMBINE() at a N:M relation you need to use the 'Right Side of the Definition - Relation Attribute Name' in your <Filter>. For Security Roles relation from SPSUserClassBase to SPSSecurityClassRole this would be 'Members' resulting in following statement: SUBSTRING(COMBINE(SPSSecurityClassRole as SecRole, ', ' + SecRole.Name, SecRole.Members.ID = base.ID), 3, 100000)
Standard SQL functions
ASQL supports the usage of all important functions provided natively by MS SQL Server’s Transact-SQL syntax. Below you will find the list of supported functions. Please refer to http://msdn.microsoft.com/de-de/library/bb510741.aspx for detailed information about the single functions.
-
Count()
COUNT ( { [ [ ALL | DISTINCT , ] expression ] | * } )
Returns the number of items in a group. COUNT always returns an int data type value. This function can be used only within the SUBQUERY function. -
Sum()
SUM ( expression )
Returns the sum of all the values in the expression. SUM can be used with numeric columns only. Null values are ignored. This function can be used only within the SUBQUERY function. -
Min()
MIN ( expression )
Returns the minimum of all the values in the expression. MIN can be used with numeric and datetime columns only. Null values are ignored. This function can be used only within the SUBQUERY function. -
Max()
MAX ( expression )
Returns the maximum of all the values in the expression. MAX can be used with numeric and datetime columns only. Null values are ignored. This function can be used only within the SUBQUERY function. -
IsNull()
ISNULL ( check_expression , replacement_value )
Replaces NULL with the specified replacement value. -
Coalesce()
COALESCE ( expression [ ,...n ] )
Returns the first nonnull expression among its arguments. -
Reverse()
REVERSE ( string_expression )
Returns the reverse of a string value. -
Left()
LEFT ( character_expression , integer_expression )
Returns the left part of a character string with the specified number of characters. -
Right()
RIGHT ( character_expression ,integer_expression )
Returns the right part of a character string with the specified number of characters. -
LTrim()
LTRIM ( character_expression )
Returns a character expression after it removes leading blanks. -
RTrim()
RTRIM ( character_expression )
Returns a character string after truncating all trailing blanks.
-
Len()
LEN ( string_expression )
Returns the number of characters of the specified string expression, excluding trailing blanks. -
SubString()
SUBSTRING ( value_expression ,start_expression ,length_expression )
Returns part of a character, binary, text, or image expression. -
Replace()
REPLACE ( string_expression,string_pattern,string_replacement)
Replaces all occurrences of a specified string value with another string value. -
PatIndex()
PATINDEX ( '%pattern%' , expression )
Returns the starting position of the first occurrence of a pattern in a specified expression, or zeros if the pattern is not found, on all valid text and character data types. -
GetDate()
GETDATE ( )
Returns the current database system timestamp as a datetime value without the database time zone offset. This value is derived from the operating system of the computer on which the instance of SQL Server is running.
-
DateAdd()
DATEADD ( datepart , number , date )
Returns a specified date with the specified number interval (signed integer) added to a specified datepart of that date. -
DateDiff()
DATEDIFF ( datepart ,startdate ,enddate )
Returns the count (signed integer) of the specified datepart boundaries crossed between the specified startdate and enddate. -
DatePart()
DATEPART ( datepart , date )
Returns an integer that represents the specified datepart of the specified date.
Important: dw(weekday) is not supported -
NewID()
NEWID ( )
Creates a unique value of type uniqueidentifier. -
Cast()
CAST ( expression, data_type, [date_format] )
Explicitly converts an expression of one data type to another.
To cast Date to string, use the "date_format" to specify the date format. Like 'yyyy-MM-dd'