{"id":17414,"date":"2026-08-04T16:46:23","date_gmt":"2026-08-04T16:46:23","guid":{"rendered":"https:\/\/techtrendfeed.com\/?p=17414"},"modified":"2026-08-04T16:46:24","modified_gmt":"2026-08-04T16:46:24","slug":"the-medallion-knowledge-structure-an-introduction","status":"publish","type":"post","link":"https:\/\/techtrendfeed.com\/?p=17414","title":{"rendered":"The Medallion Knowledge Structure: An Introduction"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<p class=\"wp-block-paragraph\"> are likely to turn out to be tougher to belief as they develop in scope, and so they definitely turn out to be tougher to run with out errors, to doc, and to debug.\u00a0<\/p>\n<p class=\"wp-block-paragraph\">A CSV arrives from one system, JSON comes from one other, a Parquet file from elsewhere. Weeks and months go previous, and earlier than  it, no person is sort of positive which model of the info will be trusted, which guidelines have been utilized to it, or why an error occurred on yesterday\u2019s dashboard.<\/p>\n<p class=\"wp-block-paragraph\">The medallion structure is a sensible response to that drawback. It divides a knowledge platform into three layers, normally known as bronze, silver, and gold. On the boundary of every layer, there ought to be a transparent, documented description of the info contained in that layer. That is very true of the bronze layer, as that&#8217;s the place preliminary ingestion of your knowledge takes place, so that you\u2019ll wish to write down as a lot info as you&#8217;ll be able to concerning the supply of information, who or which system masses it, when it was loaded, how typically it\u2019s loaded, and so forth.<\/p>\n<p class=\"wp-block-paragraph\">In a great world, the info in every layer will get there utilizing instruments equivalent to SQL, Python, dbt and others.<\/p>\n<h2 class=\"wp-block-heading\">The place did the medallion structure come\u00a0from?<\/h2>\n<p class=\"wp-block-paragraph\">The bronze, silver and gold terminology was first proposed by Databricks. Databricks is a knowledge and AI firm whose cloud platform helps organisations course of, handle and analyse giant datasets utilizing applied sciences equivalent to Apache Spark and Delta Lake.\u00a0<\/p>\n<p class=\"wp-block-paragraph\">Databricks describes the medallion construction as a multi-layered sample wherein knowledge high quality improves progressively as knowledge strikes by way of the three layers.\u00a0<\/p>\n<p class=\"wp-block-paragraph\">Sometimes, the bronze degree is used to retailer uncooked, unfiltered knowledge because it arrives from the supply. Information are usually immutable and append-only. <\/p>\n<p class=\"wp-block-paragraph\">Silver accommodates a cleaned-up model of the info in bronze. For instance, null information, invalid dates, lacking fields, and so forth., could be remedied or eliminated earlier than being saved right here.<\/p>\n<p class=\"wp-block-paragraph\">Gold typically accommodates specialised, mixture datasets outlined as SQL (materialised) views derived from Silver that align with enterprise guidelines. For instance, knowledge dashboards and administration studies are normally constructed from knowledge within the Gold layer as a result of the info is appropriate, tends to be smaller, and results in higher accuracy and decrease processing occasions.<\/p>\n<p class=\"wp-block-paragraph\">In fact, techniques like this have been round so long as knowledge has. Most database engineers can have used a \u201cstaging\u201d space to deliver knowledge right into a system earlier than farming it out to the place it\u2019s wanted lengthy earlier than they heard the time period \u201cMedallion\u201d. That\u2019s a easy two-layer medallion system. Databricks simply added one other layer, gave it a flowery title and popularised it.<\/p>\n<h2 class=\"wp-block-heading\">What belongs in every\u00a0layer?<\/h2>\n<p class=\"wp-block-paragraph\">Let\u2019s take a look in barely extra element at what every layer ought to ideally include. Observe that in real-life techniques, the gold, silver, and bronze layers normally correspond to completely different schemas inside a contemporary database or knowledge warehouse.<\/p>\n<h3 class=\"wp-block-heading\">Bronze<\/h3>\n<p class=\"wp-block-paragraph\">Bronze is a document of what arrived from the supply. Helpful bronze knowledge may additionally embody ingestion metadata alongside the supply fields equivalent to<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">supply system and supply file or occasion identifier<\/li>\n<li class=\"wp-block-list-item\">ingestion timestamp and\/or enterprise efficient date<\/li>\n<li class=\"wp-block-list-item\">variety of information ingested<\/li>\n<li class=\"wp-block-list-item\">batch or loading run identifier<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">The way you cope with errors and different kinds of knowledge points at this layer stage is necessary. <\/p>\n<p class=\"wp-block-paragraph\">For unhealthy and\/or lacking knowledge values, these ought to be retained as-is and quarantined on the silver degree if required. If a knowledge load fails half-way by way of, due to a community failure, for instance, the load ought to be marked as failed or outdated and re-loaded as a brand new batch.<\/p>\n<p class=\"wp-block-paragraph\">If further or late knowledge arrives, append it as one other batch and document its supply, ingestion time and business-effective date.<br \/>If the identical supply is submitted twice, use a file hash, batch identifier or supply key to stop unintended duplication.<\/p>\n<p class=\"wp-block-paragraph\">No matter method is taken, ingestion ought to be idempotent. Processing the identical supply supply greater than as soon as shouldn&#8217;t create duplicate information or in any other case change the ensuing state.<\/p>\n<h3 class=\"wp-block-heading\">Silver<\/h3>\n<p class=\"wp-block-paragraph\">Silver applies guidelines to the bronze layer knowledge set that make information reliable and correct sufficient to be usable. Typical transformation work contains,<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">parsing and imposing knowledge varieties<\/li>\n<li class=\"wp-block-list-item\">standardising dates, currencies, nation codes and models<\/li>\n<li class=\"wp-block-list-item\">deduplicating information<\/li>\n<li class=\"wp-block-list-item\">quarantining duff knowledge<\/li>\n<li class=\"wp-block-list-item\">becoming a member of reference knowledge<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">Silver ought to normally retain business-level element. It&#8217;s the clear, foundational knowledge that merchandise and downstream techniques can depend on.\u00a0<\/p>\n<p class=\"wp-block-paragraph\">Getting issues flawed at this degree can actually screw up your downstream techniques and processes. For instance, a silver <strong>order_total<\/strong> column ought to have an outlined forex and numeric kind. An <strong>order_id<\/strong> ought to have a documented uniqueness rule. If a row fails these guidelines, the pipeline wants an express final result, e.g insertion right into a quarantine desk, slightly than a silent omission.<\/p>\n<h3 class=\"wp-block-heading\">Gold<\/h3>\n<p class=\"wp-block-paragraph\">Gold is organised round explicit enterprise use circumstances and processes. Gold sometimes contains:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Summarised and aggregated knowledge units equivalent to totals and counts by day, month, or area (e.g., complete gross sales, lively customers).<\/li>\n<li class=\"wp-block-list-item\">Star schemas or knowledge marts constructed for quick queries with fewer joins.<\/li>\n<li class=\"wp-block-list-item\">Tailor-made, separate knowledge units for particular groups like finance, advertising and marketing, or operations.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">Tying the whole lot collectively here&#8217;s a diagram of what a typical, quite simple, Medallion system may appear to be.<\/p>\n<figure class=\"wp-block-image alignwide size-large\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2026\/07\/call_IcaBEfgHLwMqb7fHEMxxzb7z-1024x413.png\" alt=\"\" class=\"wp-image-676244\"\/><\/figure>\n<h2 class=\"wp-block-heading\">What instruments do I must implement a Medallion sample?<\/h2>\n<p class=\"wp-block-paragraph\">There\u2019s no a method to do that, however as a starter, I\u2019d say that you simply normally implement a medallion structure utilizing some sort of database, knowledge warehouse or cloud-based object storage the place your gold, silver, and bronze layers are sometimes completely different schemas in your database or folders in your object storage. It will work on something from SQLite in your native laptop computer to an AWS Redshift knowledge lake on an enormous cloud-based cluster or AWS S3\/Azure Blob\/Google Cloud Storage.\u00a0<\/p>\n<p class=\"wp-block-paragraph\">Particularly for cloud primarily based object storage you\u2019ll additionally want to consider the open desk format that you simply wish to use. The three most typical are Hudi, Apache Iceberg and Delta tables.<\/p>\n<p class=\"wp-block-paragraph\">By way of the software program tooling for use, I see the medallion sample as simply one other a part of common knowledge engineering (DE). So, the instruments that knowledge engineers use of their day-to-day jobs are the identical ones used to arrange and preserve medallion techniques. SQL will likely be your fundamental go-to, and do not forget that another instruments like dbt depend on SQL beneath the covers too. Apart from SQL, Python, Spark and different programming languages are sometimes used. <\/p>\n<p class=\"wp-block-paragraph\">For cloud primarily based structure you may additionally use instruments particular to that platform. I primarily use AWS, so I might in all probability be utilizing AWS Athena for knowledge querying, AWS Glue for pipeline improvement work and Step for orchestration.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Observe that, aside from being a consumer of the varied techniques and merchandise talked about on this article e.g DuckDB, I&#8217;ve no affiliation or industrial affiliation with any of them.<\/p>\n<\/blockquote>\n<h2 class=\"wp-block-heading\">A working instance: retail orders with Python and\u00a0DuckDB<\/h2>\n<p class=\"wp-block-paragraph\">For this instance, I\u2019m utilizing the nightly CSV export from a small on-line retailer. The file wants some work earlier than it may be used for reporting. Orders could also be repeated, some dates fail to parse, and unfavorable quantities have to be rejected. The pipeline runs in a single day in order that operations has paid and refunded gross sales totals, cut up by area and forex, by 07:00.<\/p>\n<p class=\"wp-block-paragraph\">The pipeline has 5 phases:<\/p>\n<ol class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Retailer every CSV import unchanged within the append-only Bronze desk.<\/li>\n<li class=\"wp-block-list-item\">Convert the fields to the proper varieties, validate the values and take away duplicate orders in Silver.<\/li>\n<li class=\"wp-block-list-item\">Transfer rejected rows right into a quarantine desk for investigation.<\/li>\n<li class=\"wp-block-list-item\">Combination the accepted orders into every day regional gross sales figures in Gold.<\/li>\n<li class=\"wp-block-list-item\">Prevents the identical supply file from being ingested twice.<\/li>\n<\/ol>\n<p class=\"wp-block-paragraph\">Utilizing DuckDB as our database retains the instance small, however the layer contracts translate on to a bigger lakehouse when you want it to.<\/p>\n<p class=\"wp-block-paragraph\">Our mission structure will likely be much like this.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-markdown\">retail-medallion\/\n\u251c\u2500\u2500 knowledge\/\n\u2502   \u2514\u2500\u2500 incoming\/\n\u2502       \u2514\u2500\u2500 orders_2026-07-19.csv    &lt;= manually created by you\n\u251c\u2500\u2500 pipeline.py                      &lt;= manually created by you\n\u2514\u2500\u2500 warehouse.duckdb                 &lt;= this DB file is created by the pipeline<\/code><\/pre>\n<h3 class=\"wp-block-heading\">Create a digital surroundings and set up DuckDB<\/h3>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-powershell\">D:projectsretail-medallion&gt; python3 -m venv .venv\n# Home windows PowerShell: ..venvScriptsActivate.ps1\n# macOS\/Linux: supply .venv\/bin\/activate\nD:projectsretail-medallion&gt; python3 -m pip set up duckdb pytz tabulate <\/code><\/pre>\n<h3 class=\"wp-block-heading\">Creating an enter file<\/h3>\n<p class=\"wp-block-paragraph\">That is only a easy CSV, so open your favorite textual content editor and enter the next knowledge. Reserve it as a file known as orders_2026-07-19.csv beneath the info\/incoming folder.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-markdown\">order_id,ordered_at,customer_id,area,quantity,forex,standing\n1001,2026-07-19T09:10:00Z,C001,North,125.50,GBP,paid\n1002,2026-07-19T10:05:00Z,C002,South,89.99,GBP,paid\n1002,2026-07-19T10:05:00Z,C002,South,89.99,GBP,paid\n1003,not-a-date,C003,North,45.00,GBP,paid\n1004,2026-07-19T11:42:00Z,C004,West,-10.00,GBP,paid\n1005,2026-07-19T12:20:00Z,C005,North,210.00,GBP,refunded<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The duplicate and invalid rows are deliberate and a great check to make sure our pipeline copes when knowledge is unhealthy.<\/p>\n<h3 class=\"wp-block-heading\">Our pipeline code<\/h3>\n<p class=\"wp-block-paragraph\">Save the next code to pipeline.py within the mission\u2019s house listing.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from __future__ import annotations\n\nimport hashlib\nimport sys\nfrom pathlib import Path\n\nimport duckdb\n\nDATABASE = Path(\"warehouse.duckdb\")\n\ndef file_hash(path: Path) -&gt; str:\n    digest = hashlib.sha256()\n    with path.open(\"rb\") as supply:\n        for block in iter(lambda: supply.learn(1024 * 1024), b\"\"):\n            digest.replace(block)\n    return digest.hexdigest()\n\ndef initialise(connection: duckdb.DuckDBPyConnection) -&gt; None:\n    connection.execute(\"CREATE SCHEMA IF NOT EXISTS bronze\")\n    connection.execute(\"CREATE SCHEMA IF NOT EXISTS silver\")\n    connection.execute(\"CREATE SCHEMA IF NOT EXISTS gold\")\n    connection.execute(\"\"\"\n        CREATE TABLE IF NOT EXISTS bronze.ingestion_batches (\n            source_hash VARCHAR PRIMARY KEY,\n            source_file VARCHAR NOT NULL,\n            ingested_at TIMESTAMPTZ NOT NULL DEFAULT current_timestamp\n        )\n    \"\"\")\n    connection.execute(\"\"\"\n        CREATE TABLE IF NOT EXISTS bronze.orders_raw (\n            order_id VARCHAR,\n            ordered_at VARCHAR,\n            customer_id VARCHAR,\n            area VARCHAR,\n            quantity VARCHAR,\n            forex VARCHAR,\n            standing VARCHAR,\n            source_file VARCHAR NOT NULL,\n            source_hash VARCHAR NOT NULL,\n            ingested_at TIMESTAMPTZ NOT NULL\n        )\n    \"\"\")\n\ndef ingest_bronze(connection: duckdb.DuckDBPyConnection, supply: Path) -&gt; bool:\n    supply = supply.resolve()\n    digest = file_hash(supply)\n    already_loaded = connection.execute(\n        \"SELECT 1 FROM bronze.ingestion_batches WHERE source_hash = ?\", [digest]\n    ).fetchone()\n    if already_loaded:\n        print(f\"Skipping {supply.title}: this actual file has already been loaded\")\n        return False\n\n    connection.start()\n    attempt:\n        connection.execute(\n            \"\"\"\n            INSERT INTO bronze.orders_raw\n            SELECT\n                order_id, ordered_at, customer_id, area, quantity,\n                forex, standing, ?, ?, current_timestamp\n            FROM read_csv(?, header = true, all_varchar = true)\n            \"\"\",\n            [source.name, digest, str(source)],\n        )\n        connection.execute(\n            \"\"\"INSERT INTO bronze.ingestion_batches (source_hash, source_file)\n            VALUES (?, ?)\"\"\",\n            [digest, source.name],\n        )\n        connection.commit()\n    besides Exception:\n        connection.rollback()\n        elevate\n    print(f\"Loaded {supply.title} into bronze\")\n    return True\n\ndef build_silver(connection: duckdb.DuckDBPyConnection) -&gt; None:\n    connection.execute(\"\"\"\n        CREATE OR REPLACE TEMP VIEW typed_orders AS\n        SELECT\n            trim(order_id) AS order_id,\n            try_cast(ordered_at AS TIMESTAMPTZ) AS ordered_at,\n            trim(customer_id) AS customer_id,\n            higher(trim(area)) AS area,\n            try_cast(quantity AS DECIMAL(18, 2)) AS quantity,\n            higher(trim(forex)) AS forex,\n            decrease(trim(standing)) AS standing,\n            source_file,\n            source_hash,\n            ingested_at,\n            row_number() OVER (\n                PARTITION BY trim(order_id)\n                ORDER BY ingested_at DESC, source_file DESC\n            ) AS duplicate_rank\n        FROM bronze.orders_raw\n    \"\"\")\n    legitimate = \"\"\"\n        order_id IS NOT NULL AND order_id &lt;&gt; ''\n        AND ordered_at IS NOT NULL\n        AND customer_id IS NOT NULL AND customer_id &lt;&gt; ''\n        AND quantity IS NOT NULL AND quantity &gt;= 0\n        AND forex IN ('GBP', 'EUR', 'USD')\n        AND standing IN ('paid', 'refunded', 'cancelled')\n        AND duplicate_rank = 1\n    \"\"\"\n    connection.execute(f\"\"\"\n        CREATE OR REPLACE TABLE silver.orders AS\n        SELECT * EXCLUDE (duplicate_rank)\n        FROM typed_orders\n        WHERE {legitimate}\n    \"\"\")\n    connection.execute(f\"\"\"\n        CREATE OR REPLACE TABLE silver.orders_quarantine AS\n        SELECT\n            * EXCLUDE (duplicate_rank),\n            CASE\n                WHEN duplicate_rank &gt; 1 THEN 'duplicate order_id'\n                WHEN ordered_at IS NULL THEN 'invalid ordered_at'\n                WHEN quantity IS NULL THEN 'invalid quantity'\n                WHEN quantity &lt; 0 THEN 'unfavorable quantity'\n                WHEN forex NOT IN ('GBP', 'EUR', 'USD') THEN 'unsupported forex'\n                WHEN standing NOT IN ('paid', 'refunded', 'cancelled') THEN 'invalid standing'\n                ELSE 'lacking required worth'\n            END AS rejection_reason\n        FROM typed_orders\n        WHERE NOT ({legitimate})\n    \"\"\")\n\ndef build_gold(connection: duckdb.DuckDBPyConnection) -&gt; None:\n    connection.execute(\"\"\"\n        CREATE OR REPLACE TABLE gold.daily_sales_by_region AS\n        SELECT\n            forged(ordered_at AS DATE) AS order_date,\n            area,\n            forex,\n            depend(*) FILTER (WHERE standing = 'paid') AS paid_orders,\n            sum(quantity) FILTER (WHERE standing = 'paid') AS gross_sales,\n            depend(*) FILTER (WHERE standing = 'refunded') AS refunded_orders,\n            sum(quantity) FILTER (WHERE standing = 'refunded') AS refunded_value\n        FROM silver.orders\n        GROUP BY order_date, area, forex\n        ORDER BY order_date, area, forex\n    \"\"\")\n\ndef check_quality(connection: duckdb.DuckDBPyConnection) -&gt; None:\n    duplicate_count = connection.execute(\n        \"SELECT depend(*) - depend(DISTINCT order_id) FROM silver.orders\"\n    ).fetchone()[0]\n    null_key_count = connection.execute(\n        \"SELECT depend(*) FROM silver.orders WHERE order_id IS NULL\"\n    ).fetchone()[0]\n    if duplicate_count or null_key_count:\n        elevate RuntimeError(\"Silver high quality contract failed\")\n\ndef print_query(connection: duckdb.DuckDBPyConnection, question: str) -&gt; None:\n    end result = connection.execute(question)\n    print(\" | \".be part of(column[0] for column in end result.description))\n    for row in end result.fetchall():\n        print(\" | \".be part of(\"NULL\" if worth is None else str(worth) for worth in row))\n\ndef fundamental(supply: Path) -&gt; None:\n    with duckdb.join(str(DATABASE)) as connection:\n        initialise(connection)\n        ingest_bronze(connection, supply)\n        build_silver(connection)\n        check_quality(connection)\n        build_gold(connection)\n        print(\"nGold output\")\n        print_query(connection, \"SELECT * FROM gold.daily_sales_by_region\")\n        print(\"nQuarantined information\")\n        print_query(\n            connection,\n            \"\"\"SELECT order_id, ordered_at, quantity, rejection_reason\n            FROM silver.orders_quarantine\"\"\",\n        )\n\nif __name__ == \"__main__\":\n    if len(sys.argv) != 2:\n        elevate SystemExit(\"Utilization: python pipeline.py path\/to\/orders.csv\")\n    fundamental(Path(sys.argv[1]))<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Run it utilizing this command.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-powershell\">python3 pipeline.py knowledge\/incoming\/orders_2026-07-19.csv<\/code><\/pre>\n<p class=\"wp-block-paragraph\">And the output?<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-markdown\">Loaded orders_2026-07-19.csv into bronze\n\nGold output\norder_date | area | forex | paid_orders | gross_sales | refunded_orders | refunded_value\n2026-07-19 | NORTH  | GBP      | 1           | 125.50      | 1               | 210.00\n2026-07-19 | SOUTH  | GBP      | 1           | 89.99       | 0               | NULL\n\nQuarantined information\norder_id | ordered_at                | quantity | rejection_reason\n1004     | 2026-07-19 12:42:00+01:00 | -10.00 | unfavorable quantity\n1003     | NULL                      | 45.00  | invalid ordered_at\n1002     | 2026-07-19 11:05:00+01:00 | 89.99  | duplicate order_id<\/code><\/pre>\n<p class=\"wp-block-paragraph\">After the run, Gold has one row for every date, area and forex, with separate figures for paid and refunded orders. Rows with unhealthy dates, unfavorable quantities or repeated order IDs don&#8217;t make it that far. They&#8217;re saved in silver.orders_quarantine desk to allow them to be checked.<\/p>\n<p class=\"wp-block-paragraph\">In my instance, I elected to maintain issues easy and disallow reloads of the identical enter into the bronze layer utilizing a file hash. So, when you run the command a second time, you\u2019ll see that the bronze ingestion half is skipped altogether as a result of the file hash already exists. In a manufacturing system, knowledge reloads into your bronze layer are one thing you\u2019ll must cater for too. It\u2019s not usually as massive a deal on your silver and gold layers, as these ought to at all times be reproducible out of your bronze layer knowledge, so when you get that proper, the whole lot else ought to fall into place.<\/p>\n<p class=\"wp-block-paragraph\">You may examine the medallion layers immediately utilizing code like this.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import duckdb\nfrom tabulate import tabulate\n\ndef show_table(\n    connection: duckdb.DuckDBPyConnection,\n    title: str,\n    question: str,\n) -&gt; None:\n    end result = connection.execute(question)\n    headers = [column[0] for column in end result.description]\n\n    print(f\"n{title}\")\n    print(tabulate(end result.fetchall(), headers=headers, tablefmt=\"psql\"))\n\nwith duckdb.join(\"warehouse.duckdb\") as connection:\n    show_table(\n        connection,\n        \"BRONZE - Uncooked orders\",\n        \"\"\"\n        SELECT\n            order_id,\n            ordered_at,\n            customer_id,\n            area,\n            quantity,\n            forex,\n            standing,\n            source_file\n        FROM bronze.orders_raw\n        ORDER BY order_id\n        \"\"\",\n    )\n\n    show_table(\n        connection,\n        \"SILVER - Validated orders\",\n        \"\"\"\n        SELECT\n            order_id,\n            ordered_at,\n            customer_id,\n            area,\n            quantity,\n            forex,\n            standing\n        FROM silver.orders\n        ORDER BY order_id\n        \"\"\",\n    )\n\n    show_table(\n        connection,\n        \"SILVER - Quarantined orders\",\n        \"\"\"\n        SELECT\n            order_id,\n            ordered_at,\n            quantity,\n            rejection_reason\n        FROM silver.orders_quarantine\n        ORDER BY order_id\n        \"\"\",\n    )\n\n    show_table(\n        connection,\n        \"GOLD - Day by day gross sales by area\",\n        \"\"\"\n        SELECT *\n        FROM gold.daily_sales_by_region\n        ORDER BY order_date, area\n        \"\"\",\n    )<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Which ends up in the next output.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-markdown\">BRONZE - Uncooked orders\n+------------+----------------------+---------------+----------+----------+------------+----------+-----------------------+\n|   order_id | ordered_at           | customer_id   | area   |   quantity | forex   | standing   | source_file           |\n|------------+----------------------+---------------+----------+----------+------------+----------+-----------------------|\n|       1001 | 2026-07-19T09:10:00Z | C001          | North    |   125.5  | GBP        | paid     | orders_2026-07-19.csv |\n|       1002 | 2026-07-19T10:05:00Z | C002          | South    |    89.99 | GBP        | paid     | orders_2026-07-19.csv |\n|       1002 | 2026-07-19T10:05:00Z | C002          | South    |    89.99 | GBP        | paid     | orders_2026-07-19.csv |\n|       1003 | not-a-date           | C003          | North    |    45    | GBP        | paid     | orders_2026-07-19.csv |\n|       1004 | 2026-07-19T11:42:00Z | C004          | West     |   -10    | GBP        | paid     | orders_2026-07-19.csv |\n|       1005 | 2026-07-19T12:20:00Z | C005          | North    |   210    | GBP        | refunded | orders_2026-07-19.csv |\n+------------+----------------------+---------------+----------+----------+------------+----------+-----------------------+\n\nSILVER - Validated orders\n+------------+---------------------------+---------------+----------+----------+------------+----------+\n|   order_id | ordered_at                | customer_id   | area   |   quantity | forex   | standing   |\n|------------+---------------------------+---------------+----------+----------+------------+----------|\n|       1001 | 2026-07-19 10:10:00+01:00 | C001          | NORTH    |   125.5  | GBP        | paid     |\n|       1002 | 2026-07-19 11:05:00+01:00 | C002          | SOUTH    |    89.99 | GBP        | paid     |\n|       1005 | 2026-07-19 13:20:00+01:00 | C005          | NORTH    |   210    | GBP        | refunded |\n+------------+---------------------------+---------------+----------+----------+------------+----------+\n\nSILVER - Quarantined orders\n+------------+---------------------------+----------+--------------------+\n|   order_id | ordered_at                |   quantity | rejection_reason   |\n|------------+---------------------------+----------+--------------------|\n|       1002 | 2026-07-19 11:05:00+01:00 |    89.99 | duplicate order_id |\n|       1003 |                           |    45    | invalid ordered_at |\n|       1004 | 2026-07-19 12:42:00+01:00 |   -10    | unfavorable quantity    |\n+------------+---------------------------+----------+--------------------+\n\nGOLD - Day by day gross sales by area\n+--------------+----------+------------+---------------+---------------+-------------------+------------------+\n| order_date   | area   | forex   |   paid_orders |   gross_sales |   refunded_orders |   refunded_value |\n|--------------+----------+------------+---------------+---------------+-------------------+------------------|\n| 2026-07-19   | NORTH    | GBP        |             1 |        125.5  |                 1 |              210 |\n| 2026-07-19   | SOUTH    | GBP        |             1 |         89.99 |                 0 |                  |\n+--------------+----------+------------+---------------+---------------+-------------------+------------------+<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Abstract<\/h2>\n<p class=\"wp-block-paragraph\">As database and knowledge engineers, we hear discuss of the Medallion sample in ETL jobs on a regular basis, and truthfully, you\u2019ve in all probability already carried out at the very least a cut-down model of it many occasions. What I attempted to do on this article is offer you a flavour of the way you may implement a sensible Medallion structure from first rules.<\/p>\n<p class=\"wp-block-paragraph\">Don\u2019t get me flawed. The instance I confirmed you was very a lot a toy instance. It used restricted enter knowledge and an area database, however the rules you would wish for a much bigger, productionised system are in place.\u00a0<\/p>\n<p class=\"wp-block-paragraph\">For manufacturing, you&#8217;ll have to determine whether or not you wish to use an enterprise-level RDBMS like Postgres or Oracle or use cloud-based object storage like AWS S3. If the latter you&#8217;ll have to take into consideration what transactional desk storage format to make use of, hudi, delta tables or iceberg. You\u2019ll additionally want to think about whether or not you want a pipeline orchestration software equivalent to Airflow or Dagster.<\/p>\n<p class=\"wp-block-paragraph\">And I\u2019ve not even talked concerning the kinds of automated checks you would wish for layer boundaries. Examples embody:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">bronze row counts and supply completeness<\/li>\n<li class=\"wp-block-list-item\">silver key uniqueness, accepted-value checks and referential integrity<\/li>\n<li class=\"wp-block-list-item\">gold reconciliation in opposition to silver totals<\/li>\n<li class=\"wp-block-list-item\">freshness and quantity thresholds<\/li>\n<li class=\"wp-block-list-item\">alerts for quarantine charges and schema drift.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">However these are simply the toppings on the cake. The necessary level is to grasp the fundamentals of the medallion sample and recognise how and the place it may possibly match into your new or current ETL pipelines.<\/p>\n<p class=\"wp-block-paragraph\">The medallion structure works as a result of it makes distinctions in your knowledge seen. Knowledge obtained isn\u2019t the identical as knowledge validated, and knowledge validated isn\u2019t routinely prepared for a specific enterprise choice.<\/p>\n<\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>are likely to turn out to be tougher to belief as they develop in scope, and so they definitely turn out to be tougher to run with out errors, to doc, and to debug.\u00a0 A CSV arrives from one system, JSON comes from one other, a Parquet file from elsewhere. Weeks and months go previous, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":17416,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[55],"tags":[2696,157,834,560],"class_list":["post-17414","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-machine-learning","tag-architecture","tag-data","tag-introduction","tag-medallion"],"_links":{"self":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/17414","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=17414"}],"version-history":[{"count":1,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/17414\/revisions"}],"predecessor-version":[{"id":17415,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/17414\/revisions\/17415"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/media\/17416"}],"wp:attachment":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=17414"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=17414"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=17414"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}<!-- This website is optimized by Airlift. Learn more: https://airlift.net. Template:. Learn more: https://airlift.net. Template: 69d9690a190636c2e0989534. Config Timestamp: 2026-04-10 21:18:02 UTC, Cached Timestamp: 2026-08-04 21:31:20 UTC -->