CertSafari
    Databricks Certified Data Engineer Professional· Lessons

    Domain 3 · Lesson 19/46

    Querying VARIANT Data with variant_get, Path Syntax, and Variant Functions

    Develop a model and query semi-structured data using the VARIANT data type and related functions (e.g., parse_json, variant_get).

    10 min read
    3% of exam
    5 sources
    Published 2 Oct 2026
    Docs as of 30 Sep 2026

    What you will be able to do

    • Navigate VARIANT values with the :, ., [key], and [index] path operators, including field names that contain special characters
    • Extract typed values with variant_get, try_variant_get, ::, and ?::, and predict when each returns NULL or raises an error
    • Tell a variant NULL from a SQL NULL with is_variant_null
    • Flatten arrays and objects with variant_explode and inspect structure with schema_of_variant

    1.Navigating a VARIANT with path operators

    The examples on this page query a table store_data that has one VARIANT column, raw. It holds a nested store document with top-level fields such as owner, zip code, and fb:testid, and an object store that contains arrays fruit and book and an object bicycle. You navigate VARIANT with the same SQL operators used for JSON strings: : selects a top-level field, . or [<key>] selects a nested field, and [<index>] selects an array element. Array indices are 0-based.

    Selecting a nested object two ways, then indexing into an arraysql
    -- Use dot notation
    SELECT raw:store.bicycle FROM store_data
    
    -- Use brackets
    SELECT raw:store['bicycle'] FROM store_data

    This catches teams migrating from JSON strings: JSON string paths are case-insensitive, but every VARIANT path element is matched case-sensitively. A path that does not exist, or an array index that is out of bounds, returns NULL rather than an error, so a wrong case gives you a column of NULLs, not a failure. A second migration difference: the [*] wildcard for selecting or unpacking every array element is not supported on VARIANT.

    Field names with special characters need escaping. The ['<field>'] form escapes any special character: spaces, periods, colons, and square brackets. Backticks escape only spaces and colons. If a field name contains a period or brackets and you escape it with backticks, you get NULL.

    Escaping field names that contain a space or a colonsql
    -- Enclose a field name that contains special characters in single quotes inside square brackets.
    SELECT raw:['zip code'], raw:['fb:testid'] FROM store_data

    Checkpoint 1 of 5· Check yourself

    A VARIANT column raw contains a top-level field literally named zip.code. Which expression returns its value?

    Sources12

    2.Typed extraction with variant_get and try_variant_get

    The : operator returns a VARIANT. That is why raw:owner displays as "amy", quotes included. To get a typed SQL value, use variant_get(variantExpr, path, type). The path is a JSON path string literal starting at $, and the type is a string literal such as 'string', 'int', or 'double'. The same function exists in PySpark, e.g. variant_get(col("raw"), "$.owner", "string").

    variant_get when the path is found, when it is missing, and when the cast failssql
    -- Simple example
    > SELECT variant_get(parse_json('{"key": 123, "data": [4, {"a": "hello"}, "str"]}'), '$.data[1].a', 'string')
      hello
    
    -- missing path
    > SELECT variant_get(parse_json('{"key": 123, "data": [4, {"a": "hello"}, "str"]}'), '$.missing', 'int')
      null
    
    -- Invalid cast
    > SELECT variant_get(parse_json('{"key": 123, "data": [4, {"a": "hello"}, "str"]}'), '$.key', 'array<int>')
      Error: INVALID_VARIANT_CAST.

    variant_get treats the two failure modes differently. A missing path is not an error: you get NULL. A value that is found but cannot be cast to the requested type raises INVALID_VARIANT_CAST. try_variant_get takes the same arguments but returns NULL in both cases, which makes it the safe option for messy data. The SQL shortcuts work the same way: :: (or cast) casts a path result and behaves like variant_get, while ?:: is the error-tolerant form that matches try_variant_get. :: can also cast a nested object straight into a STRUCT, for example raw:store.bicycle::STRUCT<price DOUBLE, color STRING>.

    The ?:: shorthand is synonymous with try_variant_getsql
    -- These are synonymous to:
    > SELECT '{"key": 123, "data": [4, {"a": "hello"}, "str"]}':data[1].a ?::STRING;
     hello

    Checkpoint 2 of 5· Fill the gap

    Some rows hold a non-numeric price. This query must return price as a DOUBLE and give NULL instead of failing on those rows. Which function fills the blank?

    SELECT  ? (raw, '$.store.bicycle.price', 'double') as price FROM store_data

    Checkpoint 3 of 5· Exam question

    A Lakeflow Spark Declarative Pipeline reads a `VARIANT` column named `payload` where a small fraction of upstream events have a `price` field that is sometimes a string like `"N/A"` instead of a number. The engineer wants to extract `price` as a `DOUBLE` and have any row that fails the cast produce a `NULL` for that column instead of failing the entire pipeline run. Which expression should be used?

    Sources32

    3.Variant NULLs, exploding, and schema inspection

    Each VARIANT function has a JSON-string counterpart, but VARIANT handles casting and NULLs differently from that counterpart. Learn this mapping and you can translate existing JSON-string queries:

    VARIANT functions and their JSON string counterparts
    Variant functionJSON string functionBehavior to remember
    variant_getcast and get_json_objectTakes expression, path, and type; errors on a failed cast
    try_variant_gettry_cast and get_json_objectSame arguments; NULL on a failed cast
    is_variant_nullis nullTrue only for a VARIANT-encoded NULL
    schema_of_variant / schema_of_variant_aggschema_of_json / schema_of_json_aggFall back to VARIANT when types conflict
    variant_explode / variant_explode_outerexplode / explode_outerOutput pos, key, value; key is null for arrays

    A variant can hold two kinds of NULL. A SQL NULL means the value is missing. A variant NULL means the document explicitly contains null. is_variant_null returns true only for a variant NULL, so a missing path, which is a SQL NULL, gives false. The reverse is also true: IS NULL is false for an explicit JSON null, because the VARIANT value itself exists.

    An explicit JSON null is a variant NULL, not a SQL NULLsql
    -- difference between is_variant_null and is null
    > SELECT is_variant_null(v:key), v:key IS NULL
        FROM VALUES(parse_json('{"key": null}')) AS T(v)
      true false

    Because [*] is unavailable, you flatten with variant_explode. It is a table-valued generator, so it goes in the FROM clause with LATERAL, not in the SELECT list. It returns pos, key, and value columns, and key is NULL when you explode an array. If the input is NULL or is not an array or object, variant_explode produces no rows, while variant_explode_outer produces a single row of NULLs. To find out what a document contains, schema_of_variant returns the schema of one value. schema_of_variant_agg merges the schemas across rows and falls back to VARIANT when it finds no common type.

    Exploding a VARIANT object, and then a nested array, with LATERALsql
    SELECT key, value
      FROM store_data,
      LATERAL variant_explode(store_data.raw);
    
    SELECT pos, value
      FROM store_data,
      LATERAL variant_explode(store_data.raw:store.basket[0]);

    Checkpoint 4 of 5· Match them up

    Match each function to what it does

    Tap a term, then the definition that fits it.

    Checkpoint 5 of 5· Exam question

    A team is designing a Delta table with a `VARIANT` column to store nested event attributes. During the design review, several proposals are made about how the `VARIANT` column can be used elsewhere in the table definition and in queries. Which of the following statements are correct limitations of the `VARIANT` data type? (Select all that apply.)(Select 3)

    Sources241

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.variant_get returns NULL whenever it cannot produce a value, including when the cast to the requested type fails.Why is that wrong?

      variant_get returns NULL only for a missing path. A value that is found but cannot be cast raises INVALID_VARIANT_CAST. Use try_variant_get or ?:: to get NULL instead.

      Covered in Typed extraction with variant_get and try_variant_get

    2. 2.JSON-string queries carry over to VARIANT unchanged, including case-insensitive field names and the [*] wildcard for arrays.Why is that wrong?

      VARIANT path elements are matched case-sensitively, and [*] is not supported. Use variant_explode to unpack arrays.

      Covered in Navigating a VARIANT with path operators

    3. 3.is_variant_null returns true for any NULL, including a missing path or a SQL NULL input.Why is that wrong?

      is_variant_null is true only when the variant explicitly stores a null. A missing value is a SQL NULL, which you test with IS NULL.

      Covered in Variant NULLs, exploding, and schema inspection

    Practise it for real

    Build a small VARIANT table and see each extraction and NULL behavior for yourself

    1. 1.Run SELECT parse_json('{"key": 123, "data": [4, {"a": "hello"}, "str"]}') AS v and save it as a temp view or CTAS table.

      Why: parse_json is how JSON text becomes VARIANT.

      You should see: One row containing {"data":[4,{"a":"hello"},"str"],"key":123}. Key order may differ from your input.

    2. 2.Query v:data[1].a, then v:DATA[1].a.

      Why: Shows 0-based indexing and case-sensitive path matching.

      You should see: The first returns "hello" as a VARIANT; the second returns NULL.

    3. 3.Run variant_get(v, '$.key', 'array<int>'), then try_variant_get(v, '$.key', 'boolean').

      Why: Compares the strict and error-tolerant extractors on a bad cast.

      You should see: variant_get raises INVALID_VARIANT_CAST; try_variant_get returns NULL.

    4. 4.Run SELECT * FROM variant_explode(parse_json('[1, "a", {"b": "hello"}]')).

      Why: Shows how to flatten arrays now that [*] is not available.

      You should see: Three rows with pos 0–2, key NULL, and the element values.

    Stuck? Get a nudge

    If step 2 returns NULL for both paths, check the case of the field names first.

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “All variant path elements are matched in a case-sensitive way. JSON strings are case-insensitive.”
      ↩︎ Navigating a VARIANT with path operators
      “When no least common type is identified, the type is derived as VARIANT.”
      ↩︎ Variant NULLs, exploding, and schema inspection
      “The [*] syntax is not support for identifying or unpacking all elements in an array.”
      ↩︎ Exam trap 2
      “column_name:FIELD_NAME and column_name:field_name look for different fields in the stored data.”
      ↩︎ Prediction
      “Checks whether the expression is storing a VARIANT encoded NULL. Use is null to check if the input expression is NULL.”
      ↩︎ Checkpoint
    2. 2.
      “If the path cannot be found, or if the array-index is out of bounds, the result is null.”
      ↩︎ Navigating a VARIANT with path operators
      “A field name that contains a period or square brackets returns NULL when escaped with backticks”
      ↩︎ Navigating a VARIANT with path operators
      “You can also use :: or cast to cast values to supported data types:”
      ↩︎ Typed extraction with variant_get and try_variant_get
      “Because variant_explode is a generator function, you use it as part of the FROM clause rather than in the SELECT list”
      ↩︎ Variant NULLs, exploding, and schema inspection
      “Variant NULLs indicate that the variant explicitly contains a NULL value.”
      ↩︎ Exam trap 3
      “For example, use raw:['zip.code'] to select a field named zip.code”
      ↩︎ Checkpoint
    3. 3.
      “If the object cannot be found or it cannot be cast to type, NULL is returned.”
      ↩︎ Typed extraction with variant_get and try_variant_get
    4. 4.
      “If input is NULL, or is not a VARIANT ARRAY or VARIANT object, no rows are produced.”
      ↩︎ Variant NULLs, exploding, and schema inspection

    Also cited

    Ready to test yourself?

    Practise Databricks Certified Data Engineer Professional in quiz mode.

    Spotted a mistake, or was something unclear? Tell us.