Resolver problemas al activar Windows 8

Post original en JASoft.org: http://www.jasoft.org/Blog/post/Resolver-problemas-al-activar-Windows-8.aspx

Windows 8 cuando se instala puede funcionar sin necesidad de estar registrado/activado durante 30 días. De todos modos si no lo activas no podrás hacer cosas tan simples como personalizar la pantalla de entrada y además al cabo de 30 días empezará a preguntarte que lo actives cada 3 horas. Además al cabo de otros 30 días te preguntará cada hora que lo actives, y si no lo haces se apagará.

Si has tenido que instalar la versión de Windows 8 que viene con MSDN o con licencias por volumen te habrás encontrado con el problema de que, al intentar la activación del sistema se produce un error con el siguiente mensaje:

0x8007232B – El nombre DNS no existe

Puede que simplemente veas este mensaje en la zona de configuración de Windows:

ActivarW8_1

Pulsa para aumentar

Sin más explicaciones. O si vas a las propiedades del sistema (Tecla de Windows + Pausa), puedes ver el mensaje de error indicado si intentas la activación:

ActivarW8_2
Pulsa para aumentar

El problema es que no es capaz de encontrar el servidor empresarial de licencias, cosa que es normal que no tengas en tu red, pues está pensado para empresas grandes.

Por suerte solucionarlo es muy sencillo, pero hay que saber cómo, claro.

Pulsa Windows+R para lanzar la ventana de ejecución y escribe el siguiente comando:

slui 3

ActivarW8_3

Esto abrirá la ventana de activación normal:

ActivarW8_4

Pulsa para aumentar

en la que podremos introducir el número de serie de nuestra licencia sin problema, y activarlo en el paso siguiente.

Listo.

¡Espero que te resulte útil!

Activar herramientas experimentales avanzadas en Google Chrome Developer Tools

Post original en JASoft.org: http://www.jasoft.org/Blog/post/Activar-herramientas-experimentales-avanzadas-en-Google-Chrome-Developer-Tools.aspx

Si eres programador avanzado de lado cliente, con HTML5, CSS3 y JavaScript seguramente agradecerás toda la ayuda que puedas obtener a la hora de depurar y afinar tus aplicaciones. Las herramientas de desarrollo que vienen integradas con Google Chrome son una gran ayuda. En mi libro de JavaScript tengo un capítulo entero dedicado a ellas.

Además de las herramientas incorporadas de serie, si quieres poder sacar partido a herramientas más avanzadas que de momento Google no tiene terminadas (están en fase experimental) puedes hacerlo de forma sencilla y sin necesidad de descargar o instalar nada.

Para ello puedes seguir los siguientes pasos sencillos:

1.- Abre una nueva pestaña de Chrome y escribe chrome://flags

Esto abrirá los ajustes avanzados del navegador, que nos permiten ajustar infinidad de parámetros avanzados de funcionamiento del mismo:

Chrome_flags_1

2.- Dentro de los ajustes disponibles busca "Enable Developer Tools Experiments" (puedes usar CTRL+F para hacerlo).

Para que funcione el nuevo ajuste tendrás que reiniciar por completo Chrome y todas sus ventanas. Lo mejor es pulsar el botón inferior que aparece "Relaunch now" para conseguirlo.

3.- Abre las herramientas de desarrollador en cualquier página. Para ello pulsa F12. Pulsa el icono de ajustes, que es un icono con un engranaje ubicado en la parte inferior derecha de la ventana:

Chrome_flags_2

4.- En los ajustes de las Developer tools verás que ahora hay una nueva pestaña llamada "Experiments" con una serie de cuadros de verificación que podemos marcar para activar y desactivar características:

Chrome_flags_3

Desde aquí podemos activar algunas de estas características experimentales, como por ejemplo el soporte para sintaxis Saas de CSS desde las herramientas, o poder inspeccionar elementos canvas y sus contenidos.

Es especialmente útil la opción de "Snippets Support" (es de las pocas que está documentada), que nos permite crear nuestros propios fragmentos de código JavaScript y poder usarlos de manera inmediata mientras estamos depurando una página.

OJO: estas características son experimentales y por lo tanto pueden ser inestables y provocar cuelgues o cierres del navegador. Además no están documentadas, por lo que puede resultar difícil encontrar información en Internet sorbe cómo sacarles todo el partido.

¡Espero que te sea útil!

Efecto "Polaroid" y giros en fotografías con CSS

Post original en JASoft.org: http://www.jasoft.org/Blog/post/Efecto-Polaroid-y-giros-en-fotografias-con-CSS.aspx

Cam_Polaroid_1En mi anterior post contaba cómo podíamos utilizar efectos CSS3 para conseguir una mejora sustancial en el aspecto de fotografías (sobre todo de personas), convirtiéndolas en círculos y utilizando efectos auxiliares como bordes y sombras para darles un toque estético adicional.

En esta ocasión voy a seguir en la misma línea y mostraré algunos efectos CSS3 adicionales que nos permitirán obtener un aspecto muy diferente: Efecto «Polaroid».

Las cámaras de foto instantáneas de tipo «Land» (en honor a su inventor) se empezaron a producir a partir de 1948, pero fue en los años ’70 y hasta mediados de los ’80 cuando su popularidad alcanzó el máximo apogeo. Históricamente se han producido cientos de modelos diferentes, pero sin duda la empresa que las popularizó fue Polaroid, hasta tal punto que el nombre de esta marca se ha convertido en un genérico para denominar a este tipo de fotografía (como Kleenex para los pañuelos de papel). En la actualidad Polaroid todavía sigue fabricando este tipo de cámaras .

La principal característica de este tipo de cámaras es que las fotografías que haces con ellas se revelan de manera automática a temperatura ambiente en poco menos de un minuto. Como el papel fotográfico instantáneo hay que agitarlo para acelerar el revelado, tienen un característico borde por el que agarrar la película, que les da ese toque tan especial y reconocible (mira la figura lateral). Además, generalmente, ese borde se utiliza para escribir en él con tinta indeleble mensajes cortos que hagan de la foto un recuerdo imborrable.

Dada su gran popularidad y el todavía factor «cool» que poseen, es un montaje estético que se suele utilizar en muchas páginas web para decorar las fotografías.

¿Cómo podemos conseguir un efecto como el de la fotografía lateral usando solamente CSS?

Bien, lo primero es definir los bordes del papel fotográfico instantáneo. Para ello nada más fácil que añadir unos márgenes simétricos a la fotografía a excepción del margen inferior, más amplio para simular la zona de agarre de la película, usando además un color de fondo blanco, así:

.polaroid {

    background-color:white;

    padding:10px 10px 50px 10px;

    border:1px solid #BFBFBF;

    box-shadow:10px 10px 30px rgba(0, 0, 0, 0.8);

}

Además le hemos añadido una pequeña sombra como ya vimos en el post anterior.

Con esto obtenemos el siguiente efecto sobre nuestra fotografía al aplicarle el nuevo estilo:

Polaroid_red_1

Esto ya se parece mucho a lo que estamos buscando.

Además, podemos darle un toque más realista imitando la sensación de que la fotografía se ha dejado caer de manera descuidada encima de una mesa, para lo cual vamos a rotarla.  Definiremos dos estilos, uno con rotación a la derecha y el otro hacia la izquierda, así:

.RotarIzq {

    transform:rotate(10deg);

    -ms-transform:rotate(10deg); /* IE9 */

    -webkit-transform:rotate(10deg); /* Safari y Chrome */

    -moz-transform:rotate(10deg); 

}

 

.RotarDer {

    transform:rotate(-10deg);

    -ms-transform:rotate(-10deg); /* IE9 */

    -webkit-transform:rotate(-10deg); /* Safari y Chrome */

    -moz-transform:rotate(-10deg); 

}

En este caso utilizamos el atributo CSS3 transform y sus variantes específicas de cada navegador. Este atributo nos permite realizar transformaciones 2D y 3D sobre los elementos de una página, con operaciones como rotar, desplazar, girar respecto a un punto, etc…

Nota: Las transformaciones en dos dimensiones están soportadas por todos los navegadores modernos (a partir de Internet Explorer 10, Chrome 26, Firefox 20 y safari 5.1 además de los móviles), pero las transformaciones 3D y para SVG no tienen un soporte tan amplio (las 3D no las soporta IE, y las de SVG solamente Firefox de manera total). Internet Explorer 9 las soporta si empleamos el prefijo -ms- delante del nombre del atributo, y Google Chrome, en todas sus versiones (al menos hasta la actual 27) y Safari solamente usando el prefijo específico -webkit-. Finalmente el prefijo -moz- nos sirve para que lo soporten versiones antiguas de Firefox también.

Si aplicamos por tanto la clase «polaroid» y la clase «RotarDer» a nuestra imagen:

<img class="polaroid RotarDer" src="Cam_Polaroid.jpg" alt="Imagen Polaroid con CSS">

obtenemos el siguiente efecto aún más realista:

Polaroid_res_2

Incluir texto en la solapa inferior

Si queremos además incluir texto en la parte inferior, como en una foto de verdad, tenemos que usar una estrategia ligeramente diferente. En este caso deberemos meter tanto la imagen como el texto dentro de un contenedor que simule el marco, y aplicar los estilos a este contenedor en lugar de la imagen para que se apliquen a todo el conjunto y todo éste gire a la vez. Así, podemos redefinir ligeramente el estilo de la siguiente manera:

.polaroidContenedor {

      width:300px;

      padding:10px 10px 10px 10px;

      border:1px solid #BFBFBF;

      background-color:white;

      box-shadow:10px 10px 30px rgba(0, 0, 0, 0.8);

  }

He hecho dos cambios:

  • Por un lado he especificado para el contendor un tamaño igual al de la imagen. Esto evita que éste se adapte a su contenedor y se quede pegado por lo tanto a los bordes de la fotografía, aplicando además «wrapping» (cambio de línea) al texto que vamos a poner en la base.
  • He quitado el padding adicional del borde inferior. Dado que vamos a introducir texto ahí ya no nos hace falta añadir ese espacio artificialmente, pues será el texto el encargado de dar «aire» a la parte de abajo. Hay que tener en cuenta que si no podemos texto entonces deberíamos dejárselo, pero estaríamos por tanto en el caso anterior.

Además he definido un estilo para el texto para que tenga una letra bonita (podríamos usar una fuente manuscrita embebida en el CSS o descargada desde la web), alineación centrada, y un pequeño margen de 1 em por la parte superior para que no se pegue a la imagen:

.textoPolaroid {

    display:block;

    margin-top:1em;

    text-align:center;

    font-style:italic;

    font-family:"Lucida Sans", "Lucida Sans Regular", "Lucida Grande", "Lucida Sans Unicode", Geneva, Verdana, sans-serif;

}

Si ahora escribo este código HTML:

<div class="polaroidContenedor RotarIzq">

    <img src="Cam_Polaroid.jpg" alt="Imagen Polaroid con CSS">

    <span class="textoPolaroid">¡Este es el texto que aparecerá debajo de la imagen!</span>

</div>

Obtengo una fotografía estilo Polaroid con texto debajo también rotado, como la segunda de esta imagen:

Polaroid_res_3

De esta forma además consigo que las imágenes se puedan montar unas encima de otras, como en la figura, dando mayor sensación aún de realismo. Podría haberlas metido juntas dentro de un DIV de un determinado tamaño, desplazarlas un poco desde el origen a cada una y dándoles una rotación diferente, para conseguir que parezca un grupo de fotografías Polaroid dejadas descuidadamente encima de la mesa, unas encima de otras.

Como vemos el efecto es muy llamativo, fácil de conseguir y sin necesidad de programar.

Este post está basado en material extraído de mi curso online de HTML(5) y CSS(3) en campusMVP. Si quieres aprender de verdad este tema y tenerme como tutor para contestar tus dudas empieza hoy mismo.

 

He dejado un archivo ZIP (13 Kb) con el ejemplo completo para que puedas examinarlo.

¡Espero que te sea útil!

Imágenes circulares solamente con CSS 3

Post original en JASoft.org: http://www.jasoft.org/Blog/post/Imagenes-circulares-solamente-con-CSS-3.aspx

Últimamente está muy de moda ofrecer imágenes mejoradas con algún efecto a la hora de presentarlas en las páginas Web.

Por ejemplo, si visitas mi página de Google+ verás que mi foto aparece en forma de círculo, aunque en realidad es cuadrada:

CSS_Imgs_1

La verdad es que queda mucho mejor.

Pero, si la foto que yo subí originalmente es cuadrada, esta con forma circular ¿se genera automáticamente a partir de la original? ¿Cómo se consigue ese efecto?

La respuesta viene de la mano de CSS y el uso inteligente de los bordes.

Bordes redondeados

Vamos a partir de una fotografía cuadrada como la que muestra a continuación:

PuenteBellevue

Se trata de un paso elevado entre dos edificios en Bellevue (WA).

Para conseguir que se visualice recortada en círculo, lo que tenemos que hacer es sacar partido a la propiedad border-radius de CSS 3.

Esta propiedad nos permite definir la curvatura en pixeles u otras unidades que va a tener cada uno de los cuatro bordes de un elemento HTML. Así, por ejemplo, si queremos que un DIV tenga un borde redondeado de trazo liso, con un radio de 20 pixeles de curvatura en las esquinas, sólo tenemos que escribir algo así:

<div style="width:300px; height:150px; border: 2px dashed;background-color:silver;border-radius:20px;">

</div>

Es decir, creamos un recuadro de 300px de ancho y 150 de alto, un borde a rayas de grosor 2px, con color gris de fondo y le indicamos que el radio de las esquinas debe ser de 20 pixeles. Con esto el recuadro resultante sería el siguiente:

CSS_Imgs_2

No muy espectacular, pero mucho más agradable que un simple recuadro normal.

Podríamos especificar que solamente algunas esquinas concretas fueran redondeadas utilizando los atributos CSS específicos para las mismas. Por ejemplo, que la esquina superior izquierda y la inferior derecha sean redondas pero no las otras dos, para lo cual cambiamos el border-radios (que afecta a todas) por esto:

border-top-left-radius:20px;border-bottom-right-radius:20px;

Y obtendríamos este rectángulo:

CSS_Imgs_3

Lo importante aquí para nuestro propósito es que podemos jugar con esos bordes redondeados para conseguir algunos efectos como el deseado de las fotos circulares.

Por ejemplo, si nuestra imagen mide 300×300 px de tamaño, podemos indicar que queremos que el radio de las 4 esquinas redondeadas sea justo la mitad (150px) para obtener lo siguiente:

CSS_Imgs_4

¡Tachán! Es una foto redonda, justo como queríamos.

Lo malo es que hemos tenido que especificar el radio específico para el tamaño de esta foto en concreto y en una página podemos tener fotos de diversos tamaños. Es por eso por lo que destaqué antes que, para el radio, podíamos usar cualquier unidad de medida permitida por CSS. Eso significa que podemos utilizar porcentajes, así que si en lugar de un tamaño fijo indicamos que queremos un radio para las esquinas de un 50% del tamaño (es decir, justo la mitad) obtendremos siempre el efecto circular sea cual sea el tamaño de la imagen:

img.circular {

    border-radius: 50%;

}

Podemos mejorar el aspecto de la foto redonda si además le añadimos algún efecto más con CSS Por ejemplo, si le coloco un borde a rayas y una sombra tenue alrededor, la cosa mejora bastante:

img.circular {

    border-radius: 50%;

    border:1px black dashed;

    box-shadow: 0px 0px 50px 0px rgba(0, 0, 0, 0.8);

}

obteniendo lo de la siguiente imagen, un efecto mucho más atractivo:

CSS_Imgs_5

En este caso el efecto que he utilizado es el de sombra con CSS, usando el atributo box-shadow. Éste toma como parámetros el desplazamiento de la sombra desde el centro en horizontal y vertical (en este caso lo he dejado en el centro: 0px, 0px), la distancia adicional desde el borde que deberá ocupar el difuminado de la sombra (50px), la distancia adicional que deberá alcanzar la sobra en si desde los bordes (la parte más oscura, en este caso no quiero que se vea o le haría un círculo negro: la dejo a 0px), y finalmente el color de la sombra. En este caso utilizo el color negro, pero le doy una transparencia del 80% en la componente alfa del color: rgba(0,0,0, 0.8).

Efectos estilo PowerPoint

Gracias a estas técnicas tan sencillas se pueden conseguir otros efectos gráficos interesantes. Por ejemplo, uno de los estilos de imagen automáticos que introdujo Office 2010 y que a mi más me gusta es el llamado «Diagonales Redondeadas Blancas» que podemos ver en la imagen:

CSS_Imgs_6

Gracias a lo que hemos visto en este artículo es muy sencillo conseguir el mismo efecto con CSS en una página. basta con jugar con los bordes redondeados, el color de fondo, los márgenes y las sombras:

img.DiagonalRedonda {

    border-top-left-radius: 20%;

    border-bottom-right-radius: 20%;

    border:1px black solid;

    background-color:white;

    padding:10px;

    box-shadow: 0px 0px 50px 0px rgba(0, 0, 0, 0.8);

}

Con esto lo que hacemos es poner los bordes superior-izquierdo e inferior-derecho redondeados a un 20% del tamaño de la imagen, le damos un borde fino al conjunto. A continuación le ponemos un fondo de color blanco y hacemos que haya una separación entre el objeto y el borde. De este modo ese espacio de separación (padding) que está vacío se mostrará del color del fondo, o sea blanco, que es el efecto que buscamos. Finalmente le damos un toque atractivo gracias a una sombra. El resultado es muy bonito:

CSS_Imgs_7

y es exactamente al de PowerPoint que estábamos buscando 🙂

Soporte de navegadores

Los atributos border-radius y box-shadow están soportados a partir de las siguientes versiones de los navegadores:

  • Internet Explorer 9
  • Firefox 20
  • Chrome 26
  • Safari 5.1
  • Todas las versiones de navegadores móviles importantes

Dado que, por lo tanto, están soportados por todos los navegadores modernos ya desde hace años, hoy en día ya no es necesario utilizar los prefijos propios de cada navegador (como -moz o -webkit) para que funcione.

En el caso de Chrome, como se actualiza automáticamente, los usuarios siempre tienen la última versión, pero Safari y Mozilla no se actualizan solos, así que puede que tengamos visitantes a la web que no estén a la última y no les funcione el efecto. Si queremos minimizar el impacto en estos navegadores viejos y que lo vean igual, podemos agregar estas variantes específicas del mismo atributo, quedando de la siguiente manera:

img.circular {

    border-radius: 50%;

    -webkit-border-radius: 50%;

    -moz-border-radius: 50%;

}

Con esto conseguiremos que funcione en versiones muy viejas de Firefox y Safari, aunque no en Internet Explorer 8 o anterior. En ese caso se seguirá viendo cuadrada.

En el caso de la sombra, existe un modificador para Webkit (Safari) que es, claro está, -webkit-box-shadow. No es así para el caso de Firefoz ni de IE, por lo que en versiones viejas la sombra simplemente no se visualizará, pero es un problema menor.

Más efectos bonitos en breve

En un próximo post explicaré, por ejemplo, cómo conseguir otros efectos bonitos con CSS e imágenes, como por ejemplo, el efecto «Foto Polaroid» que incluso nos permitirá hacer montajes realistas de las fotos como si estuvieran distribuidas de manera descuidada encima de una mesa (con rotaciones y solapamientos), y incluyendo además letras en el conjunto.

Te dejo el archivo de ejemplo del artículo de artículo aquí para que puedas experimentar con él.

¡Espero que haya resultado útil!

Cómo devolver los resultados de una sub-consulta como un único campo de texto

Post original en JASoft.org: http://www.jasoft.org/Blog/post/Como-devolver-los-resultados-de-una-sub-consulta-como-un-unico-campo-de-texto.aspx

cuadricula_datosEsta es una tarea bastante común pero que es muy complicada de conseguir con SQL Server.

Imagínate que tienes la siguiente situación: Necesitas obtener un listado, en una cuadricula, con los datos básicos de cada cliente de tu base de datos, y con la fecha y el importe de cada pedido que ha realizado en el último año a continuación en la misma fila.

Obtener un listado de clientes es un simple SELECT y obtener un listado de clientes con sus pedidos es un simple INNER JOIN. Lo complicado es que obtengamos para cada cliente toda la información de los pedidos como si fuera un campo más de la consulta. Cada cliente puede tener (y tendrá generalmente) un número de pedidos distinto: unos harán 1 pedido, otros 3 y otros 10, así que no podemos simplemente trasponer los resultados con PIVOT o UNPIVOT para devolverlos en columnas en lugar de en filas.

Un listado de este tipo tendría un aspecto similar a este:

FORXML_PedidosEjemplo

Es decir, si nos fijamos, en el HTML resultante cada fila tiene un número variable de columnas, de modo que un cliente tiene 3  pedidos (y por tanto 6 celdas más), otro solamente 1 pedido, otros 2, etc…

Si tenemos muchos clientes, lanzar desde el lado cliente una consulta extra por cada registro para obtener los sub-pedidos y encajarlos en los resultados es algo muy costoso y hará que perdamos rendimiento. Una opción más común y efectiva sería obtener una lista de todos los pedidos de cada cliente e iterar por ellos cambiando de fila cuando detectemos que cambia el cliente en el resulset de la base de datos.

Sin embargo en ocasiones sería mucho mejor poder lanzar una única consulta que nos devuelva de alguna manera ese dato variable ya listo para ser utilizado en nuestra aplicación.

Para ver cómo conseguir esto último, utilizaremos la archiconocida base de datos de ejemplo Northwind.

Primero las consultas básicas

Si queremos obtener todos los pedidos de cada cliente, basta hacer una consulta sencilla de combinación de tablas con INNER JOIN, así:

   1: SELECT     dbo.Customers.CompanyName, dbo.Orders.OrderID, dbo.Orders.OrderDate

   2: FROM         dbo.Customers INNER JOIN

   3:                       dbo.Orders ON dbo.Customers.CustomerID = dbo.Orders.CustomerID

   4: ORDER BY CompanyName ASC

Nota: Por simplicidad he elegido el ID del pedido en lugar de su importe por evitar una sub-consulta más para sumarlos, ya que solo liaría la sintaxis, es muy fácil y no es objeto de este post.

Con esto obtenemos el siguiente resultado en la base de datos Northwind:

FORXML_INNERJOIN

Es decir, una línea en el resulset por cada pedido del cliente, con el nombre del cliente repetido.

Lo que necesitamos sin embargo es que cada pedido se junte de alguna manera para obtenerlos todos juntos dentro de un campo de resultados, obteniendo así una única fila por cliente.

Para conseguirlo vamos a separar el proceso en dos partes

Separando la consulta en dos partes

Lo que necesitamos por lo tanto es una consulta similar a esta tan sencilla:

   1: SELECT CompanyName ,

   2:         (

   3:             --ALGO AQUÍ

   4:         ) AS Pedidos

   5: FROM Customers

   6: ORDER BY CompanyName ASC

Es decir, tendremos que introducir alguna instrucción en el hueco que hemos dejado para que nos devuelva los pedidos como un único resultado. Eso implica devolverlos concatenados de alguna manera, generalmente como una cadena de texto, claro está.

La sub-consulta que necesitamos para obtener los pedidos de cada cliente es obvia también, sería esta:

   1: SELECT  OrderID, OrderDate FROM Orders 

   2:             WHERE CustomerID = Customers.CustomerID

Que utilizada dentro de la anterior nos daría los pedidos de cada cliente en un resulset. Lo que ocurre es que no nos devuelve un único dato, sino que nos devuelve un conjunto de registros, que no podemos introducir como si fuera un campo más de resultado. Hay que juntarlos en una cadena de alguna manera.

Podríamos probar con algo así:

   1: SELECT  CAST(OrderID AS nvarchar(20)) + ' - ' + CAST(OrderDate AS NVARCHAR(20)) FROM Orders 

   2:             WHERE CustomerID = Customers.CustomerID

De este modo obtendríamos un único campo por cada registro devuelto por la sub-consulta, pero sigue sin servirnos porque si un cliente tiene 5 pedidos obtendríamos 5 registros como resultado, y necesitamos imperiosamente obtener solamente 1 para que la consulta funcione.

FOR XML al rescate

Cuando alguien inventa una herramienta con un propósito en mente, generalmente se sorprende de los usos que luego le da la gente y en los que jamás había pensado. Me da la impresión de que este es el caso de como se siente el que inventó la instrucción FOR XML de SQL Server, introducida con SQL Server 2005.

FOR XML, como puede deducirse de su nombre, sirve para convertir un conjunto de resultados en una expresión XML.

Dispone de cuatro variantes:

  • RAW: genera un elemento de tipo <row> por cada registro, poniendo sus valores como atributos de cada nodo.
  • AUTO: genere los nodos XML a partir de los nombres de los campos y de la tabla, de manera automática.
  • EXPLICIT: deja definir cómo queremos el XML resultante usando una serie de convenciones en los nombres de las tablas y los campos usados en las consultas.
  • PATH: Es parecido al anterior pero mucho más fácil de usar, aunque con algunas limitaciones. Es el que mejor nos va a venir para nuestro propósito.

¿Cómo podemos sacar partido a esta instrucción para conseguir nuestro propósito?

Usando FOR XML PATH podemos controlar de qué forma queremos devolver los resultados de la sub-consulta agregados en un único campo.

Por ejemplo, si escribimos lo siguiente para rellenar el hueco en la consulta del apartado anterior:

   1: SELECT CompanyName ,

   2:         (

   3:             SELECT  CAST(OrderID AS nvarchar(20)) + ' - ' + CAST(OrderDate AS NVARCHAR(20)) AS td FROM Orders

   4:             WHERE CustomerID = Customers.CustomerID

   5:             FOR XML PATH('tr')

   6:         ) AS Pedidos

   7: FROM Customers

   8: ORDER BY CompanyName ASC

Con el FOR XML le estamos indicando que queremos devolver los resultados de la sub-consulta como una cadena de texto XML que tiene como nodo para cada registro uno de nombre “tr” (lo que va entre paréntesis en el FOR XML PATH), y como sub-nodo para el campo que devolvemos el nombre “td”, por lo que obtendremos el siguiente resultado:

FORXML_TRTD

Pulsa para aumentar

Como puedes observar en la figura anterior, nos devuelve una cadena con filas y columnas de una tabla HTML, lo cual es perfecto para nuestro propósito, y podemos insertar el campo sin más en los resultados de una página para obtener una tabla de datos como la que queríamos.

Control libre del formato del resultado

Esto está muy bien, pero nos da poca libertad en el formato del resultado en ese campo. ¿Cómo podemos generar un texto cualquiera a partir de los campos del resultado de la sub-consulta?

Pues simplemente concatenando los campos como mejor nos venga y haciendo que el FOR XML no genere automáticamente ningún nodo XML.

Para ello lo que debemos hacer es indicar como ruta base del XML una cadena vacía: esto hará que el XML resultante no utilice nodo alguno para rodear cada registro. Si además no le ponemos nombre al campo que devolvemos en la sub-consulta tampoco se generará nodo alguno para éste. Así que si hacemos esto:

   1: SELECT CompanyName ,

   2:         (

   3:             SELECT  ' // ' + CAST(OrderID AS nvarchar(20)) + ' - ' + CAST(OrderDate AS NVARCHAR(20)) FROM Orders

   4:             WHERE CustomerID = Customers.CustomerID

   5:             FOR XML PATH('')

   6:         ) AS Pedidos

   7: FROM Customers

   8: ORDER BY CompanyName ASC

Obtendremos el siguiente resultado:

FORXML_FormatoLibre

Fíjate en como cada registro de la sub-consulta se separa de los demás mediante un “ // “ al principio , y cada campo del registro se separa del otro con un guión. Podríamos haber usado cualquier otro formato más elaborado, claro está.

Sólo queda un pequeño problema: librarnos del primer separador de registros (“ // “) que aparece al principio de cada campo y que nos está molestando justo ahí. Es decir, debería estar entre cada registro pero no en el primero. ¿Cómo lo eliminamos?

Eliminando el primer separador con STUFF

TSQL tiene una instrucción llamada STUFF que nos permite rellenar (es su traducción del inglés) cualquier cadena con otra cadena diferente, y toma los siguientes parámetros:

  • La cadena origen en la que queremos hacer el “rellenado”
  • La posición en la que empezaremos a “rellenar”
  • La cantidad de caracteres que vamos a retirar para hacer sitio para nuestra nueva cadena de "relleno”
  • La cadena de “relleno”

Gracias a esta instrucción librarnos de esos caracteres del principio es muy sencillo pues basta añadir STUFF de la siguiente manera:

   1: STUFF(expresion, 1, 4, '')

Siendo “expresion” la expresi´no en la que vamos a sustituir, en nuestro caso la consulta anterior, de la que eliminamos cuatro caracteres desde la primera posición (o sea, los cuatro de “ // “), y los sustituimos por una cadena en blanco, o sea por nada: los quitamos.

Así, nuestra expresión final queda de la siguiente manera:

   1: SELECT CompanyName ,

   2:         STUFF(

   3:               (

   4:                 SELECT  ' // ' + CAST(OrderID AS nvarchar(20)) + ' - ' + CAST(OrderDate AS NVARCHAR(20))

   5:                 FROM Orders

   6:                 WHERE CustomerID = Customers.CustomerID

   7:                 FOR XML PATH('')

   8:               ),

   9:               1,

  10:               4,

  11:               ''

  12:             ) AS Pedidos

  13: FROM Customers

  14: ORDER BY CompanyName ASC

Obteniendo el siguiente resultado:

FORXML_FormatoLibreSTUFF

que, como vemos, es el esperado.

En resumen

Utilizando un par de comandos de T-SQL en principio orientados a otro tipo de problemas, es posible conseguir cómodos listados de datos de sub-consultas, en una sola consulta, obteniendo el formato que deseemos.

Es algo poco común pero que en ciertas ocasiones puede resultarnos muy útil. Yo he tenido que utilizarlo hace poco y me lo he pasado muy bien aprendiendo estas técnicas que ahora te explico con detalle aquí.

Lleva tus conocimientos de SQL Server y T-SQL a otro nivel con nuestro curso.

Hands on SQL Server 2012: Expert Programming and Design (en inglés)

¡Espero que te resulte útil!

photo credit: ecstaticist cc