Las sentencias dinámicas son sentencias SQL que se crean como cadenas de texto (strings) y en las que se insertan/concatenan valores obtenidos de alguna fuente (normalmente proveniente del usuario), lo que puede hacer que sean vulnerables a inyección SQL si no se sanean las entradas, como por ejemplo:
¿Cómo puedo evitar que la inyección SQL ocurra en PHP?
NO USES SENTENCIAS DINÁMICAS NI FUNCIONES mysql_*
Las funciones mysql_* (mysql_connect, mysql_query, etc.) son inseguras por naturaleza y su uso no sólo no está recomendado, sino que se consideran obsoletas y se han eliminado completamente a partir de PHP7.
Incluso los métodos nativos que existen en PHP para sanear las entradas de usuario (como mysql_real_escape_string) pueden presentar (raros) problemas y fallar en algunos casos como cuando se usan codificación de caracteres diferentes a UTF-8 junto a versiones no actualizadas de MySQL (en las páginas de PHP para estas funciones se avisa de este riesgo).
Usa sentencias preparadas y consultas parametrizadas
Aunque se podrían sanear las entradas usando métodos como mysqli_real_escape_string, es más recomendable la utilización de sentencias preparadas o parametrizadas. Las sentencias preparadas te permitirán ejecutar la misma sentencia con gran eficiencia.
En PHP, tienes dos alternativas principales: PDO y MySQLi. Hay varias diferencias entre ambas, pero la principal es que PDO se puede usar con diferentes tipos de base de datos (dependiendo del driver utilizado) mientras que MySQLi es exclusivamente para bases de datos MySQL. Es por ello que recomendaría PDO sobre MySQLi.
PDO
Los marcadores de posición (que indican dónde se sustituirá una cadena por su valor), se pueden definir bien usando un signo de interrogación (?) o bien usando un nombre (generalmente empezando con :). Personalmente prefiero usar un nombre, porque eso me ayuda a encontrar posibles errores en caso de tener múltiples variables.
Aquí dejo un ejemplo:
En este caso, :idusuario se sustituirá por el valor de $_POST[“id_usuario”] de forma segura, y cuando hace el bind se indica que la variable es de tipo entero (PDO::PARAM_INT).
Nota: si la variable es una cadena de texto se usará PDO::PARAM_STR y no hace falta poner las comillas en la sentencia SQL; al especificarle a PHP que es una cadena, las añadirá automáticamente al hacer el bind.
En caso de que existan varias variables a incluir en la sentencia SQL, se debe incluir un único parámetro para cada uno de los valores que se usan en la sentencia. Del ejemplo anterior, el :id_usuario puede usarse una única vez en la consulta que se esta preparando. Si fuera necesario usar el “id_usuario” de nuevo en la consulta, se debe crear otro parámetro con el valor de $usuario_id.
MySQLi
Este método tiene dos interfaces: una procedural y otra orientada a objetos. La interfaz procedural es muy parecida a mysql_*, y por ello la gente que migra desde mysql_* puede sentirse atraída por la facilidad que mysqli_* ofrece. Aunque, de nuevo personalmente, optaría por la versión POO.
Nota: aunque las funciones mysqli_* suelen ser parecidas a las mysql_*, en algunos casos pueden tener diferentes parámetros de entrada o diferentes salidas, lo que puede llevar a algo de confusión al principio.
El ejemplo de la pregunta quedaría así con MySQLi en su interfaz orientada a objetos:
Como se puede ver, es bastante parecido a PDO (cambia un poco cómo se especifica el tipo de valor, i para enteros y s para cadenas, pero la idea es similar).
En la versión procedural de MySQLi, el código equivalente sería:
Fuente y bibliografía para más información en español: