Convert Hive/Spark/Databricks DDL to dbt models compatible with Snowflake...
Transform Hive/Spark/Databricks DDL (views, tables, UDFs) into production-quality dbt models compatible with Snowflake, maintaining the same business logic and data transformation steps while following dbt best practices.
Activate this skill when users ask about:
Do NOT begin manual conversion of tables or views. Hive/Spark/Databricks has partial SnowConvert AI support (tables and views only — UDFs and procedures are NOT supported). Before writing any dbt model for a table or view by hand:
- Run SnowConvert AI on the source DDL to produce Snowflake-compatible SQL.
- Use the
$dbt-migration-snowflakeskill to convert the SCAI output to dbt models.- Only fall back to this skill's manual translation rules for objects SCAI could not convert (check the conversion report for EWIs) or for UDFs/procedures (which require manual conversion).
See the
$dbt-migrationskill for download links and full workflow.
Preserve original object names. The dbt model filename and model name MUST match the original source object name (lowercased, without database/schema prefix). For example,
default.patient_visitsbecomespatient_visits.sql. Do not rename objects during migration unless explicitly requested by the user.
You are a database engineer working for a hospital system. You need to convert Hive/Spark/Databricks DDL to equivalent dbt code compatible with Snowflake, maintaining the same business logic and data transformation steps while following dbt best practices.
I will provide you the HiveQL DDL to convert.
The code will be executed by data engineers who are learning Snowflake and dbt.
Generate the following:
-- dbt model: models/[domain]/[target_schema_name]/model_name.sql
{{ config(materialized='view') }}
/* Original Object: [database].[object_name]
Source Platform: Hive/Spark/Databricks
Purpose: [brief description]
Conversion Notes: [key changes]
Description: [SQL logic description] */
WITH source_data AS (
SELECT
-- Hive BIGINT/INT converted to INTEGER
customer_id::INTEGER AS customer_id,
-- STRING converted to VARCHAR
customer_name::VARCHAR(100) AS customer_name,
-- DECIMAL converted to NUMBER
account_balance::NUMBER(18,2) AS account_balance,
-- TIMESTAMP converted to TIMESTAMP_NTZ
created_date::TIMESTAMP_NTZ AS created_date
FROM {{ ref('upstream_model') }}
),
transformed_data AS (
SELECT
customer_id,
UPPER(customer_name)::VARCHAR(100) AS customer_name_upper,
account_balance,
created_date,
CURRENT_TIMESTAMP()::TIMESTAMP_NTZ AS loaded_at
FROM source_data
)
SELECT
customer_id,
customer_name_upper,
account_balance,
created_date,
loaded_at
FROM transformed_data
## models/[domain]/[target_schema_name]/_models.yml
version: 2
models:
- name: model_name
description: "Table description; converted from Hive/Spark/Databricks [Original object name]"
columns:
- name: customer_id
description: "Primary key - unique customer identifier"
tests:
- unique
- not_null
- name: customer_name_upper
description: "Customer name in uppercase"
- name: account_balance
description: "Current account balance; Foreign key to OTHER_TABLE"
tests:
- relationships:
to: ref('OTHER_TABLE')
field: OTHER_TABLE_KEY
- name: created_date
description: "Date the customer record was created"
- name: loaded_at
description: "Timestamp when the record was loaded by dbt"
## dbt_project.yml (excerpt)
models:
my_project:
+materialized: view
domain_name:
+schema: target_schema_name
::TYPE syntax (e.g.,
column_name::VARCHAR(100), amount::NUMBER(18,2)) to ensure output matches expected data types| Hive/Spark | Snowflake | Notes |
|---|---|---|
| TINYINT/SMALLINT/INT/BIGINT | Same | |
| FLOAT/DOUBLE | FLOAT | |
| DECIMAL | DECIMAL | |
| STRING | VARCHAR | |
| CHAR/VARCHAR | Same | |
| BOOLEAN | BOOLEAN | |
| BINARY | BINARY | |
| DATE | DATE | |
| TIMESTAMP | TIMESTAMP_NTZ | |
| ARRAY |
ARRAY | |
| MAP<K,V> | VARIANT | Use OBJECT_CONSTRUCT |
| STRUCT | VARIANT |
-- LATERAL VIEW -> LATERAL FLATTEN
SELECT * FROM table LATERAL VIEW EXPLODE(array_col) t AS elem ->
SELECT * FROM table, LATERAL FLATTEN(input => array_col) AS f
-- PARTITIONED BY -> Clustering
CREATE TABLE t (...) PARTITIONED BY (dt STRING) ->
CREATE TABLE t (...) CLUSTER BY (dt)
-- External tables
CREATE EXTERNAL TABLE t LOCATION 's3://...' ->
CREATE EXTERNAL TABLE t WITH LOCATION = @stage/path
-- collect_list/collect_set
collect_list(col) -> ARRAY_AGG(col)
collect_set(col) -> ARRAY_AGG(DISTINCT col)
-- size() -> ARRAY_SIZE()
size(array_col) -> ARRAY_SIZE(array_col)
| Hive/Spark | Snowflake | Notes |
|---|---|---|
collect_list(col) |
ARRAY_AGG(col) |
|
collect_set(col) |
ARRAY_AGG(DISTINCT col) |
|
size(arr) |
ARRAY_SIZE(arr) |
|
explode(arr) |
LATERAL FLATTEN(input => arr) |
|
posexplode(arr) |
LATERAL FLATTEN(input => arr) |
Use f.index |
concat_ws(sep, ...) |
CONCAT_WS(sep, ...) |
Same |
nvl(a, b) |
NVL(a, b) or COALESCE(a, b) |
Same |
coalesce(...) |
COALESCE(...) |
Same |
if(cond, a, b) |
IFF(cond, a, b) |
|
unix_timestamp() |
DATE_PART(epoch_second, CURRENT_TIMESTAMP()) |
|
from_unixtime(ts) |
TO_TIMESTAMP(ts) |
|
to_date(str, fmt) |
TO_DATE(str, fmt) |
Same |
date_format(d, fmt) |
TO_CHAR(d, fmt) |
Format codes differ |
datediff(d1, d2) |
DATEDIFF('day', d2, d1) |
Arg order differs |
regexp_replace(...) |
REGEXP_REPLACE(...) |
Same |
regexp_extract(...) |
REGEXP_SUBSTR(...) |
|
split(str, delim) |
SPLIT(str, delim) |
Same |
get_json_object(j, p) |
GET_PATH(PARSE_JSON(j), p) |
| Database | Key Considerations |
|---|---|
| Hive / Spark / Databricks | External tables, PARTITIONED BY, LATERAL VIEW, file formats (PARQUET, ORC), UDFs |
Detailed syntax translation guides are available in the translation-references/ folder.
Copyright Notice: The translation reference documentation in this repository is derived from Snowflake SnowConvert Documentation and is © Copyright Snowflake Inc. All rights reserved. Used for reference purposes only.