DEV Community

Cover image for From SQL to Python: Uniting Stored Power with Functional Flexibility
Loi2008
Loi2008

Posted on

From SQL to Python: Uniting Stored Power with Functional Flexibility

Overview

Databases and programming languages are frequently used in modern software systems to provide effective, scalable, and maintainable solutions. Python functions and SQL stored procedures are essential components of these ecosystems. Python functions encapsulate reusable application logic for computation, integration, and sophisticated processing, whereas stored procedures encapsulate database logic to carry out actions directly within the database engine.
This article explores their similarities, differences, and suitable applications, emphasizing their potential in both individual and combined use.

Stored Procedure (SQL)

A stored procedure is a precompiled set of SQL statements (and optional control-of-flow logic) stored in a relational database. It can accept input parameters, perform operations (such as queries, inserts, updates, deletes, or complex business logic), and return results.

Key Features

  • Encapsulation of database logic.
  • Parameterized execution for dynamic queries.
  • Control-of-flow logic (IF, WHILE, CASE).
  • Enhanced security via procedure-level permissions.

Application

  • Generating financial or operational reports
  • Running batch updates and ETL jobs
  • Enforcing business rules within the database

SQL Script: Applying Stored Procedures

The example illustrates application of a stored procedure in a business scenario, using sales database. The script retrieve customer orders above a certain amount and log when the procedure is executed.

-- Customers table
CREATE TABLE Customers (
    CustomerID INT PRIMARY KEY,
    CustomerName VARCHAR(100),
    City VARCHAR(50)
);

-- Orders table
CREATE TABLE Orders (
    OrderID INT PRIMARY KEY,
    CustomerID INT,
    OrderDate DATE,
    OrderAmount DECIMAL(10,2),
    FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID)
);

-- ProcedureLog table
CREATE TABLE ProcedureLog (
    Log_ID SERIAL PRIMARY KEY,  
    ProcedureName VARCHAR(100),
    ExecutionTime TIMESTAMP
);

-- Insert sample data
INSERT INTO Customers (CustomerID, CustomerName, City)
VALUES (1, 'Alice Johnson', 'New York'),
       (2, 'Michael Smith', 'Chicago'),
       (3, 'Sarah Lee', 'San Francisco');

INSERT INTO Orders (OrderID, CustomerID, OrderDate, OrderAmount)
VALUES (101, 1, '2025-01-10', 250.00),
       (102, 2, '2025-01-15', 120.00),
       (103, 1, '2025-02-01', 500.00),
       (104, 3, '2025-02-05', 90.00);

-- Stored procedure 

CREATE OR REPLACE FUNCTION GetHighValueOrders(min_amount DECIMAL)
RETURNS TABLE (
    OrderID INT,
    CustomerName VARCHAR(100),
    OrderDate DATE,
    OrderAmount DECIMAL(10,2)
)
AS $$
BEGIN
    -- Log the execution
    INSERT INTO ProcedureLog (ProcedureName, ExecutionTime)
    VALUES ('GetHighValueOrders', NOW());

    -- Return query
    RETURN QUERY
    SELECT O.OrderID, C.CustomerName, O.OrderDate, O.OrderAmount
    FROM Orders O
    INNER JOIN Customers C ON O.CustomerID = C.CustomerID
    WHERE O.OrderAmount >= min_amount
    ORDER BY O.OrderAmount DESC;
END;
$$ LANGUAGE plpgsql;
-- Executing the function
SELECT * FROM GetHighValueOrders(200);

-- Check logs
SELECT * FROM ProcedureLog;
Enter fullscreen mode Exit fullscreen mode

The sql code:

  • creates the tables.
  • Insert customers and orders.
  • Create a stored procedure that:
    • Logs every execution into ProcedureLog.
    • Returns orders where OrderAmount >= @MinAmount.

Function (Python)

A Python function is a block of reusable code that performs a specific task, takes input arguments (optional), and can return values. Functions in Python support modularity, abstraction, and reusability within applications.

Key Features

  • Can return any Python object (e.g., int, list, dict)
  • Support recursion, loops, and error handling with try...except
  • Integrate seamlessly with external APIs and libraries
  • Enable abstraction and modularity in software design

Application

  • Data preprocessing and cleaning
  • Implementing application business rules
  • Applying machine learning and analytics
  • Integrating with external APIs and services

Python Script: Applying Python Function

The script applies functions for reusability and clarity by:

  • Connecting to a database.
  • Calling a stored procedure.
  • Applying a function to filter, transform, and display the data.
from datetime import datetime

# "Tables" in memory
customers = [
    {"CustomerID": 1, "CustomerName": "Alice Johnson", "City": "New York"},
    {"CustomerID": 2, "CustomerName": "Michael Smith", "City": "Chicago"},
    {"CustomerID": 3, "CustomerName": "Sarah Lee", "City": "San Francisco"}
]

orders = [
    {"OrderID": 101, "CustomerID": 1, "OrderDate": "2025-01-10", "OrderAmount": 250.00},
    {"OrderID": 102, "CustomerID": 2, "OrderDate": "2025-01-15", "OrderAmount": 120.00},
    {"OrderID": 103, "CustomerID": 1, "OrderDate": "2025-02-01", "OrderAmount": 500.00},
    {"OrderID": 104, "CustomerID": 3, "OrderDate": "2025-02-05", "OrderAmount": 90.00}
]

procedure_log = []  # "ProcedureLog table"

# Function to log execution
def log_procedure(name):
    procedure_log.append({
        "ProcedureName": name,
        "ExecutionTime": datetime.now()
    })

# Function to get high-value orders
def get_high_value_orders(min_amount):
    # Log execution
    log_procedure("get_high_value_orders")

    # Filter and join with customers
    result = []
    for order in orders:
        if order["OrderAmount"] >= min_amount:
            customer = next(c for c in customers if c["CustomerID"] == order["CustomerID"])
            result.append({
                "OrderID": order["OrderID"],
                "CustomerName": customer["CustomerName"],
                "OrderDate": order["OrderDate"],
                "OrderAmount": order["OrderAmount"]
            })
# Sort ORDER BY DESC
    result.sort(key=lambda x: x["OrderAmount"], reverse=True)
    return result
# ---------------------------
# Application
print("High value orders >= 200:")
for row in get_high_value_orders(200):
    print(row)
print("\nProcedure logs:")
for log in procedure_log:
    print(log)
Enter fullscreen mode Exit fullscreen mode

Similarities

1. Encapsulation of Logic

Both stored procedures and Python functions encapsulate logic into reusable units. For example, instead of writing the same SQL query or Python code multiple times, you place it in a procedure/function and call it when needed.

2. Parameterization

Both accept input parameters, process them, and return results. For example:

SQL: EXEC GetCustomerOrders @CustomerID = 5

Python: get_customer_orders(customer_id=5)
Enter fullscreen mode Exit fullscreen mode

3. Modularity & Reusability

Both allow modular program design, making systems easier to maintain. Code changes in one procedure/function apply everywhere it is called.

4. Control Flow Support

Both can include conditional logic (IF, CASE in SQL vs. if/else in Python) and looping constructs.

Differences

Aspect Stored Procedures (SQL) Functions (Python)
Execution Context Runs inside database engine Runs in Python interpreter/application layer
Primary Purpose Optimizing database operations (queries, transactions) Implementing general-purpose logic and algorithms
Return Types Result sets, output parameters, status codes Any Python object (int, list, dict, etc.)
Language Used SQL with procedural extensions (T-SQL, PL/SQL, etc.) Python syntax
Performance Precompiled, reduces network traffic by processing in DB Requires fetching data from DB before processing
Error Handling TRY...CATCH blocks try...except blocks
Statefulness Tied to database state (tables, views, transactions) Independent, works with in-memory or external data

Suitable Applications

Stored Procedures (SQL)

Best used when:

  • Heavy database operations are needed (aggregation, filtering, batch updates).
  • In need for reduced network overhead (logic executes close to the data).
  • Security is critical - permissions can be granted at procedure-level rather than table-level.
  • You need performance optimization: pre-compiled execution plans and indexing.
Application
  • Generating financial reports directly from the database.
  • Performing scheduled batch updates or ETL processes.
  • Enforcing business rules within the database.
Python Functions

Best used when:

  • Application-level processing is required (business rules, algorithms, data transformations).
  • Data needs to be manipulated in memory beyond SQL capabilities (e.g., machine learning, natural language processing).
  • You need integration with external APIs, services, or user interfaces.
  • Logic requires flexibility beyond relational operations (graph algorithms, recursive calculations, etc.).
Application
  • Cleaning and preparing datasets for machine learning.
  • Implementing application logic in a web service.
  • Calling a database stored procedure and further processing results in Python.
Application of both

In real-world systems, stored procedures and Python functions often complement each other- Stored procedure handles data retrieval/aggregation while Python function calls the stored procedure and applies additional business logic.

Summary

  • Stored Procedures: Optimize and secure database operations, reduce network load, enforce business rules within the DB.
  • Python Functions: Provide flexibility, abstraction, and broader application logic capabilities outside the database.
  • Both: Form a powerful combination — databases handle what they do best (data storage and retrieval), while Python manages application logic and advanced processing.

References and Further Reading

Top comments (0)