sql-server - repetidos - no mostrar registros duplicados sql server
¿Cómo mantener el orden de las filas con SqlBulkCopy? (4)
Estoy exportando datos programáticamente de Excel a SQL Server 2005 usando SqlBulkCopy. Funciona muy bien, el único problema que tengo es que no conserva la secuencia de filas que tengo en el archivo de Excel. No tengo una columna para ordenar, solo quiero que los registros se inserten en el mismo orden en que aparecen en la hoja de cálculo de Excel.
No puedo modificar el archivo de Excel y tengo que trabajar con lo que tengo. Ordenar por cualquiera de las columnas existentes romperá la secuencia.
Por favor ayuda.
PS: terminó insertando la columna de ID en la hoja de cálculo, parece que no hay forma de mantener el orden durante la exportación / importación
No creo que SQL especifique o garantice el orden de filas a menos que use una cláusula "ORDER BY".
De una publicación de Bill Vaughn ( http://betav.com/blog/billva/2008/08/sql_server_indexing_tips_and_t.html ):
Uso de Ordenar por: incluso cuando una tabla tiene un índice agrupado (que almacena los datos en orden físico), SQL Server no garantiza que las filas serán devueltas en ese (o en cualquier orden particular) a menos que se use una cláusula ORDER BY.
Otro enlace con información:
http://sqlblogcasts.com/blogs/simons/archive/2007/08/21/What-is-the-position-of-a-row--.aspx
Si puede guardar la hoja de cálculo de Excel como CSV, es muy fácil generar una lista de instrucciones INSERT con cualquier lenguaje de script que se ejecutará en el mismo orden que la hoja de cálculo. Aquí hay un ejemplo rápido en Groovy, pero cualquier lenguaje de scripting lo hará igual de fácil, si no más fácil:
def file1 = new File(''c://temp//yourSpreadsheet.csv'')
def file2 = new File(''c://temp//yourInsertScript.sql'')
def reader = new FileReader(file1)
def writer = new FileWriter(file2)
reader.transformLine(writer) { line ->
fields = line.split('','')
text = """INSERT INTO table1 (col1, col2, col3) VALUES (''${fields[0]}'', ''${fields[1]}'', ''${fields[2]}'');"""
}
Luego puede ejecutar su "yourInsertScript.sql" contra su base de datos y su orden será la misma que su hoja de cálculo.
También es posible que pueda definir una columna de identidad en su tabla que aumente automáticamente durante la carga de datos. De esta forma, puede ordenarlo más tarde cuando desee los registros en el mismo orden nuevamente.
Después de mucha investigación, parece evidente que no hay forma de mantener el orden de las filas con el comando de inserción masiva escrito como lo presenta Microsoft. Debe agregar una columna de ID directamente en el archivo de importación, usar un shell u otro script externo, o puede hacerlo sin él. Parece que sería una función necesaria (y fácil) para Microsoft agregar, pero después de más de una década de nada de ellos, no va a suceder.
Sin embargo, necesitaba preservar el orden de registro real en el archivo de importación después de la importación, ya que los registros superiores reemplazarían a los inferiores si una columna establecida tuviera el mismo valor.
Así que fui por una ruta diferente. Mis limitaciones fueron:
- No pude cambiar el archivo fuente en absoluto. (¡y sienta un mal precedente!)
- No pude usar un script externo. Demasiado complicado. Tenía que ser una solución simple basada en T-Sql, sin ejecuciones de CMD. Esto tenía que pasar por un único procedimiento para poder automatizarlo.
Me gustó la lógica de usar Powershell para crear instrucciones de inserción ordenadas para cada fila y luego ejecutarlas en Sql. En esencia, estaba poniendo en cola cada registro para una inserción individual en lugar de una inserción BULK. Sí, funcionaría, pero también sería muy lento. A menudo tengo archivos con 500K + filas en ellos. Necesitaba algo RÁPIDO.
Así que me encontré con XML. A granel cargue el archivo directamente en una sola variable XML. Esto mantendría el orden de los registros ya que cada uno se agrega al XML. Luego analice la variable XML e inserte los resultados en una tabla, agregando una columna de identidad al mismo tiempo.
Se supone que el archivo de importación es un archivo de texto estándar, y cada registro termina en una línea de alimentación (Char (13) + Char (10))
Mi enfoque tiene 2 pasos:
Ejecute la instrucción IMPORT de SQL (usando OPENROWSET), encapsulando cada registro con etiquetas XML. Capture los resultados en una variable XML.
Analice la variable por las etiquetas XML en una tabla, agregando una columna de incremento [ID].
--------------------------------- Declare @X xml; --------------------------------- SELECT @X=Cast(''<X>''+Replace([BulkColumn],Char(13)+Char(10),''</X><X>'')+''</X>'' as XML) FROM OPENROWSET (BULK N''//FileServer/ImportFolder/ImportFile_20170120.csv'',SINGLE_CLOB) T --------------------------------- SELECT [Record].[X].query(''.'').value(''.'',''varchar(max)'') [Record] ,ROW_NUMBER() OVER (ORDER BY (SELECT 100)) [ID] --Into #TEMP FROM @X.nodes(''X'') [Record](X); ---------------------------------
Las etiquetas XML reemplazan cada alimentación de línea.
Si el archivo finaliza con un salto de línea, esto provocará que se agregue una fila en blanco al final. Simplemente elimine la última fila.
Escribí esto en mi procedimiento usando sql dinámico para poder pasar el FileName y configurar el ID para comenzar en 1 o 0 (en caso de que haya una fila de encabezado).
Pude ejecutar esto contra un archivo de 300K registros en aproximadamente 5 segundos.