SQL-Server: Usar Try…Catch en una transacción.

Desde SQL-Server 2008 es posible utilizar la instrucción Try…Catch. Estas instrucciones nos permiten implementar un mecanismo de control de errores: metemos un bloque de código dentro de la instrucción Try, para intentar ejecutarlo, y dentro de Catch metemos las instrucciones para controlar la respuesta en caso de error.

La sintaxis básica de un Try…Catch en SQL-Server es la siguiente:

BEGIN TRY  
     ---Bloque de código 
END TRY  
BEGIN CATCH  
     --Código en caso de error. 
END CATCH  

Cuando realizamos una transacción podemos exprimir al 100% la instrucción Try…Catch. La idea es la siguiente: Comenzamos la transacción, intentamos una acción en un bloque Try. En caso de que falle mostramos el error y ejecutamos un rollback para anular la transacción. En caso de éxito confirmamos la ejecución de la transacción.

Veamos un código de ejemplo:

BEGIN TRANSACTION;  --Comienza

BEGIN TRY  --Aquí empieza el try
    Insert into Ejemplo(Id,Nombre) values(22,'Manuel');
    Delete From Espera Where Nombre = 'Manuel' 
--Intentaremos esas dos acciones
END TRY  
BEGIN CATCH  
--El primer paso en el Catch
--Será recoger y mostrar
--Todos los errores
    SELECT   
        ERROR_NUMBER() AS ErrorNumber  
        ,ERROR_SEVERITY() AS ErrorSeverity  
        ,ERROR_STATE() AS ErrorState  
        ,ERROR_PROCEDURE() AS ErrorProcedure  
        ,ERROR_LINE() AS ErrorLine  
        ,ERROR_MESSAGE() AS ErrorMessage;  
--Si hay transacción abierta
--Hacemos un rollback sobre ella
--Para anularla
    IF @@TRANCOUNT > 0  
        ROLLBACK TRANSACTION;  
END CATCH;  
--Fuera del bloque vamos a
--comprobar que haya transacción abierta.
--Si la hay es que no tuvo que ir por el CATCH
--Por tanto confirmamos.
IF @@TRANCOUNT > 0  
    COMMIT TRANSACTION;  
GO  

SQL-Server: Intercambiar valores 0 y 1 en un Update

Vamos con una cuestión que seguro que nos hemos encontrado más de una vez: Tenemos un campo en una base de datos donde almacenamos un valor verdadero o falso y tenemos que realizar un Update para cambiar dicho estado. ¿Cómo hacemos para modificarlo con el menor costo posible? Te doy un par de soluciones, todas válidas para SQL-Server desde la versión 2008 hasta la 2017 (y supongo que seguirán valiendo en las posteriores):

Para la primera vamos a usar la operación del OR exclusivo bit a bit:

Update TablaEjemplo SET ValorVF = Convert(Bit,ValorVF ^ 1)

Otra opción lógica es usar el operador lógico de negación para invertir el valor:

Update TablaEjemplo SET ValorVF = Convert(Bit,~ ValorVF)

¿Y qué pasa si la tabla no está bien diseñada y en lugar de almacenar un valor bit estamos almacenando un entero? Si no podemos cambiar el diseño de la tabla todavía podemos recurrir a la primera solución, el OR exclusivo bit a bit, pero sin realizar la conversión a tipo bit:

Update TablaEjemplo SET ValorVF = ValorVF ^ 1

Y además tenemos otra opción, con una simple resta y con la función ABS(), que nos devuelve el valor absoluto del parámetro que recibe:

Update TablaEjemplo SET ValorVF = ABS(ValorVF - 1)

Evitar el mensaje de error «No está permitido guardar cambios» cuando intenta modificar una tabla en SQL Server

A veces al realizar ciertas modificaciones sobre una tabla, como cambiar el tipo de datos o la precisión de una columna, el orden de la mismas o al agregar una nueva recibimos un mensaje de error de SQL-Server que nos dice que «No está permitido guardar cambios porque no se permiten cambios que obliguen a crear tablas de nuevo«. ¿Hay alguna forma de modificar esto y permitir el cambio? Sí, hay dos opciones.

La primera es no utilizar la interfaz gráfica para hacer la modificación sino usar instrucciones SQL. Si por ejemplo queremos cambiar la precisión y permitir valores nulos en una columna de la tabla podríamos hacerlo así:

alter table Clientes alter column ObservacionesCliente nvarchar(500) NULL

Otra solución es desactivar la opción de Impedir guardar cambios que requieren volver a crear tablas en el entorno gráfico. En el menú Herramientas, hacemos click en Opciones y, dentro de ese menú, vamos al submenú Diseñadores. Allí desactivamos la opción Impedir guardar cambios que requieren volver a crear tablas y, a continuación, hacemos click en Aceptar para guardar los datos. Os dejo una captura de dicho menú:

SQL-Server Opciones Diseñadores

SQL-Server: Calcular el descuento compuesto

Tras un mes de parón por temas varios volvemos con energía al blog. Vamos a dar por finalizado el capítulo dedicado a los descuentos y la aplicación de sus fórmulas en consultas de SQL-Server mirando el que nos queda, el descuento compuesto. Del descuento racional y del comercial ya hablamos en entradas pasadas.

El descuento compuesto es la operación inversa de la capitalización compuesta: si descontamos un capital utilizando el descuento compuesto, y el importe obtenido lo capitalizamos (capitalización compuesta) aplicando el mismo tipo de interés y plazo, obtenemos el importe inicial.

La fórmula para obtener el descuento sería la siguiente:

D = C0 * (1 – (1 + d) ^ -t )

Siendo C0 es el capital inicial en el momento t=0, d la tasa de descuento que se aplicará y t el tiempo que dura la inversión.

Para obtener el capital final la fórmula sería:

Cf = C0 * ( 1 + d ) ^ -t

Siendo C0 es el capital inicial en el momento t=0, d la tasa de descuento que se aplicará y t el tiempo que dura la inversión.

Entonces ¿cómo llevamos esto a una consulta SQL? Supongamos que, como en el ejemplo anterior, tenemos una tabla llamada TablaCreditos con los campos Valor (con el capital inicial en formato money), Descuento (en formato Numeric(5,2)) y Tiempo (en formato int). La consulta sería:

--Descuento
Select Valor * (1.00-POWER((1.00+Descuento),Tiempo)) as DescuentoCompuesto from TablaCreditos
--Capital final
Select Valor * POWER((1.00+Descuento),Tiempo) as CapitalFinal from TablaCreditos

SQL-Server: Calcular el descuento racional

Siguiendo con la matemática financiera el otro día veíamos cómo calcular el descuento comercial en una consulta de SQL. Ahora vamos con otro tipo de descuento, el descuento racional.

El descuento racional se trata, al igual que el comercial, de una forma de descuento simple, pero tiene principalmente una diferencia con el descuento comercial: Su cálculo se efectúa a partir de la diferencia entre el monto a pagar o valor nominal y su valor actual, por lo que no se toma el valor nominal sino el valor real.Es decir, el descuento racional será igual a la cantidad a pagar menos el valor actual del capital. Es el descuento de su respectivo interés aplicado al valor nominal de un valor, calculado a partir de la tasa de interés nominal vencida o con la tasa de interés efectiva vencida.

La fórmula para obtener el descuento sería la siguiente:

D = ( C0 * d * t ) / (1 + d * t)

Siendo C0 es el capital inicial en el momento t=0, d la tasa de descuento que se aplicará y t el tiempo que dura la inversión. Por ejemplo, para 20000 euros a un 15% anual la fórmula sería:

D=(20000*0.15*1)/(1+0.15*1)

Entonces ¿cómo llevamos esto a una consulta SQL? Supongamos que, como en el ejemplo anterior, tenemos una tabla llamada TablaCreditos con los campos Valor (con el capital inicial en formato money), Descuento (en formato Numeric(5,2)) y Tiempo (en formato int). La consulta sería:

Select (Valor*(Descuento/100.00)*CONVERT(numeric(4,2),Tiempo))/(1.00+(Descuento/100.00)*CONVERT(numeric(4,2),Tiempo)) as DescuentoRacional from TablaCreditos

SQL-Server: Calcular el descuento comercial

La operación financiera de descuento es la inversa a la de capitalización (ya vimos en el pasado la capitalización simple y la compuesta). En este caso se calcula el capital equivalente en un momento anterior de un importe futuro.

Mientras que con la fórmula de la capitalización se calculan unos intereses que se añaden al importe principal, compensando el aplazamiento en el tiempo de su disposición, en las reglas de descuento se hace lo contrario: se calculan los intereses que hay que pagar por adelantar la disposición del capital.

La fórmula para obtener el descuento sería la siguiente:

D= N*d*t

Siendo D el descuento efectuado, N el valor nominal del crédito, d la tasa de descuento y t el tiempo. Por ejemplo, para 20000 euros a un 15% anual la fórmula sería:

D = 20000*0.15*1

Entonces ¿cómo llevamos esto a una consulta SQL? Supongamos que tenemos una tabla llamada TablaCreditos con los campos Valor (con el valor nominal en formato money), Descuento (en formato Numeric(5,2)) y Tiempo (en formato int). La consulta sería:

Select Valor*(Descuento/100.00)*CONVERT(numeric(4,2),Tiempo) as Descuento from TablaCreditos

Baloncesto y estadística: Consulta SQL para calcular el porcentaje de robos de un jugador

Seguimos con el tema de la estadística baloncestística avanzada. Ya vimos cómo se calcula el PIE,también los porcentajes de tiro avanzado y real y hubo otra entrada sobre estadísticas de asistencias. Hoy vamos con el porcentaje de robos.

¿Qué nos indica este porcentaje? Pues la cantida de balones que un jugador recupera, pero teniendo en cuenta los minutos que juega y el ritmo de juego del rival. Aquí es importante matizar ¿qué entendemos por robo? Pues cuando un jugador, por medio de una acción defensiva legal, logra que el rival pierda la posesión del balón ganándola a su vez para su equipo. Es decir, que no cuenta ni cuando se recuperan balones sueltos ni cuando se intercepta el balón cambiando su trayectoria pero sin recuperar la posesión. Ojo, ahora la NBA también recoge eso en sus estadísticas oficiales avanzadas como «Loose ball recoverd» y «Deflections«. Peor lo que ahora nos ocupa es el tema de los robos.

¿La fórmula? Es la siguiente:

100 * Robos del Jugador * Minutos totales de Partido / Minutos jugados por el jugador * Posesiones del equipo rival.

En una base de datos donde tuviéramos los campos Robos,MinutosPartido,MinutosJugador y PosesionesRival la consulta sería algo así

Select 100.00*Convert(Numeric(4,2),Robos)*Convert(Numeric(4,2),MinutosPartido)/Convert(Numeric(4,2),MinutosJugador)*Convert(Numeric(4,2),PosesionesRival) as StealPcnt

¿Limitaciones de esta estadística? Pues que recoge solo el porcentaje de éxitos, al igual que el total de robos, por lo que un jugador puede quedar sobrerrepresentado en la misma, pareciendo mejor defensor de lo que es. Gente como Monta Ellis o, en Europa, Bo McCalebb son jugadores con manos rápidas que por su estilo defensivo consiguen muchos robos pero que en el global no son grandes defensores.

Baloncesto y estadística: Consulta SQL para calcular los ratios de asistencias de un jugador

Seguimos con el tema de la estadística baloncestística avanzada. Ya vimos cómo se calcula el PIE y también los porcentajes de tiro avanzado y real, así que hoy vamos con los ratios de asistencias.

En este caso tenemos dos fórmulas distintas, ya que por un lado tenemos el Ratio de Asistencias de Hollinger (hAST%) y por otro el de Pomeroy (pAST%).

El ratio de Hollinger se calcula respecto al número de balones que terminan en manos del jugador mientras que el de Pomeroy lo calcula respecto al tiempo que el jugador está en la pista y el número de posesiones.

La fórmula de Hollinger sería la siguiente:

ASISTENCIAS*100 / (TIROS DE CAMPO INTENTADOS POR EL JUGADOR+ 0.44 * TIROS LIBRES INTENTADOS POR EL JUGADOR + ASISTENCIAS + PÉRDIDAS)

Por su parte la de Pomeroy sería esta:

ASISTENCIAS*100 / (((MINUTOS JUGADOS / (MINUTOS TOTALES DEL EQUIPO / 5)) * TIROS DE CAMPO INTENTADOS POR EL EQUIPO ) – TIROS DE CAMPO INTENTADOS POR EL JUGADOR)

Entonces suponiendo que tenemos una tabla Estadisticas con los campos: Asistencias, Tiros, TirosLibres, Perdidas con los valores correspondientes, la fórmula de Hollinger la sacaríamos tal que así:

Select Convert(Numeric(5,2),Asistencias)*100.00  / (Convert(Numeric(5,2),Tiros)+ 0.44 * Convert(Numeric(5,2),TirosLibres) + Convert(Numeric(5,2),Asistencias) + Convert(Numeric(5,2),Perdidas)) as hAST from Estadisticas

Para la de Pomeroy necesitaríamos una tabla com los campos Asistencias,Minutos,MinutosEquipo,TirosEquipo y Tiros:

Select Convert(Numeric(5,2),Asistencias)*100.00  / (((Minutos / (Convert(Numeric(5,2),MinutosEquipo) / 5.00)) * Convert(Numeric(5,2),TirosEquipo)) - Convert(Numeric(5,2),Tiros)) as pAST from Estadisticas

Finalmente nos quedaría el ratio de asistencias por pérdida, que consiste simplemente en dividir las asistencias repartidas entre las pérdidas de balón sufridas. Suponiendo una tabla con los campos Asistencias y Perdidas la consulta sería:

Select Convert(Numeric(5,2),Asistencias)/Convert(Numeric(5,2),Perdidas) as ASTTO from Estadisticas

La críticaal ratio de Hollinger es que solamente refleja la tendencia de un jugador a asistir y no tanto su eficacia, mientras que la crítica al de Pomeroy es que si los compañeros fallan muchos tiros penalizan la estadística del asistente.

Baloncesto y estadística: Consulta SQL para calcular el porcentaje de tiro efectivo (eFG%) y el porcentaje de tiro verdadero (TS%)

El otro día habláblamos un poco sobre estadística avanzada en baloncesto viendo cómo se calcula el PIE, y como ha sido un artículo bien recibido vamos a ver cómo podemos calcular las dos principales estadísticas avanzadas de tiro y aplicarlas a una consulta SQL. Pero veamos primero qué son estas estadísticas.

La estadística de tiro clásica, el porcentaje de tiros anotados, ha dado resultados engañosos desde que se introdujo el tiro de tres. Pensemos por un segundo en dos jugadores que lanzan diez tiros: el primero lanza diez tiros de dos y anota seis, el segundo diez triples y anota cuatro. El porcentaje de tiro simple del primero es de un 60% mientras que el del segundo es de un 40%, pero en realidad ambos han anotado la misma cantidad de puntos: 12. El porcentaje de tiro efectivo y el porcentaje de tiro verdadero ponderan el mayor valor de los triples y el menor valor de los tiros libres para que el cálculo de la efectividad del tirador sea más realista. Dwight Howard o Clint Capela, que anotan mucho pegados al aro o machacando, tendrían mejores porcentajes simples que tiradores excelsos desde la larga distancia como Nowitzki o Curry. O en la ACB podría ser el caso de Tomic y Navarro.

El porcentaje de tiro efectivo es la estadística que pondera el mayor valor de los triples y la fórmula para su cálculo es: (Tiros de campo anotados+0.5*Triples Anotados)/Tiros de campo intentados.

El porcentaje de tiro verdadero incluye también el valor de los tiros libres y se calcula con la siguiente fórmula: Puntos / 2 * (Tiros de campo intentados + 0.44 * Tiros libres intentados)

Supongamos que tenemos una tabla llamada Tiros con las estadísticas de tiro de un jugador en una base de datos SQL-Server, con los siguientes campos: TirosIntentados, TirosAnotados, TriplesAnotados, TirosLibresIntentados y Puntos. Podríamos tener más, pero estos son los campos que necesitamos. Supongamos que todos estos campos almacenan números enteros, que sería lo lógico, y que tendremos que aplicar una conversión porque necesitamos un resultado decimal (en SQL-Server 2008 sería necesario ).

¿Cómo irían las consultas? Aquí para el eFG%:

Select ((Convert(Numeric(4,2),TirosAnotados)+0.5*Convert(Numeric(4,2),TriplesAnotados))/Convert(Numeric(4,2),TirosIntentados)) as eFG from Tiros

Aquí para el TS%:

Select (Convert(Numeric(4,2),Puntos) / 2.00 * (Convert(Numeric(4,2),TirosIntentados) + 0.44 * Convert(Numeric(4,2),TirosLibresIntentados))) as TS from Tiros

MySQL: Consulta para saber cuántas tablas o vistas hay en una base de datos

El otro día veíamos cómo hacerlo con SQL-Server ¿y con MySQL? Más o menos lo mismo, con el pequeño cambio que implica que MySQL obligue a meter siempre en la consulta el nombre del esquema que vamos a usar, mientra que en SQL-Server cogerá por defecto el que tengamos seleccionado.

Entonces en MySQL la cosa quedaría así:

#Contar Tablas
SELECT COUNT(*) from Information_Schema.Tables where TABLE_TYPE = 'BASE TABLE' and table_schema = 'LaBaseDeDatosQueSea';

#Contar Vistas
SELECT COUNT(*) from Information_Schema.Tables where TABLE_TYPE = 'VIEW' and table_schema = 'LaBaseDeDatosQueSea';

#Contar Tablas y vistas
SELECT COUNT(*) from Information_Schema.Tables where table_schema = 'LaBaseDeDatosQueSea';