Skip to content

Latest commit

 

History

History
263 lines (204 loc) · 7.26 KB

File metadata and controls

263 lines (204 loc) · 7.26 KB

Understanding SQL's Execution Order

Slide 1: SQL as a Declarative Language

SQL operates on a principle of describing what you want, rather than spelling out each computational step. This design philosophy makes SQL unique among programming languages - you declare your desired outcome, and the SQL engine determines the most efficient path to achieve it.

# Example showing declarative vs imperative approach
# Declarative (SQL-like) approach in Python
data = [
    {'name': 'Alice', 'age': 25},
    {'name': 'Bob', 'age': 30},
    {'name': 'Charlie', 'age': 35}
]

# Using list comprehension (declarative-style)
adults = [person for person in data if person['age'] >= 30]

# Imperative approach
adults = []
for person in data:
    if person['age'] >= 30:
        adults.append(person)

Slide 2: Query Structure

A SQL query follows a logical structure where clauses are arranged in a specific order. While written in one sequence, the execution follows a different path, optimizing for performance and data integrity.

def demonstrate_query_structure():
    query = {
        'select': ['column1', 'column2'],
        'from': 'table_name',
        'where': 'condition',
        'group_by': 'column1',
        'having': 'group_condition',
        'order_by': 'column1',
        'limit': 10
    }
    return query

Slide 3: FROM and JOIN Operations

The first step in query execution involves identifying and combining data sources. This forms the foundation of all subsequent operations.

def demonstrate_join():
    table1 = [('A', 1), ('B', 2), ('C', 3)]
    table2 = [(1, 'X'), (2, 'Y'), (3, 'Z')]
    
    # Simulating an INNER JOIN
    joined_data = []
    for t1 in table1:
        for t2 in table2:
            if t1[1] == t2[0]:  # Join condition
                joined_data.append((t1[0], t1[1], t2[1]))
    return joined_data

Slide 4: WHERE Clause Processing

After data sources are combined, filtering occurs through the WHERE clause. This step eliminates rows that don't meet specified conditions.

def filter_data(data, condition):
    # Simulating WHERE clause
    return [
        row for row in data 
        if eval(f"row[condition['column']] {condition['operator']} {condition['value']}")
    ]

# Example usage
data = [{'age': 25}, {'age': 30}, {'age': 35}]
condition = {'column': 'age', 'operator': '>', 'value': 30}
filtered = filter_data(data, condition)

Slide 5: GROUP BY Implementation

The GROUP BY operation aggregates rows sharing common values, creating a foundation for aggregate functions.

from collections import defaultdict

def group_data(data, group_column):
    groups = defaultdict(list)
    for row in data:
        key = row[group_column]
        groups[key].append(row)
    return dict(groups)

# Example data
data = [
    {'category': 'A', 'value': 1},
    {'category': 'B', 'value': 2},
    {'category': 'A', 'value': 3}
]
grouped = group_data(data, 'category')

Slide 5: GROUP BY Implementation

GROUP BY transforms individual rows into grouped sets based on specified columns, preparing data for aggregate operations like counting or averaging values.

def simple_group_by(data):
    # Sample data representing colors and their occurrences
    colors = ['red', 'blue', 'red', 'green', 'blue', 'red']
    
    # Dictionary to store grouped counts
    grouped_data = {}
    
    # Group and count occurrences
    for color in colors:
        if color in grouped_data:
            grouped_data[color] += 1
        else:
            grouped_data[color] = 1
            
    return grouped_data

Slide 6: Results for GROUP BY Implementation

# Output of simple_group_by():
{
    'red': 3,
    'blue': 2,
    'green': 1
}

Slide 7: HAVING Clause

The HAVING clause filters grouped data based on aggregate conditions, operating after GROUP BY has formed the groups.

def apply_having(grouped_data, min_count):
    # Filter groups based on count threshold
    filtered_groups = {
        color: count 
        for color, count in grouped_data.items() 
        if count >= min_count
    }
    return filtered_groups

# Usage example with minimum count of 2
result = apply_having({'red': 3, 'blue': 2, 'green': 1}, 2)

Slide 8: SELECT Processing

SELECT determines which columns appear in the final output, possibly including calculated values or aggregate functions.

def process_select(data, columns):
    # Sample data processing with SELECT-like behavior
    selected_data = []
    
    for record in data:
        selected_record = {}
        for col in columns:
            if col in record:
                selected_record[col] = record[col]
        selected_data.append(selected_record)
    
    return selected_data

Slide 9: ORDER BY Implementation

ORDER BY sorts the final result set based on specified columns and sort directions.

def custom_sort(data, sort_key, ascending=True):
    # Implementation of basic sorting mechanism
    sorted_data = sorted(
        data,
        key=lambda x: x[sort_key],
        reverse=not ascending
    )
    return sorted_data

Slide 10: LIMIT Operation

LIMIT controls the number of rows in the final output, useful for pagination and reducing data volume.

def apply_limit(data, limit_value):
    # Simple implementation of LIMIT
    return data[:limit_value] if limit_value > 0 else data

Slide 11: Real-Life Example - Student Records

This example demonstrates a complete query execution flow using student attendance records.

def process_student_records():
    # Sample student attendance data
    records = [
        {'student': 'Alice', 'subject': 'Math', 'attendance': 90},
        {'student': 'Bob', 'subject': 'Math', 'attendance': 85},
        {'student': 'Alice', 'subject': 'Science', 'attendance': 95}
    ]
    
    # Group by student
    grouped = {}
    for record in records:
        student = record['student']
        if student not in grouped:
            grouped[student] = []
        grouped[student].append(record)
    
    # Calculate average attendance per student
    averages = {
        student: sum(r['attendance'] for r in records) / len(records)
        for student, records in grouped.items()
    }
    
    return averages

Slide 12: Real-Life Example - Weather Data Analysis

This example shows how to process and analyze temperature readings.

def analyze_temperature_readings():
    # Sample temperature readings throughout a day
    readings = [
        {'hour': 1, 'temp': 20}, {'hour': 2, 'temp': 19},
        {'hour': 3, 'temp': 18}, {'hour': 4, 'temp': 20}
    ]
    
    # Group by temperature value
    temp_groups = {}
    for reading in readings:
        temp = reading['temp']
        if temp not in temp_groups:
            temp_groups[temp] = []
        temp_groups[temp].append(reading['hour'])
    
    # Find most frequent temperature
    most_frequent = max(temp_groups.items(), key=lambda x: len(x[1]))
    
    return {
        'temp': most_frequent[0],
        'occurrences': len(most_frequent[1]),
        'at_hours': most_frequent[1]
    }

Slide 13: Additional Resources

For deeper understanding of SQL query execution and optimization, refer to:

  • "Query Optimization Techniques in Database Systems" (arXiv:1911.03834)
  • "A Survey of Query Execution Engine and Query Optimization" (arXiv:2111.02668)