pass parameter how c# tsql

c# - how to pass sqlparameter to in()



Pase parĂ¡metro de matriz en SqlCommand (10)

Estoy tratando de pasar el parámetro array a SQL commnd en C # como a continuación, pero no funciona. ¿Alguien lo conoce antes?

string sqlCommand = "SELECT * from TableA WHERE Age IN (@Age)"; SqlConnection sqlCon = new SqlConnection(connectString); SqlCommand sqlComm = new SqlCommand(); sqlComm.Connection = sqlCon; sqlComm.CommandType = System.Data.CommandType.Text; sqlComm.CommandText = sqlCommand; sqlComm.CommandTimeout = 300; sqlComm.Parameters.Add("@Age", SqlDbType.NVarChar); StringBuilder sb = new StringBuilder(); foreach (ListItem item in ddlAge.Items) { if (item.Selected) { sb.Append(item.Text + ","); } } sqlComm.Parameters["@Age"].Value = sb.ToString().TrimEnd('','');


Como hay un método en

SqlCommand.Parameters.AddWithValue(parameterName, value)

podría ser más conveniente crear un método que acepte un parámetro (nombre) para reemplazar y una lista de valores. No está en el nivel Parámetros (como AddWithValue ) sino en el comando mismo, por lo que es mejor llamarlo AddParametersWithValues y no solo AddWithValues :

consulta:

SELECT * from TableA WHERE Age IN (@age)

uso:

sqlCommand.AddParametersWithValues("@age", 1, 2, 3);

el método de extensión:

public static class SqlCommandExtensions { public static void AddParametersWithValues<T>(this SqlCommand cmd, string parameterName, params T[] values) { var parameterNames = new List<string>(); for(int i = 0; i < values.Count(); i++) { var paramName = @"@param" + i; cmd.Parameters.AddWithValue(paramName, values.ElementAt(i)); parameterNames.Add(paramName); } cmd.CommandText = cmd.CommandText.Replace(parameterName, string.Join(",", parameterNames)); } }


O podrías intentar de la manera más simple:

var ages = new int[] { 1, 2, 3, 4, 6 }; var selectSQL = "SELECT * from TableA WHERE Age IN ({0})"; var sql = String.Format(selectSQL , String.Join(",", ages)); using (var command = CreateCommand(connection, sql)) { command.CommandType = CommandType.Text; using (var reader = command.ExecuteReader()) { ... } }


Pasar una serie de elementos como un parámetro contraído a la cláusula WHERE..IN fallará ya que la consulta tomará la forma de WHERE Age IN ("11, 13, 14, 16") .

Pero puede pasar su parámetro como una matriz serializada a XML o JSON:

Usando el método nodes() :

StringBuilder sb = new StringBuilder(); foreach (ListItem item in ddlAge.Items) if (item.Selected) sb.Append("<age>" + item.Text + "</age>"); // actually it''s xml-ish sqlComm.CommandText = @"SELECT * from TableA WHERE Age IN ( SELECT Tab.col.value(''.'', ''int'') as Age from @Ages.nodes(''/age'') as Tab(col))"; sqlComm.Parameters.Add("@Ages", SqlDbType.NVarChar); sqlComm.Parameters["@Ages"].Value = sb.ToString();

Usando el método OPENXML :

using System.Xml.Linq; ... XElement xml = new XElement("Ages"); foreach (ListItem item in ddlAge.Items) if (item.Selected) xml.Add(new XElement("age", item.Text); sqlComm.CommandText = @"DECLARE @idoc int; EXEC sp_xml_preparedocument @idoc OUTPUT, @Ages; SELECT * from TableA WHERE Age IN ( SELECT Age from OPENXML(@idoc, ''/Ages/age'') with (Age int ''text()'') EXEC sp_xml_removedocument @idoc"; sqlComm.Parameters.Add("@Ages", SqlDbType.Xml); sqlComm.Parameters["@Ages"].Value = xml.ToString();

Eso es un poco más en el lado SQL y necesitas un XML adecuado (con root).

Usando el método OPENJSON (SQL Server 2016+):

using Newtonsoft.Json; ... List<string> ages = new List<string>(); foreach (ListItem item in ddlAge.Items) if (item.Selected) ages.Add(item.Text); sqlComm.CommandText = @"SELECT * from TableA WHERE Age IN ( select value from OPENJSON(@Ages))"; sqlComm.Parameters.Add("@Ages", SqlDbType.NVarChar); sqlComm.Parameters["@Ages"].Value = JsonConvert.SerializeObject(ages);

Tenga en cuenta que para el último método, también debe tener el nivel de compatibilidad en 130+.


Quería ampliar la respuesta que Brian contribuyó para que esto fuera fácil de usar en otros lugares.

/// <summary> /// This will add an array of parameters to a SqlCommand. This is used for an IN statement. /// Use the returned value for the IN part of your SQL call. (i.e. SELECT * FROM table WHERE field IN (returnValue)) /// </summary> /// <param name="sqlCommand">The SqlCommand object to add parameters to.</param> /// <param name="array">The array of strings that need to be added as parameters.</param> /// <param name="paramName">What the parameter should be named.</param> protected string AddArrayParameters(SqlCommand sqlCommand, string[] array, string paramName) { /* An array cannot be simply added as a parameter to a SqlCommand so we need to loop through things and add it manually. * Each item in the array will end up being it''s own SqlParameter so the return value for this must be used as part of the * IN statement in the CommandText. */ var parameters = new string[array.Length]; for (int i = 0; i < array.Length; i++) { parameters[i] = string.Format("@{0}{1}", paramName, i); sqlCommand.Parameters.AddWithValue(parameters[i], array[i]); } return string.Join(", ", parameters); }

Puede usar esta nueva función de la siguiente manera:

SqlCommand cmd = new SqlCommand(); string ageParameters = AddArrayParameters(cmd, agesArray, "Age"); sql = string.Format("SELECT * FROM TableA WHERE Age IN ({0})", ageParameters); cmd.CommandText = sql; Editar: Aquí hay una variación genérica que funciona con una matriz de valores de cualquier tipo y se puede usar como método de extensión:

public static class Extensions { public static void AddArrayParameters<T>(this SqlCommand cmd, string name, IEnumerable<T> values) { name = name.StartsWith("@") ? name : "@" + name; var names = string.Join(", ", values.Select((value, i) => { var paramName = name + i; cmd.Parameters.AddWithValue(paramName, value); return paramName; })); cmd.CommandText = cmd.CommandText.Replace(name, names); } }

Luego puede usar este método de extensión de la siguiente manera:

var ageList = new List<int> { 1, 3, 5, 7, 9, 11 }; var cmd = new SqlCommand(); cmd.CommandText = "SELECT * FROM MyTable WHERE Age IN (@Age)"; cmd.AddArrayParameters("Age", ageList);

Asegúrese de configurar el CommandText antes de llamar a AddArrayParameters.

También asegúrese de que el nombre de su parámetro no coincida parcialmente con ninguna otra cosa en su declaración (es decir, @AgeOfChild)


Si está utilizando MS SQL Server 2008 y posterior, puede usar parámetros con valores de tabla como se describe aquí http://www.sommarskog.se/arrays-in-sql-2008.html .

1. Cree un tipo de tabla para cada tipo de parámetro que usará

El siguiente comando crea un tipo de tabla para enteros:

create type int32_id_list as table (id int not null primary key)

2. Implementar métodos de ayuda

public static SqlCommand AddParameter<T>(this SqlCommand command, string name, IEnumerable<T> ids) { var parameter = command.CreateParameter(); parameter.ParameterName = name; parameter.TypeName = typeof(T).Name.ToLowerInvariant() + "_id_list"; parameter.SqlDbType = SqlDbType.Structured; parameter.Direction = ParameterDirection.Input; parameter.Value = CreateIdList(ids); command.Parameters.Add(parameter); return command; } private static DataTable CreateIdList<T>(IEnumerable<T> ids) { var table = new DataTable(); table.Columns.Add("id", typeof (T)); foreach (var id in ids) { table.Rows.Add(id); } return table; }

3. Úselo así

cmd.CommandText = "select * from TableA where Age in (select id from @age)"; cmd.AddParameter("@age", new [] {1,2,3,4,5});


Si puede usar una herramienta como "dapper", esto puede ser simplemente:

int[] ages = { 20, 21, 22 }; // could be any common list-like type var rows = connection.Query<YourType>("SELECT * from TableA WHERE Age IN @ages", new { ages }).ToList();

Dapper se encargará de desenvolver esto en parámetros individuales para usted .


Tendrá que agregar los valores en la matriz uno a la vez.

var parameters = new string[items.Length]; var cmd = new SqlCommand(); for (int i = 0; i < items.Length; i++) { parameters[i] = string.Format("@Age{0}", i); cmd.Parameters.AddWithValue(parameters[i], items[i]); } cmd.CommandText = string.Format("SELECT * from TableA WHERE Age IN ({0})", string.Join(", ", parameters)); cmd.Connection = new SqlConnection(connStr);

ACTUALIZAR: Aquí hay una solución extendida y reutilizable que usa la respuesta de Adam junto con su edición sugerida. Lo mejoré un poco y lo convertí en un método de extensión para que sea aún más fácil llamar.

public static class SqlCommandExt { /// <summary> /// This will add an array of parameters to a SqlCommand. This is used for an IN statement. /// Use the returned value for the IN part of your SQL call. (i.e. SELECT * FROM table WHERE field IN ({paramNameRoot})) /// </summary> /// <param name="cmd">The SqlCommand object to add parameters to.</param> /// <param name="paramNameRoot">What the parameter should be named followed by a unique value for each value. This value surrounded by {} in the CommandText will be replaced.</param> /// <param name="values">The array of strings that need to be added as parameters.</param> /// <param name="dbType">One of the System.Data.SqlDbType values. If null, determines type based on T.</param> /// <param name="size">The maximum size, in bytes, of the data within the column. The default value is inferred from the parameter value.</param> public static SqlParameter[] AddArrayParameters<T>(this SqlCommand cmd, string paramNameRoot, IEnumerable<T> values, SqlDbType? dbType = null, int? size = null) { /* An array cannot be simply added as a parameter to a SqlCommand so we need to loop through things and add it manually. * Each item in the array will end up being it''s own SqlParameter so the return value for this must be used as part of the * IN statement in the CommandText. */ var parameters = new List<SqlParameter>(); var parameterNames = new List<string>(); var paramNbr = 1; foreach (var value in values) { var paramName = string.Format("@{0}{1}", paramNameRoot, paramNbr++); parameterNames.Add(paramName); SqlParameter p = new SqlParameter(paramName, value); if (dbType.HasValue) p.SqlDbType = dbType.Value; if (size.HasValue) p.Size = size.Value; cmd.Parameters.Add(p); parameters.Add(p); } cmd.CommandText = cmd.CommandText.Replace("{" + paramNameRoot + "}", string.Join(",", parameterNames)); return parameters.ToArray(); } }

Se llama así ...

var cmd = new SqlCommand("SELECT * FROM TableA WHERE Age IN ({Age})"); cmd.AddArrayParameters("Age", new int[] { 1, 2, 3 });

Observe que "{Age}" en la instrucción sql es el mismo que el nombre del parámetro que estamos enviando a AddArrayParameters. AddArrayParameters reemplazará el valor con los parámetros correctos.


Use .AddWithValue() , entonces:

sqlComm.Parameters.AddWithValue("@Age", sb.ToString().TrimEnd('',''));

Alternativamente, podrías usar esto:

sqlComm.Parameters.Add( new SqlParameter("@Age", sb.ToString().TrimEnd('','')) { SqlDbType = SqlDbType. NVarChar } );

Su muestra total de código se verá a continuación:

string sqlCommand = "SELECT * from TableA WHERE Age IN (@Age)"; SqlConnection sqlCon = new SqlConnection(connectString); SqlCommand sqlComm = new SqlCommand(); sqlComm.Connection = sqlCon; sqlComm.CommandType = System.Data.CommandType.Text; sqlComm.CommandText = sqlCommand; sqlComm.CommandTimeout = 300; StringBuilder sb = new StringBuilder(); foreach (ListItem item in ddlAge.Items) { if (item.Selected) { sb.Append(item.Text + ","); } } sqlComm.Parameters.AddWithValue("@Age", sb.ToString().TrimEnd('','')); // OR // sqlComm.Parameters.Add(new SqlParameter("@Age", sb.ToString().TrimEnd('','')) { SqlDbType = SqlDbType. NVarChar });


pruébalo así

StringBuilder sb = new StringBuilder(); foreach (ListItem item in ddlAge.Items) { if (item.Selected) { string sqlCommand = "SELECT * from TableA WHERE Age IN (@Age)"; SqlConnection sqlCon = new SqlConnection(connectString); SqlCommand sqlComm = new SqlCommand(); sqlComm.Connection = sqlCon; sqlComm.CommandType = System.Data.CommandType.Text; sqlComm.CommandText = sqlCommand; sqlComm.CommandTimeout = 300; sqlComm.Parameters.Add("@Age", SqlDbType.NVarChar); sb.Append(item.Text + ","); sqlComm.Parameters["@Age"].Value = sb.ToString().TrimEnd('',''); } }


tratar

sqlComm.Parameters["@Age"].Value = sb.ToString().Replace(","," ");