2010-10-25 15 views
8

que tiene una gran lista de parámetros int para una consulta SQL:lista de parámetros grande para la consulta SQL

update mytable set col='xyz' 
where id in (/* thousands of ints */) 

Mi problema es que en SQL Server 2000, hay un límite para los parámetros. Podría ejecutar esta consulta también en un SQL Server 2008.

¿Cuál es la mejor manera de hacer esto.

Editar:

la lista de identificadores provienen de un programa C#. No de otra mesa.

Respuesta

2

La mejor Soulution de trabajo para mí fue SQL Server 2008: Table Valued Parameters

100000 Ids necesita 14-20s, 1000 Ids necesita ~ 140ms.

sql = @" 
    update MyTable 
    set Col1 = 1 
    where ID in (select * from @ids) 
    "; 
sqlCmd = new SqlCommand {Connection = _sqlConn, CommandText = sql}; 

//Create a DataTable with one Column("id") and all ids as DataRows 
DataTable listOfLeadIDs = new DataTable(); 
listOfIDs.Columns.Add("id", typeof(int)); 
Ids.ToList<string>().ForEach(x => listOfIDs.Rows.Add(new object[] { int.Parse(x) })); 

//Bind this DataTable to the Command-object 
// Node: "IntTable" is an User-Defined-Table-Typ (new feature with SQL-2008) 
sqlCmd.Parameters.Add(
    new System.Data.SqlClient.SqlParameter("@ids", listOfIDs) { 
    TypeName = "IntTable" 
    }); 

//Execute the Query 
sqlCmd.ExecuteNonQuery(); 

El definida por el usuario-Tabla-Typ:

CREATE TYPE [dbo].[IntTable] AS TABLE(
    [id] [int] NULL 
) 
GO 
2

Puede insertar los números enteros en una tabla temporal, y luego consulta como esta:

update mytable m set col='xyz' 
where exists (select * from #MyTempTable where id = m.id) 
+0

¿Es esta una buena idea? el tiempo de ejecución para Insertar 5000x en #MyTempTable podría ser exorbitante. – Floyd

+0

'IN' es ** no ** una buena opción si la lista es más que algunas. 'EXISTS' es el camino a seguir. – Brad

+0

@Brad: correcto, actualizado. – RedFilter

1

A toda costa, EVITARIN; especialmente si eres post-2000. my backup


su lugar, utilice EXISTS

UPDATE myTable 
SET col = 'newValue' 
FROM myTable 
WHERE EXISTS (
     SELECT * 
     FROM @myTempTable temp 
     WHERE myTable.ID = temp.ID) 
+0

mismo que RedFilters mensaje: el tiempo para excecution 5000x Insertar en #MyTempTable podría ser exorbitantes. – Floyd

+0

Creo que 5000 insertos de un solo 'INT 'no sería tan malo. ¿Hay alguna otra forma de obtener la lista de 'INT's a través de una consulta? – Brad

+0

No, no puedo. Ese es mi problema. La lista de Ids generada por un programa. – Floyd

2

Un enfoque alternativo que funciona con SQL 2000 es utilizar XML.

Hacer que el formato del programa/aplicación de los enteros de este modo:

'<root><TMP J="111"/><TMP J="222"/><TMP J="333"/></root>' 

.
A continuación, cree el siguiente procedimiento almacenado:

CREATE PROCEDURE UpDateIntsFromXML (
    @sXML TEXT 
) 
AS 
    DECLARE @iDoc INT 
    EXEC sp_xml_preparedocument @iDoc OUTPUT, @sXML 

    UPDATE YourTable 
    SET  YourColumn = 'fixed value' 
    FROM OPENXML (@iDoc, '/root/TMP', 1) WITH (J INT) AS X 
    WHERE X.J = YourTable.IntColumn 

    EXEC sp_xml_removedocument @iDoc 
RETURN 

.
Luego su aplicación puede llamar a ese SP, pasando un bloque de texto/XML potencialmente enorme.

Obsérvese que root, TMP y J son todas mayúsculas y minúsculas.

+0

De esta manera podría ser un trabajo, vamos a intentar esto. También hemos encontrado otras dos formas: * al principio *: [Parámetros con valores de tabla] (http://lennilobel.wordpress.com/2009/07/29/sql-server-2008-table-valued-parameters-and- c-custom-iterators-a-match-made-in-heaven /) * o * SqlBulkCopy ... intentaremos esto también. – Floyd

+0

+1, me gusta esto. Floyd, avísanos si esto funciona. – Brad

+0

Esto funciona, pero los parámetros con valores de tabla son más rápidos. pero esta característica no funciona con SQL-2000. – Floyd

0

dividir los datos en grupos más pequeños, y ejecutar múltiples consultas de actualización.

No hay ninguna razón para utilizar una tabla temporal, ya que permite recuperar los datos desde fuera del db, así que no hay manera de evitar su transferencia hacia el PP.

+0

Esto funciona con '' IN' o EXISTS' pero no con '' NO IN' o NO EXISTS' – Floyd

+0

Pero la consulta hace uso de 'IN', no 'NO EN'. Se ejecuta la misma consulta, sino varias veces, en los conjuntos de datos más pequeños ... – Andy

+0

pero mi pregunta WHAS "Lista de parámetros bits para consulta SQL" no "lista de parámetros para un poco 'en' -query" .. la consulta sólo era una examen – Floyd

0

Si los enteros son de ninguna manera secuencial (más de dos a la vez), se puede hacer de ellos BETWEEN pares.

Pero en este caso, basta con una cadena de estos enteros y pasar que como una sola varchar(max) parámetro.

-2

creo que es probable que desee crear una tabla temporal basada memoria con un índice. Suponiendo que la tabla sobre la que está consultando es grande, no le conviene hacer una exploración de tabla comparando cada fila con cada una de sus 5000 coincidencias. Quieres unirte con la ayuda de dos índices.

CREATE TEMPORARY TABLE IF NOT EXISTS inputlist 
(i INT PRIMARY KEY) ENGINE = MEMORY; 

INSERT INTO inputlist (i) VALUES (1),(2),(3),(1000),(2000),(5000); 

SELECT * FROM your_table JOIN inputlist ON your_table.intvalues = inputlist.i; 

DROP TEMPORARY TABLE inputlist; 

SQL basado en MySQL, consulte:
http://dev.mysql.com/doc/refman/5.1/en/memory-storage-engine.html
http://dev.mysql.com/doc/refman/5.1/en/insert.html
http://dev.mysql.com/doc/refman/5.1/en/create-table.html

+0

este doenst funciona con sql-2000 o sql-2008. Si lo intento también hago esto con insertos singel (las multiinstrucciones no son compatibles con sql-2000) me sale un error: 'Msg 8621, nivel 17, estado 88, línea 5 Error interno del procesador de consultas: el procesador de consultas se quedó sin espacio en la pila durante la optimización de consultas. Enviaría las inserciones en bloques, pero esto lleva mucho tiempo para el transporte y la compilación de enunciados. – Floyd

+0

Mi error, no presté atención a la nota MS Sql. No soy muy familiar allí, pero sí noté una página que sugiere una solución a esto, tal vez vale la pena una prueba rápida: http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId = 897 & lngWId = 5 –

+0

Esta soulution (de la fuente de la más rápida) funciona pero solo con muy pocos ids. no con cientos y no con miles. – Floyd

Cuestiones relacionadas