SQL Server
Introducción
El primer escollo que un programador se encuentra a la hora de establecer conexiones a una base de datos es tomar la decisión de qué tipo de conexión y driver utilizará. Como ocurre con MS Access, para SQL Server se vuelve a tener el mismo problema: demasiados drivers y demasiadas versiones para cada driver. A ello se le ha de añadir que Microsoft considera que están en desuso los drivers que vienen instalados con el Sistema Operativo. En Historial de controladores para Microsoft SQL Server se puede ver el historial de las diferentes tecnologías utilizadas para la conexión a SQL Server. En la página Matriz de compatibilidad de características del controlador para Microsoft SQL Server se muestra un listado de las características que soporta cada controlador.
Por contra, existe una ventaja con respecto a MS Access: para conectarse a SQL Server no es necesario la instalación de ningún driver, ya que .NET contiene el suyo propio, en realidad tiene dos drivers, y uno de ellos viene incluido con Excel To Database.
Las pruebas que aquí se detallan para SQL Server no incluyen pruebas para “Microsoft SQL Server Database File” (¿alguien lo ha usado?) ni pruebas con la nube Azure SQL Database, ya que no se dispone de ninguna base de datos en dicho entorno debido a la escasez de recursos económicos de que dispone el equipo de MalaCharger.
No todos los drivers de SQL Server se comportan igual ante datos corruptos. Nuestras pruebas exhaustivas han identificado escenarios donde el driver falla sin dar información clara, permitiendo que Excel To Database intercepte estos errores y ofrezca un diagnóstico preciso al usuario.
Hemos sometido al motor a pruebas de estrés con desbordamientos de tipos de datos, nulos inesperados y pérdida de conexión. El objetivo es garantizar que, ante un fallo del servidor o del driver, la aplicación proteja la integridad de la transacción.
Para facilitar una depuración precisa, Excel To Database captura la excepción nativa del driver y la exporta íntegramente en formato JSON. Esto permite a los técnicos acceder al Status Code, el mensaje de error del motor y detalles extendidos que normalmente se pierden en interfaces simplificadas.
Al incluir el código de estado (Status Code) dentro del objeto JSON, es posible identificar rápidamente si el fallo es de red, de permisos o de integridad de datos, permitiendo una respuesta inmediata sin necesidad de revisar los logs internos del servidor SQL.
Aquí se presenta un resumen de los tipos de datos soportados por SQL Server, centrado en las capacidades de cada tipo de datos y su precisión. Para mas detalle se puede consultar la página: Tipos de datos (Transact-SQL)
| Tipo de Datos | Asignación de almacenamiento nominal | Intervalo de valores |
|---|---|---|
| Decimal | Precisión: 1 - 9 : 5 bytes 10 - 19 : 9 bytes 20 - 28 : 13 bytes 29 - 38 : 17 bytes | Depende de la Precisión y la Escala |
| real(float(24)) | 4 bytes | De -3,402823E+38 a -1,401298E-45 para valores negativos. De 1,401298E-45 a 3,402823E+38 para valores positivos. Los valores son redondeados a 7 dígitos significativos. |
| float(float(53)) | 8 bytes | De -1,79769313486231570E+308 a -4,94065645841246544E-324 para valores negativos. De 4,94065645841246544E-324 a 1,79769313486231570E+308 para valores positivos. Los valores son redondeados a 15 dígitos significativos. |
| Bit | 1 bit | 0-1 |
| tinyint | 1 byte | De 0 a 255 (sin signo). |
| smallint | 2 bytes | De -32.768 a 32.767 (con signo). |
| int | 4 bytes | De -2.147.483.648 a 2.147.483.647 (con signo). |
| bigint | 8 bytes | De -9.223.372.036.854.775.808 a 9.223.372.036.854.775.807 (con signo). |
| smallmoney | 4 bytes | De -214.748,3648 a 214.748,3647. |
| money | 8 bytes | De -922.337.203.685.477,5808 a 922.337.203.685.477,5807 |
| date | 3 bytes | De 0001-01-01 a 9999-12-31. |
| smalldatetime | 4 bytes | De 1900-01-01 00:00:00 a 2079-06-06 23:59:29,998. Se redondea a minutos: mayor que 29,998 al minuto superior, menor o igual que 29,998 al minuto inferior. |
| datetime | 8 bytes | De 1753-01-01 00:00:00,000 a 9999-12-31 23:59:59,997. Se redondea en incrementos de 0,000, 0,003 o 0,007 segundos |
| datetime2(p) | 6 bytes para una precisión inferior a 3. 7 bytes para las precisiones 3 y 4. 8 bytes para el resto de precisiones. | De 0001-01-01 00:00:00,0000000 a 9999-12-31 23:59:59,9999999. |
| time(p) | 5 bytes | De 00:00:00,0000000 a 23:59:59,9999999 |
| datetimeoffset(p) | 10 bytes | De 0001-01-01 00:00:00,0000000 a 9999-12-31 23:59:59,9999999. Intervalo de ajuste de zona horaria: De -14:00 a +14:00. Ejemplo, 9999-12-31 10:10:00 son válidos en UTC, pero se desbordan en la hora local al ajuste de zona horaria +13:50 |
Este capítulo muestra los resultados de los comportamientos de diferentes proveedores de datos y drivers de SQL Server ante diferentes situaciones no contempladas en los capítulos anteriores. Se espera con ello ayudar a resolver problemas y dudas respecto al comportamiento de Excel To Database.
Drivers SQL Server
-
Drivers ODBC
Según se indica en Historial de controladores para Microsoft SQL Server (ODBC) Microsoft recomienda utilizar el Microsoft ODBC Driver for SQL Server, cuyas carácterísticas y documentación se pueden encontrar en: Controlador ODBC de Microsoft para SQL Server. En Notas de la versión de Microsoft ODBC Driver for SQL Server en Windows además de encontrar los enlaces a la descarga del controlador, se pueden consultar las características de cada versión del driver. En general, se recomienda la lectura y el estudio de toda la información que Microsoft tiene en SQL Server respecto a ODBC.
Resaltar que las diferentes opciones para construir la cadena de conexión se encuentran en: Atributos de conexión y palabras clave de cadena de conexión y DSN compatibles y en Usar palabras clave de cadena de conexión con SQL Server Native Client.En Microsoft SQL Server ODBC DSN Configuration se encuentra la información sobre cómo configurar el driver ODBC para generar los ficheros DSN que se utilizarán en Excel To Database con conexiones ODBC.
Para las pruebas, se descarga e instala el ODBC Driver for SQL Server 18.4.1.1 (x64) en inglés, ya que al intentar instalar la versión en español se produce un error que indica que el Sistema Operativo no es compatible (Windows 10 22H2 en Español y SQL Server 2019 Express en español, ambos de 64 bits). ¿A alguien le extraña? A Microsoft no.
Por último, resaltar que las clases de .NET para manejar este tipo de conexiones, System.Data.Odbc, no se encuentran actualizadas y no manejan correctamente los tipos de datos devueltos por los controladores. Así, los tipos de datos de SQL Server "Time" y "DateTimeOffset" no son reconocidos por dichas clases. Un ejemplo de ello es el cargador que se suministra con SQL Server, "Asistente para la importación y exportación de SQL Server", que no funciona para dichos tipos de datos con conexiones ODBC. Sin embargo, con Excel To Database hemos realizado un gran esfuerzo para solventar este problema y, por tanto, se podrán cargar este tipo de datos.
-
Drivers OLE DB
En Controlador Microsoft OLE DB para SQL Server se indica que los controladores SQLOLEDB (Microsoft OLE DB para SQL Server) y SQLNCLI o SQLNCLI11 (SQL Server Native Client) están en desuso. El controlador recomendado es MSOLEDBSQL (Microsoft OLE DB Driver para SQL Server) o bien MSOLEDBSQL19 (Microsoft OLE DB Driver 19 para SQL Server). En Notas de la versión del controlador Microsoft OLE DB for SQL Server además de encontrar los enlaces a la descarga del controlador, se pueden consultar las características de cada versión del driver. En general, se recomienda la lectura y el estudio de toda la información que Microsoft tiene en SQL Server respecto a OLE DB.
Resaltar que las diferentes opciones para construir la cadena de conexión se encuentran en: Palabras clave de cadena de conexión de OLE DB DriverPara las pruebas, se descarga e instala el Controlador “Microsoft OLE DB Driver 19 for SQL Server” de 64 bits en español. El driver se puede descargar de: Descarga del controlador Microsoft OLE DB para SQL Server. Se ha de tener en cuenta que para la versión 19.3.5 se ha de obtener Microsoft Visual C++ Redistributable para Visual Studio 2015, 2017, 2019 y 2022 versión 14.34 como mínimo. Se puede descargar de: Descargas de las versiones más recientes admitidas de Microsoft Visual C++ Redistributable. Tenga en cuenta que necesita instalar los dritribuibles de 64 y 32 bits aunque sólo desee instalar el driver de 64 bits.
Al igual que ocurre con ODBC, las clases de .NET para manejar este tipo de conexiones, System.Data.OleDb, tampoco se encuentran actualizadas, y no manejan correctamente los tipos de datos devueltos por los controladores. Así, los tipos de datos de SQL Server "Date", "Time", "DateTimeOffset" y "DateTime2" son mapeados en .NET a cadenas de caracteres, mientras que los tipos de datos antiguos, "DateTime" y "SmallDateTime", son tratados como tipos de datos de fecha y hora.
-
Managed Drivers
Cómo se puede observar en Matriz de compatibilidad de características del controlador para Microsoft SQL Server en la primera tabla (controladores de .NET) existen dos controladores: Microsoft.Data.SqlClient (el más reciente) y System.Data.SqlClient (el tradicional).
En la actual versión de Excel To Database se utiliza el driver System.Data.SqlClient. En futuras versiones se planea que se también se pueda utilizar el driver Microsoft.Data.SqlClient, el cual es más adecuado.System.Data.SqlClient no incluye facilidades de resiliencia de la conexión, sin embargo, Excel To Database incluye código apropiado para manejar determinadas excepciones y habilitar reintentos en determinados casos.
La información asociada al driver System.Data.SqlClient se puede encontrar en: SQL Server y ADO.NET, y los diferentes atributos que se pueden utilizar en la cadena de conesión en: SqlConnection.ConnectionString Propiedad. Tenga en cuenta que la página en español de Microsoft ha traducido los atributos, así que deberá visitar la página en inglés para conocer las palabras clave correctas.
También conviene destacar que con los drivers administrados, Excel To Database utiliza la clase SqlBulkCopy durante la carga de datos para acelerar dicho proceso: SqlBulkCopy Clase. Mas información se puede encontrar en: Operaciones de copia masiva en SQL Server.
Aquí se usan transacciones, por lo que si se produce un error durante la carga de datos se deshará la transacción, no insertándose ningún dato. Con los proveedores de datos ODBC y OLE DB ocurre todo lo contrario: los datos se insertan fila a fila sin ninguna transacción, por lo que si se produce un error en una fila determinada, quedarán insertados todos los datos de las filas anteriores. Para estos proveedores de datos, Excel To Database persenta la opción Con Transacción.
Opciones Conexiones
Excel To Database impone determinadas propiedades a la cadena de conexión para que pueda funcionar correctamente:
* ".NET Data Provider for SQL Server" (Driver Administrado):
Persist Security Info=False;MultipleActiveResultSets=True;Application Name=\"Excel To Database\";Workstation ID=Nombre Máquina;ApplicationIntent=ReadWrite;Asynchronous Processing=True
* "OLE DB"
Persist Security Info=False;MARS Connection=True;Application Name="Excel To Database";Workstation ID=Nombre Máquina;Application Intent=ReadWrite;DataTypeCompatibility=80
* "ODBC"
MARS_Connection=Yes;app=Excel To Database;wsid=Nombre Máquina;ApplicationIntent=ReadWrite
Para ODBC Driver 18 for SQL Server se le añade la propiedad: longasmax=Yes
Además, tras el establecimiento de la cadena de conexión, para los Proveedores de Datos OLE DB y ".NET Data Provider for SQL Server", Excel To Database muestra en el Panel Resultados información relevante relativa a la eficiencia de las conexiones. Para ODBC no se muestra dicha información porque hasta el momento no se ha encontrado como establecer este parámetro en la cadena de conexión.
- PacketSize
Este parámetro es un gran desconocido, incluso para Microsoft, ya que no suele aportar mucha información sobre su utilidad e influencia en la eficiencia de las conexiones a la Base de Datos. Aquí, se muestra la información útil que se ha encontrado respecto a dicho parámetro, que es la misma que se muestra en el "Panel de Resultados":
CADENA DE CONEXIÓN
Parámetro: "PacketSize"
El valor de este parámetro influye tanto en el rendimiento de la red como en el de SQL Server.
Microsoft tiene varios artículos con recomendaciones para este parámetro:
http://microsoft-ssis.blogspot.com.es/2013/04/performance-best-practice-network.html
y https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.packetsize.aspx
En SQL Server se configura como se indica en:
https://msdn.microsoft.com/en-us/library/ms177437(v=sql.120).aspx
También se debería tener en cuenta el valor de MTU de la red, de forma que se aproveche totalmente la
capacidad de los paquetes de red evitando ineficiencias. Este valor se puede encontrar probando con
diferentes valores en el comando:
ping servername -f -l PacketSize
Ejemplo:
ping servername -f -l 1472
Respuesta desde servername: bytes=1472 tiempo=8ms TTL=120
ping servername -f -l 1473
Es necesario fragmentar el paquete pero se especificó DF.
NOTA: El comando ping tiene una sobrecarga de 28 bytes.
Así, se podría sustituir el valor por defecto de 8000 por 7500 (= (1472 + 28) * 5) y reconfigurar
SQL Server para admitir este tamaño de paquete. Aunque, según indica Microsoft, para operaciones
de "bulk copy" se recomienda que este valor sea el mayor posible.
También se recomienda revisar la Configuración de red para admitir tramas "jumbo mtu" con el fin aumentar
su rendimiento.
Ejemplo: https://en.wikipedia.org/wiki/Jumbo_frame
aunque la mayoría de las veces no es aconsejable habilitarlas.
Por último, destacar que este parámetro puede tener mucha influencia en VPNs o redes satelitales.
Se recomienda la lectura de: DBA Tactics for optimizing SQL Server Network Performance
Por último, tras la apretura de las conexiones a SQL Server, Excel To Database establece las siguientes opciones:
SET ANSI_DEFAULTS OFF;
SET ANSI_WARNINGS ON;
SET ANSI_PADDING ON;
SET ANSI_NULLS ON;
SET ARITHABORT ON;
SET QUOTED_IDENTIFIER ON;
SET CONCAT_NULL_YIELDS_NULL ON;
SET NUMERIC_ROUNDABORT OFF;
SET CURSOR_CLOSE_ON_COMMIT OFF;
SET IMPLICIT_TRANSACTIONS OFF;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
Libros, Bases de Datos
Las pruebas se van a realizar sobre Windows 10 64 bits, SQL Server 2019 Express con CU24 y Excel To Database de 64 bits compilada para .NET Framework 4.8 (System.Data.SqlClient). Como es de suponer, no se analizarán todos los drivers ni todas las opciones posibles, sino que se estudiarán los casos más representativos.
Las últimas versiones de los drivers por defecto encriptan las conexiones, y, además, necesitan un certificado de autenticación del servidor. Como ya se ha mencionado anteriormente, esta página no es ningún tratado de establecimiento de cadenas de conexión, así que, cuando aparezca alguno de los siguientes errores: Error "La cadena de certificados fue emitida por una autoridad que no es de confianza" después de actualizar las aplicaciones SNAC o Error "El certificado recibido del servidor remoto fue emitido por una entidad de certificación que no es de confianza" al conectarse a SQL Server. se resolverá con alguna de las soluciones indicadas en: https://learn.microsoft.com/es-es/troubleshoot/sql/database-engine/connect/certificate-chain-not-trusted?tabs=ole-db-driver-19#solutions (Use Encryption for Data=Optional/False; Encrypt=Optional/False; Trust Server Certificate=True).
-
Base de Datos SQL Server
Se va a utilizar una base de datos con intercalación "Modern_Spanish_100_CS_AS", un modelo de recuperación "Simple", sin cifrado y las opciones SET ANSI_PADDING ON, SET ANSI_WARNINGS ON, SET ARITHABORT ON, SET NUMERIC_ROUNDABORT OFF además de otras opciones.
Las dos últimas opciones tienen bastante importancia en el resultado de la carga de datos. En SET ARITHABORT (Transact-SQL) y SET NUMERIC_ROUNDABORT (Transact-SQL) se describe el comportamiento de dichas opciones.
Es de destacar que SQL Server tiene un auténtico caos con la combinación de estas opciones, y es muy complicado elegir la combinación mas conveniente.Se preparan 9 Configuraciones con las siguientes conexiones a la Bases de Datos: • Conexión con System.Data.SqlClient: Data Source=localhost;Initial Catalog=BASEDATOS;Integrated Security=True;Asynchronous Processing=True;MultipleActiveResultSets=True;Application Name=\"Excel To Database\";Workstation ID=Maquina • Conexión con MSOLEDBSQL19: Provider=MSOLEDBSQL19.1;Data Source=localhost;Persist Security Info=False;Integrated Security=SSPI;Initial Catalog=BASEDATOS;Application Name=\"Excel To Database\";Workstation ID=Maquina;Use Encryption for Data=Optional;MARS Connection=True;DataTypeCompatibility=80;Application Intent=ReadWrite • Conexión con MSOLEDBSQL: Provider=MSOLEDBSQL.1;Data Source=localhost;Persist Security Info=False;Integrated Security=SSPI;Initial Catalog=BASEDATOS;Application Name=\"Excel To Database\";Workstation ID=Maquina;MARS Connection=True;DataTypeCompatibility=80;Application Intent=ReadWrite • Conexión con SQLNCLI11: Provider=SQLNCLI11.1;Data Source=localhost;Persist Security Info=False;Integrated Security=SSPI;Initial Catalog=BASEDATOS;Application Name=\"Excel To Database\";Workstation ID=Maquina;MARS Connection=True;DataTypeCompatibility=80;Application Intent=ReadWrite • Conexión con SQLOLEDB: Provider=SQLOLEDB.1;Data Source=localhost;Persist Security Info=False;Integrated Security=SSPI;Initial Catalog=BASEDATOS;Application Name=\"Excel To Database\";Workstation ID=Maquina;mars connection=True;datatypecompatibility=80 • Conexión con ODBC Driver 18 for SQL Server: Driver={ODBC Driver 18 for SQL Server};server=localhost;trusted_connection=Yes;app=Excel To Database;wsid=Maquina;database=BASEDATOS;trustservercertificate=Yes;autotranslate=No;mars_connection=Yes • Conexión con ODBC Driver 17 for SQL Server: Driver={ODBC Driver 17 for SQL Server};server=localhost;trusted_connection=Yes;app=Excel To Database;wsid=Maquina;database=BASEDATOS;mars_connection=Yes • Conexión con ODBC SQL Server: Driver={SQL Server};server=localhost;trusted_connection=Yes;app=Excel To Database;wsid=Maquina;database=BASEDATOS;mars_connection=Yes • Conexión con ODBC SQL Server Native Client 11.0: Driver={SQL Server Native Client 11.0};server=localhost;trusted_connection=Yes;app=Excel To Database;wsid=Maquina;database=BASEDATOS;mars_connection=Yes Las conexiones ODBC utilizan los siguientes archivos DSN: ODBC Driver 18 SQL Server.dsn [ODBC] DRIVER=ODBC Driver 18 for SQL Server AutoTranslate=No TrustServerCertificate=Yes LANGUAGE=Español DATABASE=BASEDATOS WSID=Maquina APP=Excel To Database Trusted_Connection=Yes SERVER=localhost ODBC Driver 17 SQL Server.dsn [ODBC] DRIVER=ODBC Driver 17 for SQL Server TrustServerCertificate=No DATABASE=BASEDATOS WSID=Maquina APP=Sistema operativo Microsoft® Windows® Trusted_Connection=Yes SERVER=localhost ODBC Driver Native Client 11 SQL Server.dsn [ODBC] DRIVER=SQL Server Native Client 11.0 DATABASE=BASEDATOS WSID=Maquina APP=Sistema operativo Microsoft® Windows® Trusted_Connection=Yes SERVER=localhost ODBC Driver SQL Server.dsn [ODBC] DRIVER=SQL Server UID=Usuario DATABASE=BASEDATOS WSID=Maquina APP=Sistema operativo Microsoft® Windows® Trusted_Connection=Yes SERVER=localhost -
Libro Excel
Para las pruebas realizadas se ha utilizado un Libro Excel cuyas Hojas se irán mostrando en imágenes a lo largo del capítulo.
Destacar que para las pruebas no se ha incluido ninguna celda con error, por lo que la opción Sin Valores Error no va a ser utilizada.
Los datos han sido preparados de forma que permitan comprobar el funcionamiento de la carga de datos. No son una batería de pruebas exhaustivas, por lo que se puede deducir que la carga de datos no tiene garantía de que se produzca como el usuario pudiese esperar ni como se describe en esta página.
Puede descargar los ficheros de prueba desde aquí: Descarga de Ejemplos
Pruebas SQL Server: Números de "Punto Flotante"
Para mostrar el comportamiento de los drivers con este tipo de datos de SQL Server se utiliza la tabla cuyo script de creación es el mostrado a continuación y la Hoja Excel mostrada en la figura siguiente:
DROP TABLE IF EXISTS [dbo].[Tabla Numeros];
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Tabla Numeros](
[Real-float(24)] [real] NULL, --4 bytes. 7 dígitos. Precisión Simple
[Float-float(53)] [float] NULL, --8 bytes. 15 dígitos. Precisión Doble
[Provider] [varchar](10) COLLATE Modern_Spanish_100_CS_AS NOT NULL,
[Driver] [varchar](50) COLLATE Modern_Spanish_100_CS_AS NOT NULL,
[Identidad] [int] IDENTITY(1,1) NOT NULL,
PRIMARY KEY CLUSTERED
(
[Identidad] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
Aunque en SQL Server para "float" se puede ¿especificar la precisión?, realmente sólo admite 2 precisiones: Si 1<=n<=24, n es tratado como 24. Si 25<=n<=53, n es tratado como 53.
Así, los campos de tipo "real" tienen una precisión de 7 dígitos y los de tipo "float" poseen una precisión de 15 dígitos.
SQL Server: Hoja Excel para Números de "Punto Flotante"
Hay que destacar que el formato de celdas en la Hoja Excel es "Texto", "Número" o "Científica". Es "Texto" para aquellos casos en que se supera la precisión de Excel. En estos casos se utiliza como "Símbolo decimal" el punto ".", ya que es el separador que utiliza Excel To Database para convertir los textos a números.
Todos los proveedores de datos (.NET, OLE DB y ODBC) redondean el dato cuando éste excede la precisión del campo. El redondeo utilizado es del tipo MidpointRounding.AwayFromZero. Ver MidpointRounding Enumeración.
Se han puesto a prueba las máximas capacidades de Excel, SQL Server y de .NET, obteniéndose los resultados esperados con todos proveedores de datos. Se ha de tener en cuenta que tanto SQL Server como .NET tienen una precisión de 7 dígitos significativos para Single y 15 para Double.
Dada la imprecisión de los números de punto flotante, se producen los siguientes cambios en los datos debido a dicha imprecisión: "B6", "B10", "A15:A16", "A19:B21". Por otr lado, SQL Server realiza redondeos en las celdas: "B4", "B6", "B7:B9", "B10", "A12:A15" y "A19:B20"
Las celdas "B17" y "A18" superan la capacidad del campo y por ello los valores son sustiuidos por el indicando en "Valor Defecto" del "Panel de Mapeos".
Pruebas SQL Server: Fechas
Como complemento a las pruebas aquí realizadas, se recomienda la lectura del apartado dedicado a las fechas en MS Access: Pruebas MS Access: Fechas.
Excel To Database realiza el siguiente mapeo de tipos de datos de SQL Server a tipos de datos de .NET:
- Proveedor de Datos .NET (System.Data.SqlClient): date, smalldatetime, datetime, datetime2 -> String, time -> TimeSpan y datetimeoffset -> DateTimeOffset.
- Proveedor de Datos OLE DB (System.Data.OleDb) y ODBC (System.Data.Odbc): date, smalldatetime, datetime, datetime2, time y datetimeoffset -> String
ODBC (System.Data.Odbc) no reconoce los tipos de datos "Time" y "DateTimeOffset" de SQL Server. Cuando se intenta leer los campos de una tabla que contiene este tipo de datos se produce el error mostrado a continuación. Sin embargo, en Excel To Database se ha realizado un gran esfuerzo para que no existan problemas con dichos tipos de datos.
{
"$id": "1",
"$type": "System.ArgumentException, mscorlib",
"Message": "Tipo SQL desconocido - SS_TIME_EX.",
"ParamName": null,
"Data": {
"$type": "System.Collections.ListDictionaryInternal, mscorlib"
},
"InnerException": null,
"HelpLink": null,
"Source": "System.Data",
"HResult": -2147024809
}
Los Tipos de Datos:
-155, que se correspode con campos de tipo DateTimeOffset
-154 (SS_TIME_EX) que se corresponde con campos de tipo Time
No son reconocidos por el Proveedor de Datos ODBC para SQL Server.
A pesar de todos los esfuerzos, con el driver ODBC {SQL Server} (muy obsoleto) se produce un error al intentar insertar un NULL en un campo de tipo Time.
Fila: 1
Comando: INSERT INTO [dbo].[Tabla Fechas] ([Time], [Driver], [Provider]) VALUES (?, ?, ?)
Comando Select: SELECT [Time], [Driver], [Provider] FROM [dbo].[Tabla Fechas]
Excepción:
{
"$id": "1",
"$type": "System.Data.Odbc.OdbcException, System.Data",
"Errors": {
"$type": "System.Data.Odbc.OdbcErrorCollection, System.Data",
"$values": [
{
"$id": "2",
"$type": "System.Data.Odbc.OdbcError, System.Data",
"Message": "[Microsoft][ODBC SQL Server Driver]Característica opcional no implementada",
"SQLState": "HYC00",
"NativeError": 0,
"Source": "SQLSRV32.DLL"
}
]
},
"Source": "SQLSRV32.DLL",
"ErrorCode": -2146232009,
"Message": "ERROR [HYC00] [Microsoft][ODBC SQL Server Driver]Característica opcional no implementada",
"Data": {
"$type": "System.Collections.ListDictionaryInternal, mscorlib"
},
"InnerException": null,
"HelpLink": null,
"HResult": -2146232009
}
Columna: Time Valor:
Columna: Driver Valor: {SQL Server}
Columna: Provider Valor: ODBC
Se ha producido una excepción al intentar cargar la Tabla 'dbo.Tabla Fechas'. Error en la Fila: 1
Query que indica las columnas utilizadas de la Tabla:
SELECT [Time], [Driver], [Provider] FROM [dbo].[Tabla Fechas]
{
"$id": "1",
"$type": "System.Data.Odbc.OdbcException, System.Data",
"Errors": {
"$type": "System.Data.Odbc.OdbcErrorCollection, System.Data",
"$values": [
{
"$id": "2",
"$type": "System.Data.Odbc.OdbcError, System.Data",
"Message": "[Microsoft][ODBC SQL Server Driver]Característica opcional no implementada",
"SQLState": "HYC00",
"NativeError": 0,
"Source": "SQLSRV32.DLL"
}
]
},
"Source": "SQLSRV32.DLL",
"ErrorCode": -2146232009,
"Message": "ERROR [HYC00] [Microsoft][ODBC SQL Server Driver]Característica opcional no implementada",
"Data": {
"$type": "System.Collections.ListDictionaryInternal, mscorlib"
},
"InnerException": null,
"HelpLink": null,
"HResult": -2146232009
}
Así, para las pruebas, se utilizan la tabla y Hoja Excel mostradas a continuación:
DROP TABLE IF EXISTS [dbo].[Tabla Fechas];
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Tabla Fechas](
[Date] [date] NULL,
[SmallDateTime] [smalldatetime] NULL,
[DateTime] [datetime] NULL,
[DateTime2] [datetime2] NULL,
[Time] [time](2) NULL, --ODBC: Tipo SQL desconocido - SS_TIME_EX.
[DateTimeOffset] [datetimeoffset] NULL, --ODBC: Tipo SQL desconocido - -155.
[Provider] [varchar](10) COLLATE Modern_Spanish_100_CS_AS NOT NULL,
[Driver] [varchar](50) COLLATE Modern_Spanish_100_CS_AS NOT NULL,
[Identidad] [int] IDENTITY(1,1) NOT NULL,
PRIMARY KEY CLUSTERED
(
[Identidad] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
SQL Server: Hoja Excel para Fechas
-
La influencia del Formato de Celda.
Excel To Database utiliza el formato de celda para comprender el tipo de dato que contiene cada celda. Esto hace que determinados datos alamcenados en Excel que poseen Fecha y/o Hora no puedan ser almacenados en determinados tipos de datos de SQL Server.
- Celdas con formato de fecha:
Estos datos son interpretados por Excel To Database como sólo fecha, y por tanto no puede ser almacenados en campos que almacenan sólo datos de hora: "F2", "F7", "F11", "F16" y "F21".
Para el resto de celdas de la columna "F" (campo Time de la tabla) se extrae el dato de la hora y es lo que se almacena en este campo.
Para que la carga de datos funcione correctamente se ha de marcar la opción "Sin errores de Conversión" para que esos datos puedan ser sustituidos por el valor por defecto indicado en el "Panel de Mapeos". - Celdas con formato de hora:
Estos datos son interpretados por Excel To Database como sólo hora, y por tanto no puede ser almacenados en campos que requieren de una fecha: "A5:E6", "A8:E8", "A10:E10", "A14:E15", "A17:E17".
Para que la carga de datos funcione correctamente se ha de marcar la opción "Sin errores de Conversión" para que esos datos puedan ser sustituidos por el valor por defecto indicado en el "Panel de Mapeos". - Celdas con formato de fecha y hora:
Dependiendo del tipo de datos del campo, Excel To Database extrae la información adecuada (sólo fecha, sólo hora, fecha y hora) y lo almacena en el campo.
Celdas con formato de fecha: Celda: F2, Valor: 1910/10/15, Tabla: dbo.Tabla Fechas, Columna: Time El tipo de datos 'time' no puede almacenar fechas Celda: F2, Valor: 15/10/1910, Tabla: dbo.Tabla Fechas, Columna: Time La conversión especificada no es válida.No se puede almacenar <15/10/1910 23:59:59> en la columna Time. El tipo esperado es TimeSpan. Celda: F7, Valor: 1910/10/15, Tabla: dbo.Tabla Fechas, Columna: Time El tipo de datos 'time' no puede almacenar fechas Celda: F7, Valor: 15/10/1910, Tabla: dbo.Tabla Fechas, Columna: Time La conversión especificada no es válida.No se puede almacenar <15/10/1910 23:59:59> en la columna Time. El tipo esperado es TimeSpan. Celda: F11, Valor: 1910/10/15, Tabla: dbo.Tabla Fechas, Columna: Time El tipo de datos 'time' no puede almacenar fechas Celda: F11, Valor: 15/10/1910, Tabla: dbo.Tabla Fechas, Columna: Time La conversión especificada no es válida.No se puede almacenar <15/10/1910 23:59:59> en la columna Time. El tipo esperado es TimeSpan. Celda: F16, Valor: 1910/10/15, Tabla: dbo.Tabla Fechas, Columna: Time El tipo de datos 'time' no puede almacenar fechas Celda: F16, Valor: 15/10/1910, Tabla: dbo.Tabla Fechas, Columna: Time La conversión especificada no es válida.No se puede almacenar <15/10/1910 23:59:59> en la columna Time. El tipo esperado es TimeSpan. Celda: F21, Valor: 9999-12-31 23:59:59.9999999 +00:00, Tabla: dbo.Tabla Fechas, Columna: Time El tipo de datos 'time' no puede almacenar fechas Celda: F21, Valor: 9999-12-31 23:59:59.9999999 +00:00, Tabla: dbo.Tabla Fechas, Columna: Time No se reconoce la cadena como un valor de TimeSpan válido.No se puede almacenar <9999-12-31 23:59:59.9999999 +00:00> en la columna Time. El tipo esperado es TimeSpan. Celdas con formato de hora: Celda: A5, Valor: 23:59:59.4000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: Date El dato de tiempo 23:59:59.4000000 +02:00 no puede almacenarse en un campo de tipo date Celda: B5, Valor: 23:59:59.0000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: SmallDateTime El dato de tiempo 23:59:59.0000000 +02:00 no puede almacenarse en un campo de tipo smalldatetime Celda: C5, Valor: 23:59:59.4000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime El dato de tiempo 23:59:59.4000000 +02:00 no puede almacenarse en un campo de tipo datetime Celda: D5, Valor: 23:59:59.4000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime2 El dato de tiempo 23:59:59.4000000 +02:00 no puede almacenarse en un campo de tipo datetime2 Celda: E5, Valor: 23:59:59.4000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset El dato de tiempo 23:59:59.4000000 +02:00 no puede almacenarse en un campo de tipo datetimeoffset Celda: E5, Valor: 23:59:59, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset La conversión especificada no es válida.No se puede almacenar <23:59:59> en la columna DateTimeOffset. El tipo esperado es DateTimeOffset. Celda: A6, Valor: 23:59:59.0000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: Date El dato de tiempo 23:59:59.0000000 +02:00 no puede almacenarse en un campo de tipo date Celda: B6, Valor: 23:59:59.0000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: SmallDateTime El dato de tiempo 23:59:59.0000000 +02:00 no puede almacenarse en un campo de tipo smalldatetime Celda: C6, Valor: 23:59:59.0000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime El dato de tiempo 23:59:59.0000000 +02:00 no puede almacenarse en un campo de tipo datetime Celda: D6, Valor: 23:59:59.0000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime2 El dato de tiempo 23:59:59.0000000 +02:00 no puede almacenarse en un campo de tipo datetime2 Celda: E6, Valor: 23:59:59.0000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset El dato de tiempo 23:59:59.0000000 +02:00 no puede almacenarse en un campo de tipo datetimeoffset Celda: E6, Valor: 23:59:59.000, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset La conversión especificada no es válida.No se puede almacenar <23:59:59.000> en la columna DateTimeOffset. El tipo esperado es DateTimeOffset. Celda: A8, Valor: 23:59:59.4000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: Date El dato de tiempo 23:59:59.4000000 +02:00 no puede almacenarse en un campo de tipo date Celda: B8, Valor: 23:59:59.4000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: SmallDateTime El dato de tiempo 23:59:59.4000000 +02:00 no puede almacenarse en un campo de tipo smalldatetime Celda: C8, Valor: 23:59:59.4000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime El dato de tiempo 23:59:59.4000000 +02:00 no puede almacenarse en un campo de tipo datetime Celda: D8, Valor: 23:59:59.4000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime2 El dato de tiempo 23:59:59.4000000 +02:00 no puede almacenarse en un campo de tipo datetime2 Celda: E8, Valor: 23:59:59.4000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset El dato de tiempo 23:59:59.4000000 +02:00 no puede almacenarse en un campo de tipo datetimeoffset Celda: E8, Valor: 23:59:59, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset La conversión especificada no es válida.No se puede almacenar <23:59:59> en la columna DateTimeOffset. El tipo esperado es DateTimeOffset. Celda: A10, Valor: 23:59:59, Tabla: dbo.Tabla Fechas, Columna: Date El contenido de la Celda no ha podido convertirse al tipo de datos date Celda: B10, Valor: 23:59:59, Tabla: dbo.Tabla Fechas, Columna: SmallDateTime El contenido de la Celda no ha podido convertirse al tipo de datos smalldatetime Celda: C10, Valor: 23:59:59, Tabla: dbo.Tabla Fechas, Columna: DateTime El contenido de la Celda no ha podido convertirse al tipo de datos datetime Celda: D10, Valor: 23:59:59, Tabla: dbo.Tabla Fechas, Columna: DateTime2 El contenido de la Celda no ha podido convertirse al tipo de datos datetime2 Celda: E10, Valor: 23:59:59, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset El contenido de la Celda no ha podido convertirse al tipo de datos datetimeoffset Celda: E10, Valor: 23:59:59, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset La conversión especificada no es válida.No se puede almacenar <23:59:59> en la columna DateTimeOffset. El tipo esperado es DateTimeOffset. Celda: A14, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: Date El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo date Celda: B14, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: SmallDateTime El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo smalldatetime Celda: C14, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo datetime Celda: D14, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime2 El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo datetime2 Celda: E14, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo datetimeoffset Celda: E14, Valor: 23:59:59, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset La conversión especificada no es válida.No se puede almacenar <23:59:59> en la columna DateTimeOffset. El tipo esperado es DateTimeOffset. Celda: A15, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: Date El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo date Celda: B15, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: SmallDateTime El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo smalldatetime Celda: C15, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo datetime Celda: D15, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime2 El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo datetime2 Celda: E15, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo datetimeoffset Celda: E15, Valor: 23:59:59.000, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset La conversión especificada no es válida.No se puede almacenar <23:59:59.000> en la columna DateTimeOffset. El tipo esperado es DateTimeOffset. Celda: A17, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: Date El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo date Celda: B17, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: SmallDateTime El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo smalldatetime Celda: C17, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo datetime Celda: D17, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime2 El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo datetime2 Celda: E17, Valor: 23:59:59.5000000 +02:00, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset El dato de tiempo 23:59:59.5000000 +02:00 no puede almacenarse en un campo de tipo datetimeoffset Celda: E17, Valor: 23:59:59, Tabla: dbo.Tabla Fechas, Columna: DateTimeOffset La conversión especificada no es válida.No se puede almacenar <23:59:59> en la columna DateTimeOffset. El tipo esperado es DateTimeOffset. - Celdas con formato de fecha:
-
Límites de fechas en los campos
Dependiendo del tipo de datos del campo, éste admite un límite de fechas u otro. Excel To Database realiza los chequeos pertinentes y avisa al usuario en caso de que se excedan los límites del campo.
Celda: B20, Valor: 0200-10-15T23:59:59.0000000+02:00, Tabla: dbo.Tabla Fechas, Columna: SmallDateTime La fecha debe estar comprendida entre 1900-01-01T00:00:00.0000000Z y 2079-06-06T23:59:29.9980000Z Celda: C20, Valor: 0200-10-15T23:59:59.0000000+02:00, Tabla: dbo.Tabla Fechas, Columna: DateTime La fecha debe estar comprendida entre 1753-01-01T00:00:00.0000000Z y 9999-12-31T23:59:59.9970000Z Celda: B21, Valor: 9999-12-31T23:59:59.9990000, Tabla: dbo.Tabla Fechas, Columna: SmallDateTime La fecha debe estar comprendida entre 1900-01-01T00:00:00.0000000Z y 2079-06-06T23:59:29.9980000Z Celda: C21, Valor: 9999-12-31T23:59:59.9990000, Tabla: dbo.Tabla Fechas, Columna: DateTime La fecha debe estar comprendida entre 1753-01-01T00:00:00.0000000Z y 9999-12-31T23:59:59.9970000Z Celda: B22, Valor: 9999-12-31T23:59:59.9990000, Tabla: dbo.Tabla Fechas, Columna: SmallDateTime La fecha debe estar comprendida entre 1900-01-01T00:00:00.0000000Z y 2079-06-06T23:59:29.9980000Z Celda: C22, Valor: 9999-12-31T23:59:59.9990000, Tabla: dbo.Tabla Fechas, Columna: DateTime La fecha debe estar comprendida entre 1753-01-01T00:00:00.0000000Z y 9999-12-31T23:59:59.9970000ZDestacar que al contrario de lo que sucedía con el proveedor de datos ODBC para MS Access (ODBC y el chovinismo anglosajón: 1753) con SQL Server no existe este problema. Aunque si lo ponen de manifiesto en la capacidad de los campos de tipo DateTime.
-
Datos de Tiempo: Precisión, Redondeos y Recortes.
Dado que se transmiten a la base de datos los datos de Excel como cadenas de caracteres, son los proveedores de datos y la propia base de datos quienes se encargan de realizar los recortes y redondeos oportunos.
Es por ello que no se realizan pruebas exahustivas, sino que se recomienda la lectura detallada de cada uno de los tipos de datos.
Como ejemplos, aquí se detallan alguno de los redondeos mas raros:En datetime (Transact-SQL) se indica que la precisión para este tipo de datos es: "Se redondea en incrementos de 0.000, 0.003 o 0.007 segundos", lo cual concuerda con los datos cargados que contienen milisegundos.
En smalldatetime (Transact-SQL) se indica que la precisión para este tipo de datos es: "Un minuto". SQL Server hace que los datos con segundos y/o milisegundos sean redondeados.
Como es de suponer, todos los drivers recortan la hora cuando un dato se inserta en un campo de tipo Date.
Para el Proveedor de Datos OLE DB, todos los drivers se comportan de la misma forma excepto para el tipo de datos "SmallDateTime". El driver SQLOLEDB.1 redondea el dato, mientras que el resto de los drivers recortan las fracciones de segundo.
El Managed Driver (System.Data.SqlClient) redondea los datos que se insertan en un campo de tipo "SmallDateTime". Es decir, tiene el mismo comportamiento que el driver SQLOLEDB.1
Los drivers ODBC tienen un comportamiento diferente para los campos de tipo "Time". Todos los drivers recortan la parte fraccionaria de los segundos para este tipo de datos. Claro, a excepción del driver ODBC {SQL Server}, que tiene problemas con este tipo de datos.
Preguntas Frecuentes
¿Cuánto tarda en cargar un millón de filas en SQL Server?
Con Excel To Database, un millón de filas se procesan en aproximadamente 60 segundos, dependiendo de la cantidad de columnas y el ancho de los datos.
¿Qué pasa si el driver de SQL Server lanza un error desconocido?
Excel To Database está diseñado tras múltiples pruebas para capturar la excepción nativa y traducirla a un mensaje comprensible, facilitando la corrección del dato en el Excel.
¿Cómo ayuda el software a identificar errores que el driver de SQL oculta?
Tras nuestras pruebas de bugs, hemos desarrollado un sistema de captura de excepciones que identifica el registro exacto del error, permitiendo una depuración mucho más rápida que con los métodos de inserción estándar.
¿Qué información incluye el log JSON de Excel To Database?
Incluye el código de error del driver, el Status Code específico del motor de base de datos, el mensaje descriptivo y la fuente de la excepción, facilitando una depuración inmediata.