An SQL ETL pipeline is one of the most foundational components in any modern analytics stack. Nearly every organization relying on extract transform load workflows to move data at scale — from a regional bank reconciling transaction records to a global manufacturer consolidating IoT sensor feeds — relies on extract, transform, load (ETL) workflows to make raw data useful.
Yet despite their ubiquity, ETL pipelines remain a persistent source of friction: slow to build, expensive to maintain, and difficult to hand off between teams.
The root cause is not the data or the SQL. It is the gap between where data teams write logic and where that logic actually runs in production. Analysts and analytics engineers work fluently in Structured Query Language (SQL), but traditional pipeline frameworks have historically required Python, Scala, or vendor-specific procedural code to reach production environments. According to industry research, nearly two-thirds of organizations are fully dependent on data engineers for every aspect of pipeline creation and management — a bottleneck that slows analytics throughput and fragments team collaboration.
This guide is written for data engineers, analytics engineers, and data analysts who are building or modernizing etl data pipelines or SQL ETL pipelines. It covers the full lifecycle: defining what a SQL ETL pipeline actually is, identifying the right data sources and extraction patterns, designing robust transformation logic, selecting loading targets, governing sensitive data, optimizing performance, and aligning pipeline design with real business outcomes. Code patterns, architecture decisions, and operational practices are addressed throughout.
At its core, a SQL ETL pipeline is a repeatable, automated workflow that moves data from one or more source systems into a target repository — typically a data warehouse or data lake — where it can be queried, analyzed, or used to train machine learning models. The pipeline handles three responsibilities: extracting raw data from its origin, applying transformation logic to clean, enrich, or reshape it, and loading the transformed data into the destination system.
The business case for well-designed ETL pipelines is straightforward. Decision-makers cannot act on data scattered across dozens of disconnected systems. Marketing teams need unified customer data. Finance needs reconciled transaction records. Operations needs integrated sensor and ERP feeds. Without reliable data integration, organizations produce conflicting reports, miss SLA deadlines, and make decisions on stale inputs. A production-grade SQL ETL pipeline eliminates that ambiguity by creating a single, governed, continuously refreshed view of the data that matters.
Data needs have also changed. Batch-only pipelines that refreshed nightly were sufficient when dashboards were the primary analytics artifact. Today, real-time dashboards, machine learning feature pipelines, and operational alerting all require data that is minutes — not hours — stale. A modern SQL ETL pipeline needs to support both batch processing and streaming ingestion, often within the same logical workflow.
SQL is the language that makes this accessible. It is the most widely understood language across the data profession, readable by analysts and engineers alike. When ETL pipelines are expressed in SQL, they become collaborative artifacts rather than black-box scripts. Changes are easier to review, test, and roll back. Logic can be shared between the exploration phase and the production phase without rewriting. That shared foundation is the central reason why SQL-first approaches to ETL are gaining ground across the industry.
ETL — or extract transform and load, also written as etl extract transform load — describes a three-phase data integration process. In the extraction phase, a pipeline connects to one or more data sources — relational databases, flat files, APIs, message queues, cloud storage buckets — and retrieves — or retrieve data from — raw data sources. In the transformation phase, SQL commands reshape, cleanse, enrich, and aggregate that raw data to meet the requirements of the target system. In the load phase, the pipeline uses SQL commands to load data — writing the transformed data to a target system — typically a data warehouse, data lake, or lakehouse — where downstream consumers can query it.
The etl process follows a defined sequence that it is worth distinguishing from ELT (Extract, Load, Transform) and from data pipelines more broadly. In ELT workflows, raw data lands in the target system first, and transformations run directly on the warehouse using its native compute. Modern cloud data warehouse platforms make ELT increasingly attractive because storage is cheap and compute is elastic. ETL, by contrast, transforms data before loading — a pattern still common when the target system has cost-per-query pricing, when transformations require external libraries, or when data quality must be validated upstream. Data pipelines is a broader term that encompasses both patterns, along with streaming ingestion, API calls, orchestration, and any other automated data movement.
When the target is a data warehouse, ETL pipelines typically follow a schema-on-write model: data must conform to a defined schema before loading. This discipline produces high-quality, queryable data but requires upfront schema design and careful handling of schema drift. When the target is a data lake, schema-on-read is more common — raw data lands in a flexible format, and transformations are applied at query time or in downstream refinement steps. The choice between these architectures shapes how transformation logic — including any python scripts for preprocessing, calls to other systems, or custom library integrations — is written, tested, and maintained.
The relationship between etl and sql is symbiotic: SQL statements power the transformation layer in both patterns. Whether it is a SELECT with JOIN and GROUP BY for aggregation, a MERGE for upsert operations, or a window function for calculating running totals, SQL provides a rich, standardized vocabulary for expressing data transformation logic at scale.
Every SQL ETL pipeline begins with data sources. The range of systems a modern pipeline must support is broad: transactional relational database management systems such as Microsoft SQL Server, Oracle Database, and PostgreSQL; cloud data warehouse platforms; flat files in CSV, JSON, Parquet, or Avro formats; REST APIs; event streaming platforms like Apache Kafka; SaaS CRM and ERP systems; and cloud object storage on AWS S3, Azure Data Lake Storage, or Google Cloud Storage.
Each source type presents different extraction challenges. Relational databases support direct SQL queries, making extraction straightforward, but production databases should rarely be queried directly during peak load hours. Flat files require format handling and schema inference. APIs require pagination logic, rate limiting, and authentication. Event streams require checkpoint management to ensure exactly-once delivery. Assessing connector feasibility before migration — confirming that the source system's API or export mechanism can support the required extraction cadence and volume — prevents costly surprises during implementation.
For relational database sources, two extraction patterns dominate. Full extractions extract data from the entire source table on each pipeline run. They are simple to implement and guarantee completeness, but become prohibitively expensive as data volumes grow. Incremental extractions retrieve only records that have changed since the last pipeline execution, using timestamp comparisons, auto-incrementing sequence columns, or Change Data Capture (CDC) mechanisms to identify new and modified rows.
Incremental loading is the production-standard approach for high-volume pipelines. Utilizing timestamp tracking or CDC methods to identify records that have changed since the last execution dramatically reduces extraction time, network cost, and warehouse compute. The trade-off is complexity: the pipeline must maintain state across runs, handle late-arriving records, and manage schema changes in source tables gracefully.
The transformation layer is where raw data becomes structured, reliable, and analytically useful. Each SQL query in the transformation layer carries specific responsibilities. SQL transformation responsibilities include data cleansing — handling null values with COALESCE(), filtering bad records with WHERE clauses, removing duplicates with DISTINCT or ROW_NUMBER() window functions. Data unification involves joining tables from unrelated source systems via JOIN statements to produce a holistic, enterprise-wide view. Aggregation uses GROUP BY to summarize transactional detail into business-level metrics.
Explicitly stating column names rather than using SELECT * reduces memory overhead and prevents pipelines from breaking when source schemas add or remove columns. Applying business rules directly in SQL — pricing logic, customer segmentation rules, fiscal calendar adjustments — ensures that downstream BI reports reflect consistent, validated definitions rather than ad hoc analyst interpretations.
Staging tables play an important role in the transformation layer. Loading raw extractions into a staging table before applying transformations creates a reprocessing checkpoint: if a transformation fails, the pipeline can re-run from staging without re-extracting from the source. Staging also enables validation queries to run before transformed data reaches the production target, catching data quality issues before they corrupt downstream analytics.
Incremental loading is the backbone of efficient SQL ETL. Rather than reprocessing the entire source table on each run, the pipeline retrieves only new or modified rows by comparing a watermark value — typically a last_modified timestamp or a sequence number — against the maximum value already loaded into the target:
This pattern works reliably for append-only sources. For sources that also update or delete existing records, a MERGE statement handles all three operations atomically — inserting new rows, updating changed rows, and optionally soft-deleting removed rows — in a single idempotent SQL statement.
Many analytical use cases require tracking how dimension attributes change over time rather than overwriting the current state. The Slowly Changing Dimension Type 2 (SCD2) pattern preserves historical versions of a record by inserting a new row with each change while marking the previous version as expired:
SCD2 enables point-in-time analytics — for example, understanding what customer segment a buyer belonged to at the time of purchase, even if their segment has since changed. Traditional SCD2 implementations require careful management of timestamp logic, late-arriving records, and referential integrity. Declarative pipeline frameworks can automate this complexity, reducing a multi-step procedural workflow involving complex transformations to a single SQL statement.
Gold-layer aggregations consolidate granular transactional data into business-ready metrics. A typical rollup pattern groups order-level records into daily revenue summaries:
Applying business rules via SQL in this layer — segmenting revenue by product line, excluding internal test orders, applying currency conversion — ensures that every downstream dashboard, report, or ML model draws from a single, consistent source of truth.
A data warehouse imposes schema-on-write semantics. Tables are created with explicit column types, primary keys, and partitioning strategies before data arrives. This discipline pays dividends in query performance and data quality but requires upfront investment in schema design and rigorous management of schema evolution. When a source system adds a column, ETL pipelines must detect the change, update target table DDL, and handle historical records where the new column was absent.
Effective loading strategies for a unified data warehouse include using TRUNCATE and reload for small, slowly changing reference tables; using MERGE or upsert patterns for transactional tables where records can be created, updated, or deleted; and using append-only inserts for immutable event logs. Partitioning target tables by date or another high-cardinality filter column enables partition pruning, dramatically reducing the data scanned per query.
A data lake accepts data in its raw, unstructured, or semi-structured form without requiring upfront schema definition. Schema-on-read flexibility makes data lakes well-suited for exploratory analytics, machine learning feature engineering, and storing high-volume event streams where schema stability cannot be guaranteed. The trade-off is that query-time schema inference adds latency, and without governance controls, data lakes can devolve into unmanageable data swamps.
Modern data lakehouse architectures combine the storage flexibility of a data lake with the performance and governance capabilities of a data warehouse. Open table formats like Delta Lake provide ACID transactions, time travel, schema enforcement, and incremental refresh capabilities on top of cloud object storage — enabling SQL queries with data warehouse-grade reliability against data lake-scale storage.
Transformation logic is only part of the story. A production SQL ETL pipeline needs an orchestration layer to manage execution order, handle dependencies between pipeline stages, retry failed tasks, and alert operators when something goes wrong.
A range of ETL tools, specialized tools, and orchestration frameworks exists to manage this complexity. Apache Airflow defines pipeline workflows as directed acyclic graphs (DAGs), allowing teams to programmatically author, schedule, and monitor data pipelines. Airflow's Python-based DAG definitions support complex dependency management, conditional branching, and integration with virtually any data system. AWS Glue provides a serverless ETL service that removes infrastructure management — teams define jobs in Python or Scala, and AWS handles scaling and execution. Azure Data Factory is a cloud data integration service that offers a visual pipeline builder with native connectors to hundreds of data sources and a managed runtime that scales automatically with data volume. Google Cloud Dataflow is a fully managed stream and batch data processing service built on Apache Beam built on Apache Beam, well-suited for high-throughput pipelines requiring real-time latency.
The right scheduling cadence depends on business requirements and technical constraints. Hourly or daily batch jobs are appropriate for analytical reporting where moderate data freshness is acceptable. Near-real-time schedules, using micro-batch intervals of five to fifteen minutes, suit operational dashboards and alerting use cases. Streaming pipelines with continuous ingestion are the right choice for applications requiring subsecond data freshness — real-time fraud detection, live inventory tracking, or customer experience monitoring.
Batch processing consolidates data processing into discrete time windows. It is cost-efficient, easy to debug, and compatible with most analytical workflows. Streaming processing ingests and transforms — continuously process data as as it arrives. The decision criterion is latency tolerance: if business stakeholders need data within seconds, streaming is required; if hours or minutes are acceptable, batch is simpler and cheaper.
In practice, many modern pipelines blend both modes. A streaming table ingests event data continuously from Kafka or cloud storage, while downstream materialized views refresh on an hourly schedule for aggregated reporting. This hybrid architecture eliminates the forced choice between batch and streaming that made traditional ETL rigid and brittle.
Monitoring etl operations at runtime is as important as designing them correctly. Retry and backoff policies are a critical operational detail. Transient failures — network timeouts, source system rate limits, temporary lock contention — are inevitable in production data pipelines. Configuring exponential backoff with a maximum retry count prevents cascading failures while ensuring transient issues resolve without operator intervention. Dead-letter queues or failed-record tables should capture records that exhaust retries, enabling manual review and reprocessing.
Data migration projects — moving data from legacy systems to modern cloud data platforms — is one of the most common and highest-risk ETL projects an engineering team undertakes. Legacy systems often contain years of undocumented business logic, inconsistent data models, and sensitive data with no clear governance lineage. A phased migration approach reduces risk by enabling parallel validation before decommissioning the source system.
Phase one focuses on extraction and profiling: connect to the legacy source, extract a representative sample, and document the schema, data types, null rates, and value distributions for each column. This inventory surfaces data quality issues before they contaminate the new platform. Phase two implements the full extraction and transformation pipeline, loading data into a staging environment where automated validation queries confirm row counts, checksum totals, and business rule compliance. Phase three runs the new and legacy systems in parallel, comparing query outputs to validate equivalence before promoting the new pipeline to production.
Source-to-target field mapping is the connective tissue of a migration project. For each source column, the mapping document records the target column name, data type conversion rules, null handling logic, and any business transformation applied. This artifact becomes the authoritative reference for debugging discrepancies during validation and for onboarding new team members who join after the initial migration.
Scheduling validation windows during low-traffic periods — typically overnight or on weekends — minimizes the impact on production systems while providing the compute headroom needed to run large-scale row-count reconciliation queries.
Effective data management at the pipeline level means more than just moving records. Enterprise data pipelines process sensitive data — personally identifiable information, financial records, health data — that must be protected from unauthorized access. Access controls should be defined at the pipeline level, not just at the database level. Each pipeline component should have a documented owner, a list of authorized consumers, and a data classification label that drives downstream governance policies.
Governing data access and data operations at the row and column level enables fine-grained governance without duplicating data into separate access-controlled tables. A single customer data table can surface different columns to marketing analysts (name, segment, channel preference) and finance teams (account balance, payment history) through view-level security policies, with sensitive columns masked or excluded for consumers who do not have a business need.
Sensitive data must be encrypted both in transit — using TLS for all network connections between pipeline components — and at rest in the target storage layer. For regulated industries, encryption key management and access audit logs are compliance requirements. Column-level encryption for highly sensitive fields like Social Security numbers or payment card data adds an additional protection layer beyond storage-level encryption, ensuring that even users with storage access cannot read protected values without the appropriate decryption key.
Data accuracy SLAs define the acceptable error rate and staleness threshold for pipeline outputs. A financial reporting pipeline might require 100% row-count reconciliation between source and target, with zero tolerance for missing or duplicated records. An operational dashboard might tolerate a small percentage of late-arriving records as long as the delay does not exceed fifteen minutes. Documenting these SLAs explicitly — and wiring automated alerts to fire when pipelines miss them — creates accountability and enables teams to prioritize remediation based on business impact.
Production SQL ETL pipelines grow complex quickly. A pipeline that starts as a single script for loading one table evolves into dozens of interdependent transformations spanning multiple source systems. ETL workflows are only as reliable as the scripts that define them. Modularizing SQL into discrete, single-responsibility scripts — one script per transformation layer, one script per business entity — makes pipelines easier to test, debug, and reuse across projects.
Idempotent load operations are a non-negotiable property of production pipelines. An idempotent pipeline produces the same result regardless of how many times it runs. This property enables safe retries after failures: if a pipeline fails midway through loading, operators can restart it without fear of duplicating or corrupting data. Idempotency is typically achieved through MERGE statements, INSERT OVERWRITE partition replacement, or truncate-and-reload patterns, depending on the target system and use case.
Complex pipelines create complex dependencies. A Gold-layer aggregation depends on a Silver-layer join, which depends on Bronze-layer ingestion from two separate source systems. Documenting these dependencies — either in code comments, a data catalog, or a dedicated lineage tracking system — enables operators to quickly identify the blast radius of a source-system failure. When an upstream table is modified or delayed, dependency documentation answers the question "what downstream pipelines are affected?" within seconds rather than hours.
All SQL scripts, pipeline configuration files, and deployment manifests should be version-controlled in a code repository. Version control enables change history, code review, rollback to known-good states, and CI/CD integration for automated testing before deployment.
Even well-designed ETL pipelines fail. Source schemas change unexpectedly. Cloud storage buckets fill up. Network partitions cause extraction timeouts. A well-maintained incident runbook documents the steps an on-call engineer should take when a pipeline alerts: which dashboards show pipeline health, how to identify the failing step, how to safely rerun a partial pipeline, and when to escalate to upstream system owners.
Assigning clear ownership for each pipeline component prevents the diffusion-of-responsibility failures that occur when everyone assumes someone else is monitoring a critical job. A simple ownership registry — mapping each pipeline, table, and transformation to a named engineer and a backup — takes an hour to build and saves hours of confusion during an incident.
Data teams rarely operate in isolation, and neither do their etl workflows. Analytics engineers building downstream models depend on data engineers maintaining upstream pipelines. Data analysts depend on data engineers' transformation logic matching their business definitions. Regular cross-team synchronization — a standing weekly or biweekly sync between data engineering, analytics engineering, and analytics consumers — creates a forum for communicating upcoming schema changes, new data sources, and deprecation timelines before they break downstream workflows.
Schema change notifications should be automated wherever possible. When a source system adds, renames, or removes a column, the pipeline should detect the drift, log a structured alert, and optionally pause rather than silently propagating unexpected nulls or type mismatches downstream.
Query performance in ETL pipelines degrades for predictable reasons: missing indexes on join keys, full table scans on large source tables, Cartesian products from misconfigured joins, and transformation logic applied row-by-row rather than in set-based operations. Using execution plans — the primary tool to optimize queries — available in virtually every SQL engine as EXPLAIN or EXPLAIN ANALYZE — surfaces the highest-cost operations in a query, directing teams to optimize queries where it will have the most impact.
Pushing transformations down to the data warehouse layer when possible is a core optimization principle. Computing aggregations, joins, and filters in the warehouse rather than pulling raw data into an application layer for processing reduces data movement, leverages the warehouse's distributed compute, and takes advantage of query optimizer intelligence that application-layer code cannot match.
Partitioning target tables by a commonly filtered column — order date, event timestamp, or geographic region — enables partition pruning, a technique where the query engine scans only the partitions that satisfy the filter predicate rather than the entire table. For tables with billions of rows, partition pruning reduces query execution time from minutes to seconds.
Clustering tables on join keys and grouping columns complements partitioning by physically co-locating related rows on storage. Well-clustered tables reduce the data shuffled during joins and aggregations, improving both query performance and the effectiveness of materialized view incremental refresh. Caching frequently used lookup tables — product catalogs, currency conversion rates, dimension tables — reduces the repeated join overhead that accumulates across a high-throughput pipeline.
When building complex SQL queries involving multi-level joins and aggregations, using Common Table Expressions (CTEs) or breaking logic into intermediate materialized steps improves both readability and optimizer performance. Avoid deeply nested subqueries, which many SQL engines cannot optimize as effectively as CTEs or staged intermediates.
Rigorous etl testing begins with basic reconciliation: the number of rows in the target table after loading should match the number of rows extracted from the source (adjusted for deduplication and filter rules). Row-count tests catch the most common failure modes — partial loads, double-loads, and missed increments — and can be automated as SQL queries run at the end of every pipeline execution.
Checksum tests extend reconciliation to data content. A checksum across the values in a key column — customer ID, transaction ID, order number — confirms not just that the right number of rows arrived, but that the correct rows arrived. For financial pipelines, summing monetary values and comparing source versus target totals is a standard validation that surfaces rounding errors, currency conversion mistakes, and truncation bugs before they reach reporting.
Schema drift — unexpected changes to source system column names, types, or cardinality — is one of the most disruptive failure modes in production ETL pipelines. Automated schema drift detection compares the current source schema against a stored baseline on each extraction run, alerting operators when discrepancies are detected before they propagate downstream.
Data gap monitoring identifies missing time windows in event-based or timestamp-partitioned tables. If a source system fails to emit events between 2:00 AM and 4:00 AM, a data gap monitor catches the anomaly before a business analyst reports a suspicious dip in their morning dashboard. Transformation lineage logging — recording which source rows contributed to which target rows — provides the audit trail needed to investigate data quality incidents and satisfy regulatory data access requirements.
Well-designed ETL data pipelines are not purely technical artifacts. They are the infrastructure that makes business intelligence, machine learning, and operational analytics possible. Pipelines that produce actionable insights are designed backward from business requirements: identify the metrics that decision-makers rely on, trace those metrics to the source data and transformation logic required to compute them, and build the pipeline around that critical path.
Prioritizing pipelines by business impact — not by technical complexity or engineering convenience — ensures that engineering effort flows toward the data products that matter most. A pipeline powering a weekly revenue report used by the CFO warrants more investment in testing, monitoring, and SLA enforcement than a pipeline feeding an exploratory dashboard used by a single analyst. Making that prioritization explicit, and revisiting it regularly as business priorities shift, keeps engineering investment aligned with organizational value.
Data pipelines are living systems. Source schemas change. Business definitions evolve. New use cases emerge that require additional transformation layers or new data sources. Building pipelines with modularity and version control in mind makes iteration faster and less risky — changes can be tested in isolation, reviewed before deployment, and rolled back if something breaks.
The most effective data teams treat stakeholder feedback as a primary input to pipeline design decisions. When a business analyst reports that a metric looks wrong, that complaint is both a data quality signal and a pipeline design signal. Structured feedback loops between data teams and business stakeholders — post-incident reviews, quarterly pipeline health reviews, standing feedback channels in team communication tools — accelerate the convergence between what the pipeline produces and what the business actually needs.
In today's data-driven world, organizations that treat ETL pipelines as collaborative, continuously improved products — rather than one-time engineering projects — consistently outperform peers who treat them as infrastructure to be built once and forgotten. Building a SQL ETL pipeline the right way means investing not just in the code, but in the practices, collaboration patterns, and governance frameworks that keep that code reliable, trustworthy, and aligned with the business it serves.
ETL and SQL serve complementary but distinct roles in data management. ETL (Extract, Transform, Load) defines the overall process of moving and reshaping data between systems — including extraction from source systems, transformation to meet target requirements, and loading into a destination like a data warehouse. SQL (Structured Query Language) is the programming language used to execute operations that manipulate data and handle retrieval within that process. ETL defines the workflow; SQL is the language that implements the transformation and loading steps within it. In practice, modern SQL ETL pipelines use SQL statements as the primary implementation language for both transformation logic and load operations.
The choice between ETL and ELT depends primarily on where transformation compute is cheapest and most scalable. Use ETL — transforming before loading — when the target system charges by query or compute usage, when data quality validation must occur before data enters the warehouse, or when transformations require external libraries or complex stateful logic not expressible in SQL. Use ELT — loading raw data first and transforming in place — when the target is a modern cloud data warehouse with elastic compute, when source schemas are unstable and flexibility is needed, and when SQL-native transformation logic is sufficient. Many organizations run hybrid approaches: raw data lands in a data lake, a subset is transformed and promoted to a structured data warehouse layer using SQL-based transformation pipelines.
Ensuring data accuracy in ETL pipelines requires a layered testing strategy. Maintaining data integrity starts with row-count reconciliation, which confirms that the expected number of records arrived at the target. Checksum validation confirms that the correct records arrived — not just the right quantity. Business rule validation queries confirm that computed metrics match expected values derived from source data. Schema drift monitoring detects unexpected changes to source or target table structures before they cause silent data corruption. For financial or regulated data, end-to-end reconciliation between source system records and warehouse outputs is a required audit control. Automated tests should run on every pipeline execution, with alerts configured to fire when validation thresholds are breached.
Sensitive data handling in ETL pipelines operates at multiple layers. At the transport layer, all connections between pipeline components should use TLS encryption. At the storage layer, target tables containing sensitive data should use storage-level encryption with managed key rotation. At the access layer, column-level masking or row-level security policies should restrict access to sensitive fields based on consumer role — preventing data analysts from reading payment card numbers while still allowing them to query transaction aggregates. For highly regulated data, column-level encryption with separate key management ensures that storage administrators cannot read sensitive values. All access to sensitive data should be logged for audit purposes, with retention policies aligned to regulatory requirements.
The core SQL vocabulary for ETL pipelines includes SELECT with JOIN, WHERE, GROUP BY, and window functions for data extraction and transformation; INSERT INTO for append operations; MERGE for upsert operations combining inserts, updates, and deletes in a single atomic statement; TRUNCATE for full-refresh patterns; CREATE TABLE AS SELECT for materializing transformation results; and COALESCE(), NULLIF(), and CASE WHEN for data cleansing and conditional logic. ROW_NUMBER() and DISTINCT handle deduplication. For Microsoft SQL Server environments, EXEC and stored procedures are common in legacy pipeline implementations, though modern declarative approaches favor plain SQL statements over procedural constructs.