Data Engineer Associate · Domain 3: Data Transformation and Modeling · 22% of the exam
Task 3.1: Implement data cleaning by reading bronze tables with PySpark/SQL, cleaning nulls, standardizing data types, and writing to new silver tables.
Filling and dropping nulls, casting and parsing dates, trimming and standardizing values, and writing the result to a silver table with saveAsTable or CREATE TABLE AS SELECT.
Study it
Cleaning bronze into silver: nulls, types and standard values
Lesson coming
Sample questions
Try each one before opening the answer. Every option is explained, with the Databricks documentation page that proves it.
Question 1 · choose 1
A bronze DataFrame df has null values in country (a string column) and quantity (an integer column). The silver table must hold 'unknown' for a missing country and 0 for a missing quantity, and no other column may change. Which expression produces this?
A dictionary maps each column name to its own replacement value, so each column gets the right default and other columns are untouched.
Ddf.na.fill(0).na.fill('unknown')
Incorrect
Without a subset, each call fills nulls in all columns of a matching type, so other numeric and string columns change too.
fillna and na.fill are aliases. A dictionary gives per-column replacement values; a single value applies to columns of a matching type, limited by subset if given.
A silver query on serverless compute converts the bronze STRING column signup_date to DATE. A few rows contain values such as 'n/a', and the query fails because ANSI mode is on. The requirement is to keep those rows with a NULL date. Which expression should replace the conversion?
ACAST(signup_date AS DATE)
Bsignup_date::DATE
CCOALESCE(signup_date, '1900-01-01')
Dtry_cast(signup_date AS DATE)
Show the answer and why
ACAST(signup_date AS DATE)
Incorrect
With ANSI mode on, an invalid cast raises a runtime error instead of returning NULL, which is the failure being seen.
Bsignup_date::DATE
Incorrect
The :: operator is shorthand for cast, so it fails on 'n/a' in the same way.
CCOALESCE(signup_date, '1900-01-01')
Incorrect
COALESCE replaces NULL strings only; 'n/a' is not NULL, so it stays and the cast still fails.
Dtry_cast(signup_date AS DATE)
Correct
try_cast returns NULL when a value is not well formed for the target type instead of raising an error.
Serverless compute runs with ANSI mode on, so bad values make cast fail loudly. try_cast keeps the row and yields NULL, which you can count or quarantine later.
A bronze DataFrame df has five columns. Rows with fewer than three non-null values are unusable and must be removed; all other rows must be kept as they are. Which expression does this?
Adf.dropna(how='any')
Bdf.dropna(how='all')
Cdf.dropna(thresh=3)
Ddf.na.fill('')
Show the answer and why
Adf.dropna(how='any')
Incorrect
how='any' drops a row that has even one null, so many usable rows would be lost.
Bdf.dropna(how='all')
Incorrect
how='all' drops a row only when every value is null, so rows with one or two values would stay.
Cdf.dropna(thresh=3)
Correct
thresh drops rows that have fewer than the given number of non-null values, and it overrides how.
Ddf.na.fill('')
Incorrect
Filling nulls keeps every row and changes values, instead of removing the unusable rows.
dropna removes rows; fillna replaces values. how chooses between any and all nulls, and thresh sets a minimum count of non-null values.
In a bronze table, country codes appear as ' us', 'Us ' and 'US'. The silver table must store them as 'US', with no surrounding spaces. Which column expression standardizes them?
Aupper(trim(col('country')))
Binitcap(col('country'))
Cregexp_replace(col('country'), ' ', '')
Dlower(col('country'))
Show the answer and why
Aupper(trim(col('country')))
Correct
trim removes leading and trailing spaces, and upper converts the result to upper case.
Binitcap(col('country'))
Incorrect
initcap capitalizes the first letter of each word, giving 'Us', and keeps the spaces.
Cregexp_replace(col('country'), ' ', '')
Incorrect
This removes the spaces but leaves the mixed case unchanged.
Dlower(col('country'))
Incorrect
lower changes only the case, to the wrong case, and keeps the spaces.
Standardizing text usually combines functions: trim for whitespace, then upper or lower for case.
A bronze STRING column order_day holds dates written as day/month/year, for example '19/10/2026'. The silver table needs a DATE column. Which expression converts it correctly?
Ato_date(col('order_day'))
Bcol('order_day').cast('date')
Cto_date(col('order_day'), 'MM/dd/yyyy')
Dto_date(col('order_day'), 'dd/MM/yyyy')
Show the answer and why
Ato_date(col('order_day'))
Incorrect
Without a format, to_date follows the cast rules for DATE, which expect the year-month-day form, so these strings do not convert.
Bcol('order_day').cast('date')
Incorrect
A plain cast also expects the standard year-month-day form and cannot read day/month/year strings.
Cto_date(col('order_day'), 'MM/dd/yyyy')
Incorrect
This reads the first number as the month, so '19/10/2026' has no valid month and the dates come out wrong or fail.
Dto_date(col('order_day'), 'dd/MM/yyyy')
Correct
Passing the datetime pattern that matches the data, day first, makes to_date parse each value into a DATE.
When strings are not in the standard date form, give to_date the matching datetime pattern. Use try_to_date instead when some values may not parse.
Each night a job rebuilds the silver table main.silver.customers in full from bronze. Dashboards read the table at all hours, and the table's history must be kept so that it can be restored if a rebuild goes wrong. Which statement should the job run?
ADROP TABLE main.silver.customers, then CREATE TABLE main.silver.customers AS SELECT ...
BCREATE OR REPLACE TABLE main.silver.customers AS SELECT ... FROM main.bronze.customers
CINSERT INTO main.silver.customers SELECT ... FROM main.bronze.customers
DTRUNCATE TABLE main.silver.customers, then INSERT INTO it
Show the answer and why
ADROP TABLE main.silver.customers, then CREATE TABLE main.silver.customers AS SELECT ...
Incorrect
Between the drop and the create the table does not exist, concurrent readers can fail, and the dropped table's history is no longer linked to the name.
BCREATE OR REPLACE TABLE main.silver.customers AS SELECT ... FROM main.bronze.customers
Correct
CREATE OR REPLACE replaces the contents in one transaction, keeps the table's identity and history, and lets concurrent readers continue.
CINSERT INTO main.silver.customers SELECT ... FROM main.bronze.customers
Incorrect
INSERT INTO appends, so each nightly run adds another full copy of the data.
DTRUNCATE TABLE main.silver.customers, then INSERT INTO it
Incorrect
These are two separate commits, so readers can see an empty table between them.
For a full rebuild of a table that others read, use CREATE OR REPLACE TABLE: it is atomic, keeps the table's history, and avoids the drop-and-recreate anti-pattern.