Type Casting: Intermediate
TRY_CAST and Safe Conversion
Spot questions where type casting is the hidden requirement: string dates, numeric strings, decimal precision.
Three concerns this lesson covers
- ▸"the source is TIMESTAMPTZ; the target is TIMESTAMP; conversion?"
- ▸"NUMERIC(20,4) vs DECIMAL(38,9) in cross-engine migration"
- ▸"the JOIN is slow because one column is INT and the other is BIGINT"
- ▸"the column type changed last release; downstream queries need updates"
- ▸"the precision differs; we're losing pennies on aggregation"
String-to-Date and Date-to-String
Write explicit type conversions and use TRY_CAST to handle dirty data that fails conversion.
The three timestamp flavors
Casting TIMESTAMPTZ to TIMESTAMP
Engines differ on default behavior
The DST conversion edge case
Decimal Precision and Rounding
Avoid the integer division trap (5/2=2) by casting to DECIMAL before dividing, and control precision in financial calculations.
Numeric precision differences
Integer sizes
String length
Boolean and NULL Cast Edge Cases
Parse dates from strings using TO_DATE/PARSE with format strings, and format dates back to strings for output.
The mismatched-type join
The string-vs-typed-column trap
Aligning types during ingestion
Dialect Differences in Casting Rules
Discuss how column types affect storage size, join performance (int vs string keys), and predicate pushdown eligibility.
The migration pattern
Dual-typed columns during migration
Versioned schema contracts
The closing thought
> You are in a data engineering interview at a multi-warehouse company. The interviewer asks: 'We ingest from a Postgres source whose timestamps are TIMESTAMPTZ; we land them in a BigQuery warehouse whose TIMESTAMP is timezone-naive UTC. Walk me through what could go wrong.'
TIMESTAMPTZ to TIMESTAMP drops the zone in whichever zone the session happens to be in, so write (ts_tz AT TIME ZONE 'UTC')::TIMESTAMP and make the conversion explicit; UTC also has no DST, which removes the skipped and repeated local hours.TIMESTAMP is always UTC while DATETIME is naive, Snowflake's default zone is an account setting, and Postgres TIMESTAMPTZ stores UTC but displays in the session zone, so document the convention per column.NUMERIC(10,4) lands cleanly in BigQuery NUMERIC(38,9), but NUMERIC(38,12) silently loses scale, and BigQuery offers only INT64 where Postgres has four integer widths.WHERE customer_id = '12345', forces a cast on every row and kills index use; align types on both sides of every join at the silver layer so downstream models inherit one type contract.Implicit casts hide bugs that only show up in production at 2 AM
- Category
- SQL
- Difficulty
- intermediate
- Duration
- 25 minutes
- Challenges
- 0 hands-on challenges
Topics covered: TRY_CAST and Safe Conversion, String-to-Date and Date-to-String, Decimal Precision and Rounding, Boolean and NULL Cast Edge Cases, Dialect Differences in Casting Rules
Lesson Sections
- TRY_CAST and Safe Conversion (concepts: sqlCast)
The question that recurs in interviews involving multi-system data: 'we ingest from a Postgres source whose timestamps are TIMESTAMPTZ; we land them in a BigQuery warehouse whose TIMESTAMP is timezone-naive UTC. Walk me through what could go wrong.' This is not a CAST question. The candidate who answers with 'I'd cast at the boundary' is missing the conversation about what each engine's type means and what the correct conversion is. The platform-grade answer walks the type semantics and names th
- String-to-Date and Date-to-String (concepts: sqlCast)
Timestamp types are the type-casting area that catches the most engineers. The same logical value (a specific moment in time) can be stored as TIMESTAMP (no timezone, just date and time), TIMESTAMPTZ (an absolute moment with timezone awareness), or DATETIME (engine-specific semantics). Casting between them is not always lossless; conventions differ across engines. The three timestamp flavors TIMESTAMP (without timezone): stores a date and time, no zone information. When displayed, the engine ass
- Decimal Precision and Rounding (concepts: sqlDecimalType)
When data flows between engines (Postgres to Snowflake via ETL; BigQuery to Iceberg via export; federated queries across systems), the type systems have to align. Each engine has its own precision rules, default sizes, and edge cases. Migrations and federations are where the differences surface. Numeric precision differences Postgres NUMERIC defaults to unlimited precision; specifying NUMERIC(10,2) gives 10 total digits with 2 after the decimal. Snowflake NUMBER defaults to (38,0); use NUMBER(10
- Boolean and NULL Cast Edge Cases (concepts: sqlCast)
When joining columns of different types (INT to BIGINT, VARCHAR(50) to VARCHAR(100), or worse, NUMERIC to VARCHAR), the engine inserts an implicit cast. The cast can prevent index usage and can change the comparison semantics. The discipline is to match the types on both sides of the join. The mismatched-type join Most cases where both sides are integer types of different widths work fine; the engine handles the widening cast efficiently. The case that bites is comparing a typed column to a stri
- Dialect Differences in Casting Rules (concepts: sqlStorageOptimization)
The last common intermediate pattern: schema evolution. A column's type changes between releases (INT to BIGINT to support larger values; NUMERIC(10,2) to NUMERIC(20,4) for higher precision; TIMESTAMP to TIMESTAMPTZ for timezone awareness). The migration needs explicit casting and downstream code may need updates. The migration pattern Three steps. First: alter the column to the new type (or add a new column with the new type). Second: backfill historical data with explicit casts. Third: update