Skip to main content

SQL Template

test pypi version PyPI - Python Version size gh license

A SQL Template Generator (aka SqlPlate) provide the generator object for SQL template statements via Python API object. All SQL template files are store in the Jinja template format that is the powerful template tool package.

[!NOTE] This project keep all SQL use-case that use on Data Engineer works like SCD2 with MERGE operator.

The layer of SQL template files will be:

templates/
   ├─ databricks/
   │     ├─ 📂macros/
   │     │     ╰─ ⚙️ delta.jinja
   │     ╰─ 📂latest/
   │           ├─ 📜 etl.delta.sql
   │           ├─ 📜 etl.scd2.sql
   │           ╰─ 📜 select.sql
   ├─ sqlite/
   │     ╰─ 📂latest/
   │           ╰─📜 etl.delta.sql
   ├─ synapse/
   │     ╰─ 📂latest/
   │           ╰─📜 etl.delta.sql
   ╰─ utils/
         ╰─ ⚙️ etl_vars.jinja

[!IMPORTANT] The first object of this project is generate ETL statements for dynamic service change. You can change the SQL compute service while the SQL statement does not change.

:package: Installation

pip install -U sqlplate

:fork_and_knife: Usage

Generate SQL template

Start passing option parameters before generate the Delta ETL SQL statement that will use on the Azure Databricks service.

from datetime import datetime
from sqlplate import SQLPlate

statement: str = (
    SQLPlate.format('databricks')
    .template('etl.delta')
    .option('catalog', 'catalog-name')
    .option('schema', 'schema-name')
    .option('table', 'table-name')
    .option('pk', 'pk_col')
    .option('columns', ['col01', 'col02'])
    .option('query', 'SELECT * FROM catalog-name.schema-name.source-name')
    .option('load_src', 'SOURCE_FOO')
    .option('load_id', 1)
    .option('load_date', datetime(2025, 2, 1, 10))
    .option('only_main', True)
    .load()
)
print(statement.strip().strip('\n'))

The result SQL statement:

MERGE INTO catalog-name.schema-name.table-name AS target
USING (
    WITH change_query AS (
        SELECT
            src.*,
        CASE WHEN tgt.pk_col IS NULL THEN 99
             WHEN hash(src.col01, src.col02) <> hash(tgt.col01, tgt.col02) THEN 1
             ELSE 0 END AS data_change
        FROM ( SELECT * FROM catalog-name.schema-name.source-name ) AS src
        LEFT JOIN catalog-name.schema-name.table-name AS tgt
            ON  tgt.col01 = src.col01
AND tgt.col02 = src.col02
    )
    SELECT * EXCEPT( data_change ) FROM change_query WHERE data_change IN (99, 1)
) AS source
    ON  target.pk_col = source.pk_col
WHEN MATCHED THEN UPDATE
    SET target.col01            = source.col01
    ,   target.col02            = source.col02
    ,   target.updt_load_src    = 'SOURCE_FOO'
    ,   target.updt_load_id     = 1
    ,   target.updt_load_date   = to_timestamp('20250201', 'yyyyMMdd')
WHEN NOT MATCHED THEN INSERT
    (
        col01, col02, pk_col, load_src, load_id, load_date, updt_load_src, updt_load_id, updt_load_date
    )
    VALUES (
        source.col01,
        source.col02,
        source.pk_col,
        'SOURCE_FOO',
        1,
        20250201,
        'SOURCE_FOO',
        1,
        to_timestamp('20250201', 'yyyyMMdd')
    )
;

Data Quality

This package handle generate SQL statement only. For the data quality part, this package can use quality templates instead.

from sqlplate import SQLPlate

statement: str = (
    SQLPlate.format('databricks')
    .template('quality.check')
    .option('catalog', 'catalog-name')
    .option('schema', 'schema-name')
    .option('table', 'table-name')
    .option('filter', "load_date >= to_timestamp('20250201', 'yyyyMMdd')")
    .option('unique', ['pk_col'])
    .option('notnull', ['col01', 'col02'])
    .check("contain", ["col01"], "IN ['A', 'B', 'C']")
    .check("gt_10000", ["col03"], "> 10000")
    .load()
)
print(statement.strip().strip('\n'))

The result SQL statement:

WITH source AS (
    SELECT
        *
    FROM
        catalog-name.schema-name.table-name
    WHERE load_date >= to_timestamp('20250201', 'yyyyMMdd')
)
, records AS (
    SELECT COUNT(1) AS table_records FROM source
)
SELECT
    (SELECT table_records FROM records) AS table_records
    , (SELECT COUNT( DISTINCT pk_col ) FROM source) = table_records AS unique_pk_col
    , (SELECT COUNT_IF( col01 IS NULL ) FROM source) = 0 AS notnull_col01
    , (SELECT COUNT_IF( col02 IS NULL ) FROM source) = 0 AS notnull_col02
    , (SELECT COUNT(1) FILTER(WHERE col01 IN ['A', 'B', 'C']) FROM source) = table_records AS contain_col01
    , (SELECT COUNT(1) FILTER(WHERE col03 > 10000) FROM source) = table_records AS gt_10000_col03
FROM records

:chains: Support Systems

System Progress Status System Integration Test Remark
databricks 🟢 🟡 Azure Databricks
postgres 🔴 🔴
mysql 🔴 🔴
mssql 🔴 🔴 Microsoft SQL Server
synapse 🔴 🔴 Azure Synapse Dedicate SQL Pool
synapse-serverless 🔴 🔴 Azure Synapse Serverless SQL Pool
bigquery 🟡 🔴 Google BigQuery
snowflake 🔴 🔴
sqlite 🟡 🟡
duckdb 🟡 🟡
redshift 🔴 🔴 Amazon RedShift
athena 🔴 🔴 Amazon Athena
trino 🔴 🔴 Trino

[!NOTE]

  • 🟢 Complete
  • 🟡 In progress
  • 🔴 Does not develop yet
  • 🟣 Does not plan to support

:speech_balloon: Contribute

I do not think this project will go around the world because it has specific propose, and you can create by your coding without this project dependency for long term solution. So, on this time, you can open the GitHub issue on this project :raised_hands: for fix bug or request new feature if you want it.

Release files for sqlplate 0.0.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sqlplate 0.0.7
File Size Uploaded
sqlplate-0.0.7.tar.gz 14.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sqlplate 0.0.7
File Interpreter ABI Platform
sqlplate-0.0.7-py3-none-any.whl Python 3 none any Details

Total release size: 24.0 kB

Release files / sqlplate-0.0.7.tar.gz

Download URL sqlplate-0.0.7.tar.gz
Size 14.5 kB
Tags Source
SHA-256 checksum
How to use checksums
6dacd5919a52b8151cd69d8ad0fd64372c0bf88aa9ff191afef91e2183346572
BLAKE2b-256 checksum
How to use checksums
93969e2fe7bafe4c78e97444f605855e6c5e312c7901d408bd9a20e7767be237
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.8

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2025.

Transparency log

Release files / sqlplate-0.0.7-py3-none-any.whl

Download URL sqlplate-0.0.7-py3-none-any.whl
Size 9.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8a0e60b64faada08196e432a786301efd526fc1e06f1e94b127390a4397a593a
BLAKE2b-256 checksum
How to use checksums
fdd8c1490dfd006b6af3bf74398ee893bbe4706b8ef2eed7b9c66c5b71aa6aa4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.8

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.0.7 This release

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page