Sitemap

Handling CLOB’s in Cloud

3 min readMay 14, 2026

--

# Handling Legacy Oracle CLOB Data in Cloud Databases for Reporting & Analytics

## The Core Problem

Oracle CLOBs store large text payloads (XML, JSON, free-text, serialized objects) that cloud data warehouses and analytics engines don’t support natively. The strategy depends on **what’s in the CLOB**.

Step 1: Classify Your CLOB Content

Step 2: Extraction Strategies

### Option A — Flatten at ETL Layer (recommended)

Use your ETL tool (dbt, Spark, Glue, Dataflow) to decompose the CLOB during ingestion:

```sql

— dbt example: extract fields from a JSON CLOB

SELECT

id,

— Snowflake VARIANT

PARSE_JSON(clob_column):customer_id::STRING AS customer_id,

PARSE_JSON(clob_column):order_total::FLOAT AS order_total,

PARSE_JSON(clob_column):status::STRING AS status

FROM raw.legacy_orders

```

### Option B — Land Raw, Parse in Views

Store the raw text first, then create views that parse on read. Good when the schema is evolving.

```sql

— BigQuery: land as STRING, parse in a view

CREATE OR REPLACE VIEW analytics.orders_parsed AS

SELECT

id,

JSON_VALUE(clob_text, ‘$.customer_id’) AS customer_id,

CAST(JSON_VALUE(clob_text, ‘$.order_total’) AS FLOAT64) AS order_total

FROM raw.legacy_orders_raw;

```

### Option C — Semi-structured Column (Snowflake/Redshift)

If the CLOB schema varies, store as native semi-structured and let analysts query with dot-notation:

```sql

— Snowflake: cast VARCHAR to VARIANT once

ALTER TABLE raw.orders ADD COLUMN clob_parsed VARIANT;

UPDATE raw.orders SET clob_parsed = PARSE_JSON(clob_text);

— Query in Snowflake

SELECT clob_parsed:order_total::FLOAT FROM raw.orders;

```

## Step 3: Oracle-Side Extraction (before migration)

Use `DBMS_LOB` to truncate or export CLOBs that exceed varchar limits:

```sql

— Export CLOB as VARCHAR chunks (Oracle → staging)

SELECT

id,

DBMS_LOB.SUBSTR(clob_column, 4000, 1) AS clob_part_1,

DBMS_LOB.SUBSTR(clob_column, 4000, 4001) AS clob_part_2

FROM legacy_table;

```

For GoldenGate, Qlik or AWS DMS — configure CLOB handling explicitly:

```yaml

# AWS DMS task settings

“LobSettings”: {

“BulkMaxSize”: 32, # KB

“LobMaxSize”: 32,

“EnableLobHighPrecision”: true

}

Get Adithya Karunanidhi’s stories in your inbox

Join Medium for free to get updates from this writer.

```

## Step 4: Platform-Specific Best Practices

### Snowflake

- Cast CLOB → `VARCHAR(16777216)` (max 16 MB)

- Use `PARSE_JSON()` / `PARSE_XML()` + `FLATTEN()` for nested data

- Store raw in `VARIANT` columns for schema-on-read flexibility

### Google BigQuery

- Map CLOB → `STRING` (unlimited size)

- Use `JSON_VALUE`, `JSON_QUERY`, `JSON_EXTRACT_ARRAY` for parsing

- Use `SEARCH` indexes for full-text analytics (GA since 2024)

### Azure Synapse / Fabric

- Map to `NVARCHAR(MAX)` in dedicated pools or `STRING` in serverless

- Use `OPENJSON()` or `JSON_VALUE()` for structured extraction

### AWS Redshift

- Map CLOB → `VARCHAR(65535)` (hard limit — truncation risk!)

- Pre-parse in Glue/Spark before loading; Redshift is not suitable for raw CLOB storage

- Use Redshift Spectrum + S3 Parquet for large text payloads

### PostgreSQL (Aurora, AlloyDB)

- Map to `TEXT` (unlimited) or `JSONB` for JSON CLOBs

- Use GIN indexes on `JSONB` for fast analytics queries

## Step 5: Reporting & Analytics Patterns

**For BI tools (Tableau, Power BI, Looker):**

- Never expose raw CLOB columns — always pre-parse into typed columns in a semantic layer

- Use dbt models as the transformation layer

**For ad-hoc SQL analytics:**

```sql

— Snowflake: lateral flatten a JSON array inside a CLOB

SELECT

o.id,

item.value:product_id::STRING AS product_id,

item.value:qty::INT AS quantity

FROM raw.orders o,

LATERAL FLATTEN(input => PARSE_JSON(o.clob_text):line_items) item;

```

**For full-text search on free-text CLOBs:**

- BigQuery: `SEARCH(table, ‘keyword’)` with search indexes

- Snowflake: `SEARCH()` function or offload to Elasticsearch/OpenSearch

- Postgres: `tsvector` / `tsquery` with GIN index

## Step 6: Data Quality & Size Guardrails

```python

# Spark/Glue ETL: flag oversized CLOBs before load

from pyspark.sql.functions import length, col, when

df = df.withColumn(

“clob_size_flag”,

when(length(col(“clob_text”)) > 65000, “TRUNCATION_RISK”).otherwise(“OK”)

)

# Drop or archive rows that exceed target platform limits

clean_df = df.filter(col(“clob_size_flag”) == “OK”)

```

## Summary

├── JSON/XML → parse to columns (dbt/Spark) OR store as VARIANT/JSONB

├── Free text → VARCHAR/TEXT + search index

├── >64KB → Redshift❌, use Snowflake/BigQuery/Postgres

└── Unknown → land as raw STRING, profile first, then decide

**Recommended general pattern:**

> Land raw as STRING → profile in a staging schema → build typed dbt models → expose clean columns to BI/reporting layer.

This decouples extraction from transformation and lets you handle CLOB schema variations incrementally.

--

--