string
The KQL string type and its relationship to null
The string type represents UTF-8 text. String literals can use double or single quotes:
print s1 = "hello", s2 = 'world'Strings and Null
Unlike other scalar types, string has no distinct null value. An absent or missing string is represented as the empty string "", so a string variable is always a valid, usable string — there is no "unknown" or "undefined" state. You never need to null-check a string before using it, which simplifies queries and avoids an entire class of null-handling errors.
Because a string is never null, isnull() on a string is always false — use isempty() to test for an empty-or-missing string:
print isnull("") // false — a string is never null
print isempty("") // trueFields read from your data are dynamic — typed by the value stored in each row. A string comparison matches when the stored value is that string; an absent or null field counts as "". This makes string equality with stored data behave predictably: a present value matches its own text, and missing values match "".
For a field attr that is absent or null on a row:
T | where attr == "" // matches (null/absent counts as empty)
T | where attr != "" // does not match
T | where attr in ("") // matchesThis applies to ==, !=, and in. Ordering operators (<, >) and non-string comparisons are unaffected — null == 0 is still false.
isnotempty vs isnotnull
For strings, isnotempty() and isnotnull() are equivalent — both return false for "" and true for any non-empty string.
Prefer isnotempty() for strings because it communicates intent more clearly. When you write isnotempty(name), readers understand you're checking for meaningful content. When you write isnotnull(name), it suggests you're checking for missing data — but for strings, these are the same condition.
// Both are equivalent for strings:
T | where isnotempty(message)
T | where isnotnull(message)
// isnotempty reads better for string checks
T | where isnotempty(name) and isnotempty(email)For non-string types, use isnotnull() — a long value of 0 is not null, but only isnotnull() correctly distinguishes null from zero.
String Comparisons
Strings are compared lexicographically and are an ordered type. By default, string comparison operators are case-sensitive:
T | where name == "Alice" // case-sensitive
T | where name =~ "alice" // case-insensitive
T | where name contains "ali" // case-insensitive substring
T | where name has "alice" // case-insensitive whole-term matchIn contrast to other Kusto implementations where has is significantly faster than contains, Berserk uses bloom filters and other indexing tricks to accelerate all string search operators equally. Case-sensitive variants (contains_cs, has_cs, ==) are fastest since they skip case folding. See Best Practices for how this changes which query patterns to reach for.