Dynamic SQL — Building and Executing SQL on the Fly

Dynamic SQL

A report accepts a city value and an approved sort choice from the user. Both affect the request, but they cannot be handled with the same substitution rule.

Dynamic SQL constructs or prepares a statement at runtime. The SQL structure and its data values require different handling.

  1. Explain and apply

    Build a MySQL prepared statement and keep user-supplied values separate from its SQL structure.

  2. Work it out

    Prepare a MySQL query with one city value parameter and execute it for Pune.

  3. Avoid mistakes

    Concatenating an untrusted value into SQL is unsafe.

Dynamic SQL: the request and its result

  1. School need

    A report accepts a city value and an approved sort choice from the user. Both affect the request, but they cannot be handled with the same substitution rule.

  2. Database operation

    Dynamic SQL constructs or prepares a statement at runtime. The SQL structure and its data values require different handling.

  3. Check the outcome

    The statement structure stays fixed while the city value is supplied separately. A sort-column name would instead need selection from trusted SQL choices.

A conceptual model. The query examples below show the actual syntax, input data and results.

Understand what the database does

Bind data values through supported parameter markers. Identifiers and sort directions are part of SQL structure and usually cannot be replaced by a value parameter; choose them from an explicit allowlist instead. MySQL PREPARE and EXECUTE implement server-side prepared statements, with restrictions inside stored programs.

Related concepts: Prevent SQL Injection and SQL with Python.

What is Dynamic SQL?

Dynamic SQL is a SQL statement created and executed at runtime rather than being hardcoded into the procedure. You use it when the structure of your query is not fixed in advance — for example, when filtering by variable columns, table names, or sorting criteria.

MySQL Syntax Overview

  • PREPARE stmt_name FROM @sql
  • EXECUTE stmt_name
  • DEALLOCATE PREPARE stmt_name

Sample Table – students

MySQL 8.4 · prepared statement

CREATE TABLE students (
  roll_no INT,
  name VARCHAR(50),
  marks INT,
  city VARCHAR(30)
);

INSERT INTO students VALUES
(1, 'Aarav Sharma', 85, 'Delhi'),
(2, 'Diya Iyer', 92, 'Chennai'),
(3, 'Sneha Patil', 78, 'Pune'),
(4, 'Mehul Agarwal', 90, 'Delhi');

1. Basic Dynamic SQL – Select by City

Input definitions and data for this example. The shown statements establish the base fixture. Where this section changes an existing object, its required object definition is included below; use the stated before/after table to follow a sequence of changes.

CREATE TABLE students (
  roll_no INT,
  name VARCHAR(50),
  marks INT,
  city VARCHAR(30)
);

INSERT INTO students VALUES
(1, 'Aarav Sharma', 85, 'Delhi'),
(2, 'Diya Iyer', 92, 'Chennai'),
(3, 'Sneha Patil', 78, 'Pune'),
(4, 'Mehul Agarwal', 90, 'Delhi');

MySQL 8.4 · prepared statement

SET @city_name = 'Delhi';
SET @sql = CONCAT('SELECT name, marks FROM students WHERE city = "', @city_name, '"');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
name           | marks
----------------+-------
Aarav Sharma   | 85
Mehul Agarwal  | 90

2. Sorting Dynamically

Input definitions and data for this example. The shown statements establish the base fixture. Where this section changes an existing object, its required object definition is included below; use the stated before/after table to follow a sequence of changes.

CREATE TABLE students (
  roll_no INT,
  name VARCHAR(50),
  marks INT,
  city VARCHAR(30)
);

INSERT INTO students VALUES
(1, 'Aarav Sharma', 85, 'Delhi'),
(2, 'Diya Iyer', 92, 'Chennai'),
(3, 'Sneha Patil', 78, 'Pune'),
(4, 'Mehul Agarwal', 90, 'Delhi');

MySQL 8.4 · prepared statement

SET @sort_column = 'marks';
SET @sql = CONCAT('SELECT name, marks FROM students ORDER BY ', @sort_column, ' DESC');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
name           | marks
----------------+-------
Diya Iyer      | 92
Mehul Agarwal  | 90
Aarav Sharma   | 85
Sneha Patil    | 78

3. Inside a Stored Procedure

Input definitions and data for this example. The shown statements establish the base fixture. Where this section changes an existing object, its required object definition is included below; use the stated before/after table to follow a sequence of changes.

CREATE TABLE students (
  roll_no INT,
  name VARCHAR(50),
  marks INT,
  city VARCHAR(30)
);

INSERT INTO students VALUES
(1, 'Aarav Sharma', 85, 'Delhi'),
(2, 'Diya Iyer', 92, 'Chennai'),
(3, 'Sneha Patil', 78, 'Pune'),
(4, 'Mehul Agarwal', 90, 'Delhi');

MySQL 8.4 · prepared statement

DELIMITER $$

CREATE PROCEDURE get_students_by_city(IN p_city VARCHAR(30))
BEGIN
  SET @sql = CONCAT('SELECT name, marks FROM students WHERE city = "', p_city, '"');
  PREPARE stmt FROM @sql;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
END$$

DELIMITER ;

Call it:

CALL get_students_by_city('Pune');

When to Use Dynamic SQL

  • When table, column, or filter values are determined at runtime
  • When building advanced search or reporting systems
  • When writing reusable admin tools or dashboards

Best Practices

Query discussed in this section:

CALL get_students_by_city('Pune');
  • Always sanitize input to avoid SQL injection risks
  • Use prepared statements instead of directly executing dynamic strings
  • Use stored procedures to encapsulate dynamic SQL safely

Real-World School Use Cases

  • Generate student reports by city or class dynamically
  • Create dashboards where the admin selects filter criteria
  • Allow dynamic sorting and pagination of student data

Important differences and mistakes

Concatenating an untrusted value into SQL is unsafe. Escaping manually is not a substitute for parameter binding. Dynamic SQL is unnecessary when one static parameterized query already expresses the task.

Try it with the school data

Prepare a MySQL query with one city value parameter and execute it for Pune.

This practice uses a separate, fresh fixture named practice_students. It does not continue the changing table state of the earlier examples.

Practice input: practice_students
roll_nonameclassmarkscity
1Aarav10A85Pune
2Diya9B70Chennai
3Sneha10A85Pune

SQL · create only these practice tables in a disposable database:

CREATE TABLE practice_students (roll_no INTEGER PRIMARY KEY, name VARCHAR(50), class VARCHAR(10), marks INTEGER, city VARCHAR(30));
INSERT INTO practice_students VALUES
(1, 'Aarav', '10A', 85, 'Pune'),
(2, 'Diya', '9B', 70, 'Chennai'),
(3, 'Sneha', '10A', 85, 'Pune');

Worked answer and reasoning

This practice uses a separate, fresh fixture named practice_students. It does not continue the changing table state of the earlier examples.

Practice input: practice_students
roll_nonameclassmarkscity
1Aarav10A85Pune
2Diya9B70Chennai
3Sneha10A85Pune

SQL · create only these practice tables in a disposable database:

CREATE TABLE practice_students (roll_no INTEGER PRIMARY KEY, name VARCHAR(50), class VARCHAR(10), marks INTEGER, city VARCHAR(30));
INSERT INTO practice_students VALUES
(1, 'Aarav', '10A', 85, 'Pune'),
(2, 'Diya', '9B', 70, 'Chennai'),
(3, 'Sneha', '10A', 85, 'Pune');

MySQL 8.4 · prepared statement

PREPARE practice_report FROM 'SELECT name FROM practice_students WHERE city = ? ORDER BY roll_no';
SET @practice_city = 'Pune';
EXECUTE practice_report USING @practice_city;
DEALLOCATE PREPARE practice_report;
Expected result on the specified MySQL setup
name
Aarav
Sneha

The statement structure stays fixed while the city value is supplied separately. A sort-column name would instead need selection from trusted SQL choices.

Run this engine-specific script on a fresh MySQL 8.4 practice schema with the required routine privileges. It is not executable in SQLite.

Check your understanding

Can a value parameter normally stand in for an ORDER BY column name?
Choose one answer. You can try again.

Answer and explanation

No. Choose permitted identifier text from an allowlist.

The statement structure stays fixed while the city value is supplied separately. A sort-column name would instead need selection from trusted SQL choices.

Check your understanding

Which claim about this lesson’s practice result is justified?
Choose one answer. You can try again.

Answer and explanation

The statement structure stays fixed while the city value is supplied separately. A sort-column name would instead need selection from trusted SQL choices.

Concatenating an untrusted value into SQL is unsafe. Escaping manually is not a substitute for parameter binding. Dynamic SQL is unnecessary when one static parameterized query already expresses the task.

Use the idea independently

Dynamic SQL constructs or prepares a statement at runtime. The SQL structure and its data values require different handling.

The statement structure stays fixed while the city value is supplied separately. A sort-column name would instead need selection from trusted SQL choices.

Continue your understanding with Prevent SQL Injection and SQL with Python.

Source for the engine-specific behavior: MySQL 8.4 reference documentation.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: SQL Normalization — 1NF, 2NF, 3NF, BCNF →