Loading...
Loading...
Provisions BigQuery datasets, ingests staged Parquet files directly into native BigQuery tables by using bq load, and deploys already-translated views from local or Cloud Storage BigQuery Migration Service (BQMS) translation outputs. Use when provisioning target BigQuery datasets for warehouse migrations, batch loading staged Parquet files into native BigQuery tables by using bq load, auditing loaded table row counts, or deploying already-translated BigQuery views into a target dataset. Don't use for extracting source database catalog metadata, translating SQL queries, views, stored procedures, or DDL schemas to GoogleSQL (use bigquery-migration-sql-translator), exporting or unloading source database tables (such as Snowflake, Databricks, Teradata, or Oracle) to Parquet on Cloud Storage, or running post-migration cross-database data validation.
npx skill4agent add google/skills bigquery-migration-data-loaderbq loadgcloudgcloudbqgcloud config set project PROJECT_ID
gcloud config set compute/region REGIONgcloud config set compute/regionbqcompute/regionUS--locationbq~/.bigqueryrcdefault_locationUSEUus-central1europe-west4--locationbqbigquery.googleapis.comstorage.googleapis.comgcloud services enable bigquery.googleapis.com storage.googleapis.comgcloud auth logingcloud auth application-default loginGOOGLE_APPLICATION_CREDENTIALSroles/bigquery.jobUserroles/bigquery.dataEditorbq mkroles/storage.objectViewerpip install pyyaml==6.0.2bqUSEUUSEUus-central1gcloud storage rm -r gs://BUCKET/EXPORT_PREFIXbq rm -r -f PROJECT_ID:DATASET_IDflowchart TD
subgraph 1. Inputs
A1["Translation Output Directory / Cloud Storage URI<br>gs://bucket/translation_output/metadata/"]
A2["Staged Parquet Files<br>gs://bucket/data_unload/TABLE/*.parquet"]
end
subgraph 2. Ingestion Pipeline
B1["1. Ensure Dataset Exists<br>bq mk --dataset --location=LOCATION DATASET"]
B2["2. Concurrent Parquet Ingestion<br>bq load --source_format=PARQUET --replace=true<br>Auto-creates native tables"]
B3["3. Row Count Audit<br>Print BigQuery Row Counts for Comparison"]
B4["4. Deploy Consumption Views<br>Deploys views directly from consolidated views.sql or relations/"]
end
A1 & A2 --> B1 --> B2 --> B3 --> B4[!TIP] Migration workflow context: Before running the loader, translate source schemas and views into GoogleSQL by using theskill and stage exported source table Parquet files in Cloud Storage. After loading tables and deploying views, compare row counts and data aggregates against the source database.bigquery-migration-sql-translator
--translation-metadata-dirbq loadTIMESTAMPDATETIMESTRING(n)NUMERIC(p, s)metadata/config/DATABASE/SCHEMA/*.yamlsourceNameexternalTableNameexternalTableDdlPathrelations/db_DATABASE/schema_SCHEMA/VIEW.sqlviews.sqlCREATE VIEWCREATE OR REPLACE VIEW--parquet-base-uriBASE_URIBASE_URI/SCHEMA/TABLE/*.parquetBASE_URI/TABLE/*.parquetgcloud storage cp -r LOCAL_DIR/SCHEMA gs://BUCKET/data_unload/data_unload/SCHEMA/--datasetbq loadPROJECT_ID="PROJECT_ID"
DATASET_ID="DATASET_ID"
LOCATION="LOCATION"
TABLE_NAME="TABLE_NAME"
BUCKET="BUCKET"
PREFIX="data_unload"
bq show --dataset --project_id=${PROJECT_ID} ${DATASET_ID} >/dev/null 2>&1 || \
bq mk --dataset --project_id=${PROJECT_ID} --location=${LOCATION} ${DATASET_ID}PROJECT_IDDATASET_IDLOCATIONus-central1TABLE_NAMEBUCKET--decimal_target_types=NUMERIC --decimal_target_types=BIGNUMERIC --decimal_target_types=STRINGNUMERICBIGNUMERICSTRINGDECIMAL(p, s)p - s <= 29, s <= 9NUMERICp - s <= 38, s <= 38DECIMAL(38, 10)BIGNUMERICDECIMAL256STRINGbq load \
--project_id=${PROJECT_ID} \
--location=${LOCATION} \
--source_format=PARQUET \
--replace=true \
--decimal_target_types=NUMERIC \
--decimal_target_types=BIGNUMERIC \
--decimal_target_types=STRING \
${DATASET_ID}.${TABLE_NAME} \
"gs://${BUCKET}/${PREFIX}/${TABLE_NAME}/*.parquet"--replace=trueJSONINTERVALRANGETRUNCATE TABLE--replace=false--replace=true--schemaJSON_WRAP_JSON_QUERY_WITH_PARSE_JSON = FalseJSON_QUERY()SAFE.PARSE_JSON()JSONSTRINGJSONTIMESTAMPTIMESTAMPisAdjustedToUTC=falseTIMESTAMP WITHOUT TIME ZONEDATETIMEDATETIMEDATETIME(column)CREATE OR REPLACE TABLE `PROJECT_ID.DATASET_ID.TABLE_NAME` AS
SELECT * REPLACE (DATETIME(created_at) AS created_at)
FROM `PROJECT_ID.DATASET_ID.TABLE_NAME`;bq query \
--project_id=${PROJECT_ID} \
--location=${LOCATION} \
--use_legacy_sql=false \
"SELECT '${TABLE_NAME}' AS table_name, count(*) AS row_count FROM \`${PROJECT_ID}\`.\`${DATASET_ID}\`.\`${TABLE_NAME}\`;"assets/bq_loader_template.pyassets/bq_loader_template.pyassets/bq_loader_template.pySKILL_DIR./bq_loader.pycpSKILL_DIRSKILL.mdcp SKILL_DIR/assets/bq_loader_template.py ./bq_loader.py# CUSTOMIZE:# DEFAULT SCAFFOLDING# CUSTOMIZE: Schema Overrides & Partitioningbq load--time_partitioning_field--clustering_fieldsload_parquet_table()# CUSTOMIZE: Custom View Rewriting & Deployment_rewrite_view_sql()deploy_views()_WRAP_JSON_QUERY_WITH_PARSE_JSON = FalseJSON# CUSTOMIZE: Connection & CLI Wrapperbq--default_kms_keyensure_dataset()--destination_kms_key--reservation_idload_parquet_table()execute_sql()# CUSTOMIZE: Post-Load Auditingaudit_row_counts()# Direct from a Cloud Storage translation_output URI with concurrency:
python3 ./bq_loader.py \
--project "PROJECT_ID" \
--dataset "DATASET_ID" \
--location "LOCATION" \
--translation-metadata-dir "gs://BUCKET/translation_output/metadata/" \
--parquet-base-uri "gs://BUCKET/data_unload/" \
--concurrency 8
# Using local translation output folder:
python3 ./bq_loader.py \
--project "PROJECT_ID" \
--dataset "DATASET_ID" \
--location "LOCATION" \
--translation-metadata-dir "TRANSLATION_OUTPUT/metadata" \
--parquet-base-uri "gs://BUCKET/data_unload/" \
--concurrency 4bqNot found: Table ...All N views successfully deployed across M passes.--project--dataset--parquet-base-urigs://BUCKET/path/--translation-metadata-dir--locationus-central1--concurrency4bq load