sql >> Base de Datos >  >> RDS >> Sqlserver

Parametrizar una cláusula SQL IN

Puede parametrizar cada uno valor, entonces algo como:

string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" };
string cmdText = "SELECT * FROM Tags WHERE Name IN ({0})";

string[] paramNames = tags.Select(
    (s, i) => "@tag" + i.ToString()
).ToArray();

string inClause = string.Join(", ", paramNames);
using (SqlCommand cmd = new SqlCommand(string.Format(cmdText, inClause))) {
    for(int i = 0; i < paramNames.Length; i++) {
       cmd.Parameters.AddWithValue(paramNames[i], tags[i]);
    }
}

Lo que te dará:

cmd.CommandText = "SELECT * FROM Tags WHERE Name IN (@tag0, @tag1, @tag2, @tag3)"
cmd.Parameters["@tag0"] = "ruby"
cmd.Parameters["@tag1"] = "rails"
cmd.Parameters["@tag2"] = "scruffy"
cmd.Parameters["@tag3"] = "rubyonrails"

No, esto no está abierto a la inyección de SQL. El único texto inyectado en CommandText no se basa en la entrada del usuario. Se basa únicamente en el prefijo "@tag" codificado y en el índice de una matriz. El índice siempre ser un número entero, no es generado por el usuario y es seguro.

Los valores ingresados ​​por el usuario todavía están incluidos en los parámetros, por lo que no hay vulnerabilidad allí.

Editar:

Dejando a un lado las preocupaciones de inyección, tenga cuidado de tener en cuenta que construir el texto del comando para acomodar una cantidad variable de parámetros (como se indicó anteriormente) impide la capacidad del servidor SQL para aprovechar las consultas almacenadas en caché. El resultado neto es que es casi seguro que pierde el valor de usar parámetros en primer lugar (en lugar de simplemente insertar las cadenas de predicados en el propio SQL).

No es que los planes de consulta en caché no sean valiosos, pero en mi opinión, esta consulta no es lo suficientemente complicada como para ver mucho beneficio de ella. Si bien los costos de compilación pueden acercarse (o incluso superar) los costos de ejecución, todavía está hablando de milisegundos.

Si tiene suficiente RAM, espero que SQL Server probablemente también almacene en caché un plan para los recuentos comunes de parámetros. Supongo que siempre podría agregar cinco parámetros y dejar que las etiquetas no especificadas sean NULAS; el plan de consulta debería ser el mismo, pero me parece bastante feo y no estoy seguro de que valga la pena la microoptimización (aunque, en Stack Overflow; puede valer la pena).

Además, SQL Server 7 y versiones posteriores parametrizarán automáticamente las consultas, por lo que el uso de parámetros no es realmente necesario desde el punto de vista del rendimiento; sin embargo, es crítico. desde el punto de vista de la seguridad, especialmente con datos ingresados ​​por el usuario como este.