2012-02-23 16 views
6

Tengo una pregunta sobre una forma eficiente de actualizar varias filas a través de SQL.C#, SQL update multiple rows

Basiclly Tengo una consulta que necesito para funcionar en diferentes ROWIDs:

UPDATE TableName SET Column = (some number) WHERE RowID = (some number) 

si para ser más específico que esto es un mejor ejemplo:

UPDATE TableName SET Column = 5 WHERE RowID = 1000 
UPDATE TableName SET Column = 10 WHERE RowID = 1001 
UPDATE TableName SET Column = 30 WHERE RowID = 1002 
.. 

me gustaría saber cómo deben Construyo el comando de consulta de actualización en C# (o simplemente doy un ejemplo de la consulta resultante a la que debería llegar) así que una vez que use ExecuteQuery ejecutará todos estos comandos de una pieza y no mediante la ejecución de cada comando.

editado: tengo otro problema, puede también explicar lo que acerca de la situación dinámica en la que no necessarly la fila quiero actualizar ya existen, en ese caso tengo que insertar en lugar de actualización. Para explicar mejor, volver a mi ejemplo digamos que quiero hacer

UPDATE TableName SET Column = 5 WHERE RowID = 1000 
INSERT INTO TableName [RowID, Column] VALUES (1001, 20) 
UPDATE TableName SET Column = 30 WHERE RowID = 1002 
.. 

El significado de esto es que necesito para comprobar si la fila existe, si es así me gustaría usar la actualización de lo contrario voy a tener que insertar eso.

¡Gracias!

+0

¿Procedimiento almacenado? – Vedran

+0

¿Puede confirmar qué producto de base de datos y versión está utilizando? Para el Servidor SQL moderno (> = 2008), estaría buscando usar un parámetro con valores de tabla y una declaración 'MERGE' –

Respuesta

7

Se puede usar un DataTable para almacenar sus archivos, insertar, eliminar o cambiar filas y actualizar todos los cambios en un lote mediante el uso de SqlDataAdapter UpdateBatchSize (0 significa sin límite):

public static void BatchUpdate(DataTable dataTable,Int32 batchSize) 
{ 
    // Assumes GetConnectionString() returns a valid connection string. 
    string connectionString = GetConnectionString(); 

    // Connect to the AdventureWorks database. 
    using (SqlConnection connection = new 
     SqlConnection(connectionString)) 
    { 

     // Create a SqlDataAdapter. 
     SqlDataAdapter adapter = new SqlDataAdapter(); 

     // Set the UPDATE command and parameters. 
     adapter.UpdateCommand = new SqlCommand(
      "UPDATE Production.ProductCategory SET " 
      + "[email protected] WHERE [email protected];", 
      connection); 
     adapter.UpdateCommand.Parameters.Add("@Name", 
      SqlDbType.NVarChar, 50, "Name"); 
     adapter.UpdateCommand.Parameters.Add("@ProdCatID", 
      SqlDbType.Int, 4, "ProductCategoryID"); 
     adapter.UpdateCommand.UpdatedRowSource = UpdateRowSource.None; 

     // Set the INSERT command and parameter. 
     adapter.InsertCommand = new SqlCommand(
      "INSERT INTO Production.ProductCategory (Name) VALUES (@Name);", 
      connection); 
     adapter.InsertCommand.Parameters.Add("@Name", 
      SqlDbType.NVarChar, 50, "Name"); 
     adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.None; 

     // Set the DELETE command and parameter. 
     adapter.DeleteCommand = new SqlCommand(
      "DELETE FROM Production.ProductCategory " 
      + "WHERE [email protected];", connection); 
     adapter.DeleteCommand.Parameters.Add("@ProdCatID", 
      SqlDbType.Int, 4, "ProductCategoryID"); 
     adapter.DeleteCommand.UpdatedRowSource = UpdateRowSource.None; 

     // Set the batch size. 
     adapter.UpdateBatchSize = batchSize; 

     // Execute the update. 
     adapter.Update(dataTable); 
    } 
} 

http://msdn.microsoft.com/en-us/library/aadf8fk2.aspx

Supongo que estás malinterpretando cómo funciona el DBMS internamente. Este

UPDATE TableName SET Column = 5 WHERE RowID = 1000; 
UPDATE TableName SET Column = 5 WHERE RowID = 1002; 

es lo mismo que

UPDATE TableName SET Column = 5 WHERE RowID IN(1000,2002); 

el DBMS actualizará todos los registros afectados, uno por uno de todos modos, incluso si usted escribiría una declaración como UPDATE table SET value=1 lo que afectaría a todos los registros de la tabla. Al actualizar en un lote, se asegura de que todas las actualizaciones (eliminaciones, inserciones) se envíen a la base de datos en lugar de una ida y vuelta para cada declaración.

+0

Estoy viendo el código de actualización (ya que es el más relevante para mi pregunta) y no lo hice Entiendo bastante bien cuál es la consulta resultante al final y por qué es eficiente? parece que estás construyendo la consulta que intento evitar, ¿no es así? – Popokoko

+1

El dbms actualizará todos los registros afectados uno por uno de todos modos, incluso si usted escribe una declaración como 'UPDATE tabla SET valor = 1' que afectaría a cada registro en la tabla.Al actualizar en un lote, se asegura de que todas las actualizaciones (eliminaciones, inserciones) se comprometan a la vez en la misma transacción. –

+0

Se debe tener en cuenta que 'Update (dataTable)' está [documentado] (http://msdn.microsoft.com/en-us/library/z1z2bkx2.aspx) para no batir las actualizaciones: "Debe tenerse en cuenta que estos las declaraciones no se realizan como un proceso por lotes, cada fila se actualiza individualmente ", y los lotes y las transacciones son dos conceptos ortogonales en SQL. –

0

Uso MERGE:

MERGE INTO TableName 
    USING (
      VALUES (1000, 5), 
       (1001, 10), 
       (1002, 30) 
     ) AS source (RowID, Column_name) 
     ON TableName.RowID = source.RowID 
WHEN MATCHED THEN 
    UPDATE 
     SET Column_name = source.Column_name 
WHEN NOT MATCHED THEN 
    INSERT (RowID, Column_name) 
     VALUES (RowID, Column_name); 

En lugar de difícil codificación/SQL dinámico, la declaración MERGE podrían ser encapsulados en un procedimiento almacenado que toma un table-valued parameter.