Why I Keep Business Logic Out of SQL
Should business logic reside in the database—using views, procedures, functions—or in application code (including SQL statements)?
First, define business logic. Wikipedia provides an excellent description:
Business logic is the portion of an enterprise system which determines how data is transformed or calculated, and how it is routed to people or software.
I focus specifically on logic that executes just before writing data: the conditional statements and loops that mutate the system's externally visible state. Reading data from the database using SQL with filtering and aggregation is excluded; here, SQL offers significant advantages.
This remains a long-discussed topic, though less debated in the last 15 years. Common wisdom has largely settled.
TL;DR
I keep most code in the application, treating the database as a simple data store with minimal logic.
SQL's Expressive Limitations
SQL and its vendor dialects excel at handling row-based data—many rows at a time—and the relations between them. However, applications using relational databases require rich business logic. Is SQL suitable for implementing this logic?
Despite vendor-specific extensions that provide a type system (e.g., Oracle PL/SQL), the answer is no. Modeling a class hierarchy or object composition in SQL is clumsy and verbose. SQL performs poorly when processing single rows. While possible, it lacks the expressiveness of mainstream programming languages like TypeScript, Java, C#, Haskell, Python, or JavaScript. Attempt this example yourself to see the challenge.
Deployment Challenges
Deploying application code is easier, though context-dependent. Modern CI/CD systems enable near-automated application deployments and rollbacks. Database deployments, however, face greater obstacles:
- Require database access with elevated privileges
- Often need coordination with DBAs in corporate environments
- Are frequently subject to stricter security policies
- Involve complex rollbacks, especially when schema changes are involved (a challenge for applications too)
Such restrictions are common, though not universal.
Additional Disadvantages
Other drawbacks to database-resident code include:
- Increased vendor lock-in
- A smaller tooling ecosystem compared to application languages
Performance Considerations
Address the N+1 query problem when orchestrating database access in application code. Processing more data in the database reduces this risk. This objectively favors placing logic in the database. However, avoid premature optimization before identifying actual bottlenecks.
Summary
SQL's inherent limitations as a language are the primary reason I implement business logic in standard programming languages. Therefore, I recommend keeping most code within the application.