coalesce

Use the coalesce() function to return the first non-NULL value from a defined list of input fields or expressions.

Syntax

coalesce (<field_1>, <field_2>, ...<field_n>)

Parameters

Name Type Required Description
field_n Any Yes An arbitrary number of fields or expressions. The function evaluates them from left to right.

Returns

The coalesce() function returns a single value whose data type matches the first non-NULL argument it encounters. If all arguments are NULL, the function returns NULL.

Usage notes

  • Arguments are evaluated strictly from left to right. When a non-NULL value is found, the evaluation stops, and that value is returned.
  • This function is valuable for ensuring data completeness and providing fall-back mechanisms, allowing you to define a prioritized list of data sources for a single field.

Examples

Example 1: Coalescing literal values of different types

Goal: Demonstrate the core "first non-NULL" behavior by providing various literal values, including NULLs, of different data types.

XQL code:

config timeframe = 1d // Sets the query timeframe 
| dataset = sample_xql_raw // Specifies the dataset to use 
| alter chosen_value_str = coalesce(NULL, "Fallback String", "Another Option") // First non-NULL string 
| alter chosen_value_int = coalesce(NULL, 123, NULL, 456) // First non-NULL integer 
| alter chosen_value_bool = coalesce(false, NULL, true) // First non-NULL boolean 
| fields event_id, chosen_value_str, chosen_value_int, chosen_value_bool 
| limit 3 

Explanation: For chosen_value_str, coalesce() skips NULL and returns "Fallback String". For chosen_value_int, it returns 123. For chosen_value_bool, it returns false. This demonstrates the function's ability to handle various data types and select the first available non-NULL literal.

Output:

EVENT_ID CHOSEN_VALUE_STR CHOSEN_VALUE_INT CHOSEN_VALUE_BOOL
101 Fallback String 123 false
102 Fallback String 123 false
103 Fallback String 123 false

Example 2: Coalescing existing fields

Goal: Use coalesce() with existing fields, specifically leveraging a field that can be NULL (dst_domain) and one that is always present (event_description) as a fallback.

XQL code:

config timeframe = 1d // Sets the query timeframe 
| dataset = sample_xql_raw // Specifies the dataset to use 
// dst_domain is NULL for event_id 105, event_description is always present 
| alter primary_or_fallback_description = coalesce(dst_domain, event_description) 
| fields event_id, dst_domain, event_description, primary_or_fallback_description 
| limit 5 

Explanation: For events where dst_domain is not NULL (for example, event 101-104), coalesce() returns the dst_domain. For event 105, where dst_domain is NULL, coalesce() falls back to event_description, providing "Data transformation".

Output:

EVENT_ID DST_DOMAIN EVENT_DESCRIPTION PRIMARY_OR_FALLBACK_DESCRIPTION
101 ec2.amazonaws.com User login successful ec2.amazonaws.com
102 sts.amazonaws.com File access attempt sts.amazonaws.com
103 www.google.com Network connection established www.google.com
104 dropbox.com System heartbeat dropbox.com
105 NULL Data transformation Data transformation

Example 3: Coalescing multiple JSON paths for a single concept

Goal: Handle variations in JSON data where different keys might represent the same logical piece of information (for example, status code under code or error).

XQL code:

config timeframe = 1d // Sets the query timeframe 
| dataset = sample_xql_raw // Specifies the dataset to use 
// Extract 'code' or 'error' from JSON, using the first available 
| alter status_code = coalesce(simple_json_data -> code, simple_json_data -> error) 
| fields event_id, simple_json_data, status_code 
| limit 3 

Explanation: For event 101, code (200) is found first. For event 102, code is not present, so error ("access_denied") is returned. For event 103, neither code nor error_code exists, resulting in NULL.

Output:

EVENT_ID SIMPLE_JSON_DATA STATUS_CODE
101 {"status": "ok", "code": 200} 200
102 {"status": "fail", "error": "access_denied"} access_denied
103 {"connection_id": "CONN-001", "protocol": "TCP"} NULL

Example 4: Coalescing complex nested JSON paths for a unified identifier

Goal: Extract a "principal name" from multiple possible nested JSON paths within the nested_json_data field, such as user.name, process.name, client.id, or db.name.

XQL code:

config timeframe = 1d // Sets the query timeframe 
| dataset = sample_xql_raw // Specifies the dataset to use
| filter event_id in(101, 102, 108, 109, 110)
// Attempt to find a 'principal_name' from various nested JSON paths 
| alter principal_name = coalesce( 
    nested_json_data -> user.name, 
    nested_json_data -> process.name, 
    nested_json_data -> client.id, 
    nested_json_data -> db.name 
) 
| fields event_id, nested_json_data, principal_name 
| limit 5 

Explanation: For event 101, user.name ("Alice") is found first. For event 102, user.name is missing, but process.name ("cmd.exe") is present. For event 108, none of the specified paths exist, resulting in NULL. For event 109, client.id ("C2") is found. For event 110, db.name ("prod_db") is found.

Output:

EVENT_ID NESTED_JSON_DATA PRINCIPAL_NAME
101 {"user": {"id": "U1", "name": "Alice"}, "session": {"start": "10:00", "type": "web"}} Alice
102 {"process": {"name": "cmd.exe", "pid": 1234}, "target": {"path": "/var/log", "permission": "rwx"}} cmd.exe
108 {"system":{"hostname":"webserver01","os":"Linux"},"patch":{"version":"1.2.3"}} NULL
109 {"client":{"id":"C2","api_key":"xyz"},"request":{"endpoint":"/data","rate":100}} C2
110 {"db":{"name":"prod_db","type":"SQL"},"storage":{"location":"S3","cost_usd":15}} prod_db

Example 5: Selecting the first non-null username from multiple fields

Goal: Evaluate three different username fields (actor_primary_username, os_actor_primary_username, and causality_actor_primary_username) and return the first available (non-null) value to populate a single username column.

XQL code:

|dataset = sample_xql_raw
| fields actor_primary_username,
       os_actor_primary_username,
       causality_actor_primary_username 
| alter username = coalesce(actor_primary_username,
                          os_actor_primary_username,
                          causality_actor_primary_username) 

Explanation: The coalesce() function checks the provided arguments in order from left to right. The function returns the value of the first field that is not null. If actor_primary_username is null, it checks os_actor_primary_username, and so on. This is a common technique for normalizing data when the same information might be stored in different fields depending on the event source.

Output:

actor_primary_username os_actor_primary_username causality_actor_primary_username username
null "admin_user" "system" "admin_user"
"jsmith" "jsmith_os" null "jsmith"
null null "root" "root"
null null null null