<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8153574442463741229</id><updated>2026-03-18T20:43:18.981+01:00</updated><category term="T-SQL"/><category term="rendimiento"/><category term="configuración"/><category term="procedimientos almacenados"/><category term="COUNT"/><category term="Management Studio"/><category term="SELECT"/><category term="triggers"/><category term="DBA"/><category term="DELETE"/><category term="DMV"/><category term="IDENTITY"/><category term="INSERT"/><category term="Itzik Ben-Gan"/><category term="OUTPUT"/><category term="SET NOCOUNT ON"/><category term="SQL Server Express"/><category term="UPDATE"/><category term="agregados"/><category term="autogrowth"/><category term="puzzle"/><category term="script"/><category term="tipos de datos"/><category term="vistas de sistema"/><category term="Índices"/><category term="ALTER INDEX"/><category term="AVG"/><category term="Bug"/><category term="CASE"/><category term="Cast"/><category term="DBCC"/><category term="DISTINCT"/><category term="Data Annotations"/><category term="Entity Framework"/><category term="ExecuteNonQuery"/><category term="Express Profiler"/><category term="FROM"/><category term="Fluent API"/><category term="ISNULL"/><category term="IntelliSense"/><category term="LEFT OUTER JOIN"/><category term="MAX"/><category term="MIN"/><category term="MVC"/><category term="Microsoft"/><category term="NULL"/><category term="POCO"/><category term="Plan de ejecución"/><category term="Power BI"/><category term="REBUILD"/><category term="REORGANIZE"/><category term="ROW_NUMBER"/><category term="SEQUENCE"/><category term="SET"/><category term="SET DATEFORMAT"/><category term="SET LANGUAGE"/><category term="SQL Saturday"/><category term="SQL Server 2012"/><category term="SQL Server 2014"/><category term="SQLSaturday"/><category term="SUM"/><category term="TABLESAMPLE"/><category term="Trace Flags"/><category term="UNION"/><category term="UNION ALL"/><category term="XML"/><category term="aprendizaje"/><category term="autocompletado"/><category term="best practices"/><category term="buenas prácticas"/><category term="clustered"/><category term="concurso"/><category term="configuración regional"/><category term="consultas"/><category term="deleted"/><category term="desbordamiento"/><category term="diagnóstico"/><category term="error"/><category term="errores comunes"/><category term="esquemas"/><category term="eventos"/><category term="fechas"/><category term="ficheros"/><category term="fragmentación"/><category term="fully qualified name"/><category term="funciones"/><category term="heap"/><category term="in-memory OLTP"/><category term="inserted"/><category term="inyección"/><category term="limitaciones"/><category term="log"/><category term="mantenimiento"/><category term="model"/><category term="name resolution"/><category term="networking"/><category term="profiler"/><category term="propietario"/><category term="recomendaciones"/><category term="seguridad"/><category term="sql server profiler"/><category term="tablas"/><category term="tamaño"/><category term="vistas"/><category term="vistas de catálogo"/><category term="vulnerabilidad"/><title type='text'>Aprendiendo SQL Server</title><subtitle type='html'>Este es el blog de un entusiasta, experto en bases de datos (SQL Server 2012 Microsoft Certified Professional), que tratará de contaros el día a día de sus peripecias con Microsoft SQL Server. ¿Quieres aprender un poco más? ¿Tienes problemas con alguna consulta o de rendimiento con tu base de datos? Quizás pueda ayudarte. No dudes en dejar tus comentarios.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>36</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-5587677636224190180</id><published>2017-08-17T10:42:00.000+02:00</published><updated>2017-08-17T11:21:20.023+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="agregados"/><category scheme="http://www.blogger.com/atom/ns#" term="AVG"/><category scheme="http://www.blogger.com/atom/ns#" term="COUNT"/><category scheme="http://www.blogger.com/atom/ns#" term="desbordamiento"/><category scheme="http://www.blogger.com/atom/ns#" term="error"/><category scheme="http://www.blogger.com/atom/ns#" term="SUM"/><title type='text'>Desbordando AVG y SUM: Cuando SQL Server se queda sin dedos para sumar</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Entre las múltiples funciones de agregado que nos ofrece SQL Server, nos encontramos con dos que, probablemente junto con &lt;b&gt;COUNT&lt;/b&gt;(), son las más usadas: &lt;b&gt;SUM&lt;/b&gt;() y &lt;b&gt;AVG&lt;/b&gt;().&lt;br /&gt;
&lt;br /&gt;
El resultado que producen ambas parece bastante obvio: SUM() devuelve la &lt;b&gt;suma de valores&lt;/b&gt; de la columna que le indiquemos a la función, mientras que AVG() nos devolverá el &lt;b&gt;valor promedio&lt;/b&gt; de los datos de la columna deseada.&lt;br /&gt;
&lt;br /&gt;
Así pues, si tenemos una tabla de pedidos con la columna Importe, que indica el importe final de cada pedido sin decimales (tipo de datos int), si queremos saber la suma de los importes de todos los pedidos, bastará con realizar la siguiente consulta:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SELECT SUM(Importe)
FROM dbo.Pedidos;
&lt;/pre&gt;
&lt;br /&gt;
Análogamente, si queremos conocer el valor promedio de los pedidos:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SELECT AVG(Importe)
FROM dbo.Pedidos;
&lt;/pre&gt;
&lt;br /&gt;
El resultado devuelto por ambas será un entero (int) con la suma y el promedio respectivamente.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
        &quot;Estos números son muy grandes, no sé contar tanto&quot;
    &lt;/h3&gt;
&lt;br /&gt;
Estas funciones probablemente no nos fallarán nunca, hasta que de repente un día veamos un mensaje en rojo que nos diga:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: red;&quot;&gt;Msg 8115, Level 16, State 2, Line 1&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: red;&quot;&gt;Arithmetic overflow error converting expression to data type int.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
¡Oh, oh! ¿Qué ha ocurrido aquí? Muy sencillo: Si el resultado de la suma es más grande que el entero (int) más grande, tenemos un &lt;b&gt;desbordamiento aritmético&lt;/b&gt;. El número es demasiado grande como para que SQL Server lo pueda devolver.&lt;br /&gt;
&lt;br /&gt;
Es decir, es como si nos piden sumar 5 y 6 con los dedos de la mano: una vez pasemos de 10, nos hemos quedado sin dedos. Se nos han desbordado las manos.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;
        &lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVSKZiVNtxmAulmZ9iZxc5gb3Qu2cYm4RWD8_LsSvZd9Ob7wjwJsLZ_1WTe2ExPuBb1RPyEm_0ytHLW-TkIgtHC9wNG9xvRLU5qLPszEM_Me6JqTadOj6DXYCvk6CIDj1scDnhulg83lEV/s1600/1441135302_istock_000016718615_medium.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;No podemos contar más de 10 con los dedos de la mano&quot; border=&quot;0&quot; data-original-height=&quot;363&quot; data-original-width=&quot;850&quot; height=&quot;170&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVSKZiVNtxmAulmZ9iZxc5gb3Qu2cYm4RWD8_LsSvZd9Ob7wjwJsLZ_1WTe2ExPuBb1RPyEm_0ytHLW-TkIgtHC9wNG9xvRLU5qLPszEM_Me6JqTadOj6DXYCvk6CIDj1scDnhulg83lEV/s400/1441135302_istock_000016718615_medium.jpg&quot; title=&quot;¿Cuántos son 6 + 5? ¡No tengo suficientes dedos!&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;¿Cuántos son 6 + 5? ¡No tengo suficientes dedos!&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
    &lt;/table&gt;
Podemos hacer la &lt;b&gt;prueba &lt;/b&gt;rápidamente con el siguiente script, en el que introducimos dos pedidos con importe de 1.000.000.000 y 2.000.000.000, y tratamos de obtener la suma de los importes:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;CREATE TABLE dbo.Pedidos
(
 NumeroPedido int PRIMARY KEY,
 Importe int
);&lt;/pre&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;INSERT INTO dbo.Pedidos (NumeroPedido, Importe)
VALUES (1, 1000000000), (2, 2000000000);&lt;/pre&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SELECT SUM(Importe)
FROM dbo.Pedidos;&lt;/pre&gt;
&lt;br /&gt;
Ejecutamos el script y se genera el error anteriormente mencionado. La explicación es sencilla: la suma de los importes es 3.000.000.000, pero el valor máximo que puede representar el tipo de datos int es algo más de 2.100.000.000, así que hemos desbordado la suma.&lt;br /&gt;
&lt;br /&gt;
Si ejecutamos el promedio (AVG) ocurrirá exactamente lo mismo:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SELECT AVG(Importe)
FROM dbo.Pedidos;&lt;/pre&gt;
&lt;br /&gt;
¿Por qué? Porque primero hay que realizar la suma de todos los importes para después dividir entre el número de elementos. Como la suma desborda el tipo de datos, SQL Server no puede seguir adelante con la operación:&lt;br /&gt;
&lt;br /&gt;
(1.000.000.000&amp;nbsp;+ 2.000.000.000) / 2&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
        Todo tiene solución
    &lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;
En este caso, como muchas otras veces, podemos solucionar este escenario simplemente consultando la &lt;a href=&quot;https://msdn.microsoft.com/es-es/library/ms187810(v=sql.120).aspx&quot;&gt;ayuda online&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Vemos en la siguiente tabla que SUM devuelve un entero (int) si el tipo de datos de entrada es tinyint (1 byte), smallint (2 bytes) o int (4 bytes), por lo que si intentamos sumar columnas de estos tipos de datos tendremos el límite citado anteriormente (exactamente 2.147.483.647)&amp;nbsp;
    &lt;/div&gt;
&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;div class=&quot;topic&quot; xmlns:cs=&quot;http://msdn.microsoft.com/en-us/&quot; xmlns:msxsl=&quot;urn:schemas-microsoft-com:xslt&quot; xmlns:mtps=&quot;http://msdn2.microsoft.com/mtps&quot; xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;div id=&quot;mainSection&quot; style=&quot;clear: both;&quot;&gt;
&lt;div id=&quot;mainBody&quot;&gt;
&lt;div class=&quot;tableSection&quot;&gt;
&lt;div class=&quot;contentTableWrapper&quot; style=&quot;overflow-x: auto;&quot;&gt;
&lt;table responsive=&quot;true&quot; style=&quot;border-collapse: collapse; border: 1px solid rgb(187, 187, 187); margin-bottom: 20px; margin-top: 20px; word-break: break-word;&quot; summary=&quot;table&quot;&gt;
                                    &lt;tbody&gt;
&lt;tr responsive=&quot;true&quot;&gt;
                                            &lt;th scope=&quot;col&quot; style=&quot;background-color: #ededed; border: 1px solid rgb(187, 187, 187); color: #636363; padding: 10px 8px; text-align: left;&quot;&gt;&lt;div style=&quot;color: #2a2a2a; line-height: 18px; padding-bottom: 0px;&quot;&gt;
&lt;span class=&quot;sentence&quot; data-guid=&quot;1b77ddc77882ff50558d29d36da83d93&quot; data-source=&quot;Expression result&quot; id=&quot;mt19&quot; xml:space=&quot;preserve&quot;&gt;Resultado de la expresión&lt;/span&gt;
                                                &lt;/div&gt;
&lt;/th&gt;
                                            &lt;th scope=&quot;col&quot; style=&quot;background-color: #ededed; border: 1px solid rgb(187, 187, 187); color: #636363; padding: 10px 8px; text-align: left;&quot;&gt;&lt;div style=&quot;color: #2a2a2a; line-height: 18px; padding-bottom: 0px;&quot;&gt;
&lt;span class=&quot;sentence&quot; data-guid=&quot;f9f8a3c1693b3965d83435feadd1ff6b&quot; data-source=&quot;Return type&quot; id=&quot;mt20&quot; xml:space=&quot;preserve&quot;&gt;Tipo de valor devuelto&lt;/span&gt;
                                                &lt;/div&gt;
&lt;/th&gt;
                                        &lt;/tr&gt;
&lt;tr&gt;
                                            &lt;td data-th=&quot;Resultado de la expresión&quot; style=&quot;border: 1px solid rgb(187, 187, 187); color: #2a2a2a; min-width: 80px; padding: 10px 8px; vertical-align: top;&quot;&gt;&lt;div style=&quot;line-height: 18px; padding-bottom: 0px;&quot;&gt;
&lt;span class=&quot;input&quot; style=&quot;font-weight: 700;&quot;&gt;tinyint&lt;/span&gt;
                                                &lt;/div&gt;
&lt;/td&gt;
                                            &lt;td data-th=&quot;Tipo de valor devuelto&quot; style=&quot;border: 1px solid rgb(187, 187, 187); color: #2a2a2a; min-width: 80px; padding: 10px 8px; vertical-align: top;&quot;&gt;&lt;div style=&quot;line-height: 18px; padding-bottom: 0px;&quot;&gt;
&lt;span class=&quot;input&quot; style=&quot;font-weight: 700;&quot;&gt;int&lt;/span&gt;
                                                &lt;/div&gt;
&lt;/td&gt;
                                        &lt;/tr&gt;
&lt;tr&gt;
                                            &lt;td data-th=&quot;Resultado de la expresión&quot; style=&quot;border: 1px solid rgb(187, 187, 187); color: #2a2a2a; min-width: 80px; padding: 10px 8px; vertical-align: top;&quot;&gt;&lt;div style=&quot;line-height: 18px; padding-bottom: 0px;&quot;&gt;
&lt;span class=&quot;input&quot; style=&quot;font-weight: 700;&quot;&gt;smallint&lt;/span&gt;
                                                &lt;/div&gt;
&lt;/td&gt;
                                            &lt;td data-th=&quot;Tipo de valor devuelto&quot; style=&quot;border: 1px solid rgb(187, 187, 187); color: #2a2a2a; min-width: 80px; padding: 10px 8px; vertical-align: top;&quot;&gt;&lt;div style=&quot;line-height: 18px; padding-bottom: 0px;&quot;&gt;
&lt;span class=&quot;input&quot; style=&quot;font-weight: 700;&quot;&gt;int&lt;/span&gt;
                                                &lt;/div&gt;
&lt;/td&gt;
                                        &lt;/tr&gt;
&lt;tr&gt;
                                            &lt;td data-th=&quot;Resultado de la expresión&quot; style=&quot;border: 1px solid rgb(187, 187, 187); color: #2a2a2a; min-width: 80px; padding: 10px 8px; vertical-align: top;&quot;&gt;&lt;div style=&quot;line-height: 18px; padding-bottom: 0px;&quot;&gt;
&lt;span class=&quot;input&quot; style=&quot;font-weight: 700;&quot;&gt;int&lt;/span&gt;
                                                &lt;/div&gt;
&lt;/td&gt;
                                            &lt;td data-th=&quot;Tipo de valor devuelto&quot; style=&quot;border: 1px solid rgb(187, 187, 187); color: #2a2a2a; min-width: 80px; padding: 10px 8px; vertical-align: top;&quot;&gt;&lt;div style=&quot;line-height: 18px; padding-bottom: 0px;&quot;&gt;
&lt;span class=&quot;input&quot; style=&quot;font-weight: 700;&quot;&gt;int&lt;/span&gt;
                                                &lt;/div&gt;
&lt;/td&gt;
                                        &lt;/tr&gt;
&lt;tr&gt;
                                            &lt;td data-th=&quot;Resultado de la expresión&quot; style=&quot;border: 1px solid rgb(187, 187, 187); color: #2a2a2a; min-width: 80px; padding: 10px 8px; vertical-align: top;&quot;&gt;&lt;div style=&quot;line-height: 18px; padding-bottom: 0px;&quot;&gt;
&lt;span class=&quot;input&quot; style=&quot;font-weight: 700;&quot;&gt;bigint&lt;/span&gt;
                                                &lt;/div&gt;
&lt;/td&gt;
                                            &lt;td data-th=&quot;Tipo de valor devuelto&quot; style=&quot;border: 1px solid rgb(187, 187, 187); color: #2a2a2a; min-width: 80px; padding: 10px 8px; vertical-align: top;&quot;&gt;&lt;div style=&quot;line-height: 18px; padding-bottom: 0px;&quot;&gt;
&lt;span class=&quot;input&quot; style=&quot;font-weight: 700;&quot;&gt;bigint&lt;/span&gt;
                                                &lt;/div&gt;
&lt;/td&gt;
                                        &lt;/tr&gt;
&lt;/tbody&gt;
                                &lt;/table&gt;
&lt;/div&gt;
Pero si usamos un bigint como tipo de datos de la columna a sumar, el resultado será también un &lt;b&gt;bigint&lt;/b&gt;, ampliándonos el límite hasta un valor de 2 elevado a 63 (9.223.372.036.854.775.807). Un número lo suficientemente grande como para que sea complicado de desbordar, aunque no imposible.&lt;br /&gt;
&lt;br /&gt;
Así pues, sin necesidad de cambiar el tipo de datos de nuestras columnas, podemos usar un &lt;b&gt;CAST para convertir los valores de la columna Importe a bigint&lt;/b&gt; y después realizar la operación deseada. Del siguiente modo:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SELECT SUM(CAST(Importe AS bigint))
FROM dbo.Pedidos;

SELECT AVG(CAST(Importe AS bigint))
FROM dbo.Pedidos;
&lt;/pre&gt;
&lt;br /&gt;
¡Ahora SQL Server ya nos devuelve los valores esperados!&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/5587677636224190180/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2017/08/desbordando-avg-y-sum-cuando-sql-server.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/5587677636224190180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/5587677636224190180'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2017/08/desbordando-avg-y-sum-cuando-sql-server.html' title='Desbordando AVG y SUM: Cuando SQL Server se queda sin dedos para sumar'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVSKZiVNtxmAulmZ9iZxc5gb3Qu2cYm4RWD8_LsSvZd9Ob7wjwJsLZ_1WTe2ExPuBb1RPyEm_0ytHLW-TkIgtHC9wNG9xvRLU5qLPszEM_Me6JqTadOj6DXYCvk6CIDj1scDnhulg83lEV/s72-c/1441135302_istock_000016718615_medium.jpg" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-619762784837281988</id><published>2016-06-21T21:24:00.005+02:00</published><updated>2016-06-22T08:25:30.604+02:00</updated><title type='text'>Usa el esquema en tus consultas o rompe tu código sin darte cuenta</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Hace ya algún tiempo contábamos en otra entrada de este blog la importancia que tiene &lt;a href=&quot;http://aprendiendosqlserver.blogspot.com.es/2014/05/haz-bien-tus-consultas-llama-las-cosas.html&quot;&gt;nombrar correctamente a los objetos&lt;/a&gt; de una base de datos a la hora de realizar las consultas: &lt;b&gt;siempre debemos usar el formato esquema.nombre&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Los motivos quedaban claros entonces: &lt;b&gt;evitar problemas de rendimiento&lt;/b&gt; en la compilación de las consultas debidos al proceso de resolución de nombres y &lt;b&gt;evitar errores&lt;/b&gt; si el esquema por defecto de un usuario es distinto a &quot;dbo&quot; o &quot;NULL&quot;.&lt;br /&gt;
&lt;br /&gt;
Si bien estos errores pueden ocasionar algún quebradero de cabeza, su resolución es bastante sencilla, tal y como se explica en el artículo anterior. Sin embargo, añadimos ahora un nuevo caso que podría ser más problemático, ya que podemos generar un error que pasase inadvertido, devolviendo &lt;b&gt;registros incorrectos en nuestras consultas&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Cuando trabajamos con más de un esquema -cosa que deberíamos hacer no sólo por motivos de organización de nuestros objetos, sino también para aplicar permisos sobre ellos más ágilmente- es especialmente importante prestar atención en la &lt;b&gt;definición de vistas y procedimientos almacenados&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
En ellos, deberemos &lt;b&gt;poner siempre el esquema y el nombre de los objetos&lt;/b&gt; a los que hagamos referencia, si no queremos exponer nuestro código a futuros problemas.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Abocados al cataclismo&lt;/b&gt;&lt;/h3&gt;
&lt;br /&gt;
Supongamos que en nuestra base de datos &lt;b&gt;usamos esquemas&lt;/b&gt;, en concreto &quot;&lt;b&gt;dbo&lt;/b&gt;&quot; y &quot;&lt;b&gt;web&lt;/b&gt;&quot;. En el esquema dbo tenemos &lt;b&gt;dos tablas&lt;/b&gt; &quot;Cliente&quot; y &quot;Pedido&quot;, en el esquema web añadimos ahora la &lt;b&gt;vista &lt;/b&gt;&quot;PedidosCliente&quot; e insertamos algunos registros en las tablas a modo de prueba. El script completo para crear los objetos y rellenar las tablas es el siguiente:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/eae556c5b06544cda0407cfddc9f8914.js&quot;&gt;&lt;/script&gt;

Una vez tenemos los objetos creados, ejecutamos una &lt;b&gt;simple consulta sobre la vista&lt;/b&gt;:
&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/0112cd5f9c78179027a9ff07a9f49e66.js&quot;&gt;&lt;/script&gt;

Que nos devolverá &lt;b&gt;tres resultados&lt;/b&gt;: Dos pedidos para Juan y uno para María.
&lt;br /&gt;
&lt;br /&gt;
Ahora bien, imaginemos que solamente para los clientes web necesitamos guardar más información, por ejemplo su password. Como tenemos clientes tradicionales y web, decidimos &lt;b&gt;añadir una segunda tabla Cliente, esta vez en el esquema web&lt;/b&gt;, que hará referencia a la tabla dbo.Cliente por el Codigo y extenderá la información de sus registros con la columna Password, para aquellos que vengan a través de la web. Así:
&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/e4b503e88a0ae498028740271bcbaca6.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Empieza la batalla de los esquemas&lt;/h3&gt;
&lt;br /&gt;
A estas alturas ya podemos empezar a tener &lt;b&gt;dudas sobre a qué tabla referencia nuestra vista&lt;/b&gt; web.PedidosCliente. Recordemos que habíamos referenciado a las tablas Pedido y Cliente sin usar el esquema en la definición de la vista. Así pues, ¿la vista &lt;b&gt;seguirá usando dbo.Clientes&lt;/b&gt; como hasta ahora, o bien &lt;b&gt;pasará a referenciar la nueva tabla web.Clientes&lt;/b&gt;?&lt;br /&gt;
&lt;br /&gt;
Una primera &lt;b&gt;comprobación&lt;/b&gt; que podemos hacer es, en el SQL Server Management Studio, hacer clic derecho sobre la vista y en el menú contextual seleccionar &lt;b&gt;&quot;Ver Dependencias&quot;&lt;/b&gt;.
&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiz_EvDcAEGxLMIQE26fRRj449OFXUm-140BugElNK_Dbh20gUw_zfm5HoWaGbtER9gQP5vNQYa5Dg_A1KpfPESuQoUc0jaKiiYFNeQbDI5NDx-Yhf4M1wOQoCzDeUhuA_2drheej30D1C/s1600/dependecia.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;451&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiz_EvDcAEGxLMIQE26fRRj449OFXUm-140BugElNK_Dbh20gUw_zfm5HoWaGbtER9gQP5vNQYa5Dg_A1KpfPESuQoUc0jaKiiYFNeQbDI5NDx-Yhf4M1wOQoCzDeUhuA_2drheej30D1C/s400/dependecia.JPG&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;SQL Server nos dice que la vista sigue dependiendo de dbo.Cliente&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Parece que &lt;b&gt;sigue usando la tabla dbo.Cliente&lt;/b&gt;. Para estar doblemente seguros, podemos consultar también la &lt;b&gt;definición de la vista&lt;/b&gt; &amp;nbsp;-igualmente con clic derecho sobre ella- y ver cómo está definida. Efectivamente, SQL Server parece estar seguro, &lt;b&gt;es sobre dbo.Cliente&lt;/b&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
SELECT &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;P.Numero, P.FechaPedido, C.Nombre&lt;br /&gt;
FROM &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;background-color: yellow;&quot;&gt;dbo.Pedido&lt;/span&gt; AS P INNER JOIN&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;background-color: yellow;&quot;&gt;dbo.Cliente&lt;/span&gt; AS C ON P.CodigoCliente = C.Codigo&lt;/blockquote&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
SQL Server Management Studio no dice la verdad&lt;/h3&gt;
&lt;br /&gt;
A estas alturas podemos asumir que &lt;b&gt;nuestra vista seguirá funcionando&lt;/b&gt; como si nada hubiera pasado. Para comprobarlo, ejecutemos la misma consulta del principio de esta entrada&amp;nbsp;sobre la vista. Debería devolver los mismos tres resultados, ¿verdad? Veámoslo:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Msg 207, Level 16, State 1, Procedure PedidosCliente, Line 3 [Batch Start Line 44]&lt;/i&gt;&lt;span style=&quot;background-color: yellow;&quot;&gt;&lt;i&gt;El nombre de columna &#39;Nombre&#39; no es válido.&lt;/i&gt;&lt;/span&gt;&lt;i&gt;Msg 4413, Level 16, State 1, Line 46&lt;/i&gt;&lt;i&gt;No se pudo usar la vista o función &#39;web.PedidosCliente&#39; debido a errores de enlace.&lt;/i&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;b&gt;¡Oh! ¡Oh! Hemos roto nuestra vista&lt;/b&gt; y no nos hemos dado cuenta hasta que hemos ejecutado una consulta sobre ella.&lt;br /&gt;
&lt;br /&gt;
Sin embargo, esta es la buena noticia dentro de la gravedad del problema. Ha ocurrido un error y SQL Server nos lo ha notificado. Este error &lt;b&gt;se produce porque la vista está definida dentro del esquema web&lt;/b&gt;. Al estar dentro de este esquema, pese a que el Management Studio nos insista en que la vista hace referencia a la tabla dbo.Cliente, no es así: &lt;b&gt;al crear la tabla web.Cliente, la vista hace referencia a ella&lt;/b&gt;, porque está en su mismo esquema. Como esta tabla no tiene la columna Nombre, se produce el error.&lt;br /&gt;
&lt;br /&gt;
El mismo error lo podríamos obtener si recreásemos la vista o la intentásemos modificar sin alterar la definición.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Aún puede ser peor&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;
Sí, podría serlo. Si nuestra &lt;b&gt;nueva tabla web.Cliente también tuviese un campo Nombre&lt;/b&gt; -imaginemos que queremos poner nombre de usuario web, pero llamamos a la columna Nombre- no se produciría ningún error. Simplemente &lt;b&gt;cambiaría el conjunto de resultados devuelto&lt;/b&gt;, circunstancia que podría pasar inadvertida hasta que, por ejemplo, un usuario detectase la anomalía. Por ejemplo:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/5d87cf295880b6c98119e614c8455865.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;¡Oooooh! ¡Ooooooh! ¿Ningún resultado?&lt;/b&gt; ¿Qué ha pasado con nuestros tres pedidos de Juan y María? Fácil: &lt;b&gt;la consulta sobre la vista ha funcionado&lt;/b&gt;, pero haciendo referencia a la tabla web.Cliente, donde no tenemos ningún registro. Así que la vista nos devuelve eso: ningún registro.&lt;/div&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
La solución
&lt;/h3&gt;
&lt;br /&gt;
Es sencilla: &lt;a href=&quot;http://aprendiendosqlserver.blogspot.com.es/2014/05/haz-bien-tus-consultas-llama-las-cosas.html&quot;&gt;Nombrar a los objetos por su nombre completo&lt;/a&gt;, que incluye esquema.nombre. Si en la definición de la vista original simplemente hubiésemos puesto dbo.Cliente y dbo.Pedido, no habría forma de haberla roto, ni con error ni inadvertidamente. Así:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/c3a87a6731fa86a63658c1f7cf755035.js&quot;&gt;&lt;/script&gt;

&lt;br /&gt;
Recuérdalo, &lt;b&gt;llama a las cosas por su nombre&lt;/b&gt;, o podrás tener problemas que, por muy poco probables que parezcan, ocurrirán en el momento más inoportuno. Siempre es mejor no dejarlo en manos del azar.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Con SCHEMABINDING esto no pasaría&lt;/h3&gt;
&lt;br /&gt;
Efectivamente, hay otra solución. SQL Server nos permite &lt;a href=&quot;https://msdn.microsoft.com/es-es/library/ms187956.aspx&quot;&gt;definir nuestras vistas (y funciones) con la opción SCHEMABINDING&lt;/a&gt;. Esta opción hace que no se pueda cambiar la definición de los objetos a los que hace referencia la vista (las tablas Pedido y Cliente en nuestro caso). Además, tal y como explica la MSDN, se nos obliga a usar el esquema siempre cuando definimos una vista con WITH SCHEMABINDING.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;background-color: white; color: #2a2a2a; font-family: &amp;quot;segoe ui&amp;quot; , &amp;quot;lucida grande&amp;quot; , &amp;quot;verdana&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: 13px; line-height: 18px;&quot;&gt;Cuando se utiliza SCHEMABINDING,&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;background-color: white; box-sizing: border-box; color: #2a2a2a; font-family: &amp;quot;Segoe UI&amp;quot;, &amp;quot;Lucida Grande&amp;quot;, Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 18px;&quot;&gt;select_statement&lt;/em&gt;&lt;span style=&quot;background-color: white; color: #2a2a2a; font-family: &amp;quot;segoe ui&amp;quot; , &amp;quot;lucida grande&amp;quot; , &amp;quot;verdana&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: 13px; line-height: 18px;&quot;&gt;&amp;nbsp;debe incluir los nombres de dos partes (&lt;/span&gt;&lt;em style=&quot;background-color: white; box-sizing: border-box; color: #2a2a2a; font-family: &amp;quot;Segoe UI&amp;quot;, &amp;quot;Lucida Grande&amp;quot;, Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 18px;&quot;&gt;schema&lt;/em&gt;&lt;span style=&quot;background-color: white; box-sizing: border-box; color: #2a2a2a; font-family: &amp;quot;segoe ui&amp;quot; , &amp;quot;lucida grande&amp;quot; , &amp;quot;verdana&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: 13px; font-weight: 700; line-height: 18px;&quot;&gt;.&lt;/span&gt;&lt;em style=&quot;background-color: white; box-sizing: border-box; color: #2a2a2a; font-family: &amp;quot;Segoe UI&amp;quot;, &amp;quot;Lucida Grande&amp;quot;, Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 18px;&quot;&gt;object&lt;/em&gt;&lt;span style=&quot;background-color: white; color: #2a2a2a; font-family: &amp;quot;segoe ui&amp;quot; , &amp;quot;lucida grande&amp;quot; , &amp;quot;verdana&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: 13px; line-height: 18px;&quot;&gt;) de las tablas, vistas o funciones definidas por el usuario a las que se hace referencia.&lt;/span&gt;&lt;/blockquote&gt;
Por ejemplo, si intentamos definir nuestra vista web.PedidosCliente así:&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/e05bb1a20d27c5fcfefeb7dc04590e50.js&quot;&gt;&lt;/script&gt;

Recibiremos el siguiente error:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Msg 4512, Level 16, State 3, Procedure PedidosCliente, Line 4 [Batch Start Line 27]&lt;/i&gt;&lt;i&gt;No se puede enlazar a esquema vista &#39;web.PedidosCliente&#39; porque el nombre &#39;Pedido&#39; no es válido para enlazar a esquema. Los nombres deben constar de dos partes y los objetos no pueden hacer referencia a sí mismos&lt;/i&gt;.&lt;/blockquote&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/619762784837281988/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2016/06/usa-el-esquema-en-tus-consultas-o-rompe.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/619762784837281988'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/619762784837281988'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2016/06/usa-el-esquema-en-tus-consultas-o-rompe.html' title='Usa el esquema en tus consultas o rompe tu código sin darte cuenta'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiz_EvDcAEGxLMIQE26fRRj449OFXUm-140BugElNK_Dbh20gUw_zfm5HoWaGbtER9gQP5vNQYa5Dg_A1KpfPESuQoUc0jaKiiYFNeQbDI5NDx-Yhf4M1wOQoCzDeUhuA_2drheej30D1C/s72-c/dependecia.JPG" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-824821935148503528</id><published>2015-11-09T14:13:00.001+01:00</published><updated>2015-11-09T14:14:24.552+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="UNION"/><category scheme="http://www.blogger.com/atom/ns#" term="UNION ALL"/><title type='text'>UNION vs UNION ALL: Entiende las diferencias</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
SQL Server ofrece el operador &lt;b&gt;UNION&lt;/b&gt; para, &lt;a href=&quot;https://msdn.microsoft.com/es-es/library/ms180026(v=sql.120).aspx&quot;&gt;según la MSDN&lt;/a&gt;, &quot;&lt;b&gt;combinar los resultados de dos o más consultas&lt;/b&gt; en un solo conjunto de resultados que incluye todas las filas que pertenecen a las consultas de la unión.&quot;&lt;br /&gt;
&lt;br /&gt;
Para que el motor de base de datos pueda combinar el resultado de distintas consultas, éstas deben respetar el número y orden de las columnas implicadas. Asimismo, las columnas equivalentes en posición deben serlo también compatibles en tipos de datos.&lt;br /&gt;
&lt;br /&gt;
El operador UNION presenta un modificador o argumento: &lt;b&gt;ALL&lt;/b&gt;. Éste se escribe a continuación de UNION, así: UNION ALL. Cuando se especifica, SQL Server devuelve todas las filas de todas las consultas combinadas, incluyendo posibles duplicados.&lt;br /&gt;
&lt;br /&gt;
Ahí radica justamente &lt;b&gt;la diferencia entre UNION y UNION ALL&lt;/b&gt;: El operador de &lt;b&gt;unión elimina las filas duplicadas&lt;/b&gt; cuando combina los resultados de las consultas implicadas. Sin embargo, &lt;b&gt;con el argumento ALL, los duplicados se mantienen&lt;/b&gt;.&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
¿Cuándo uso UNION y cuándo UNION ALL?&lt;/h3&gt;
&lt;div&gt;
El primer criterio de selección está claro: si no nos importa que haya registro repetidos o los necesitamos, entonces debemos usar UNION ALL. Si queremos asegurarnos de que no haya registros repetidos, usaremos UNION.&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/h4&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
¿Y qué pasa si estoy seguro de que no hay registros repetidos?&lt;/h4&gt;
&lt;div&gt;
En ese caso, por normal general, será mucho más eficiente usar UNION ALL, ya que le ahorramos a SQL Server la necesidad de comprobar y descartar posibles duplicados. Así que, salvo excepciones, salvo que explícitamente queramos eliminar duplicados, será más eficiente para SQL Server el uso de UNION ALL.&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/824821935148503528/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2015/11/union-vs-union-all-entiende-las.html#comment-form' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/824821935148503528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/824821935148503528'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2015/11/union-vs-union-all-entiende-las.html' title='UNION vs UNION ALL: Entiende las diferencias'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-4362289935709012778</id><published>2015-01-28T10:46:00.001+01:00</published><updated>2015-01-28T10:52:38.575+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="configuración"/><category scheme="http://www.blogger.com/atom/ns#" term="DMV"/><category scheme="http://www.blogger.com/atom/ns#" term="Management Studio"/><category scheme="http://www.blogger.com/atom/ns#" term="propietario"/><category scheme="http://www.blogger.com/atom/ns#" term="vistas de catálogo"/><category scheme="http://www.blogger.com/atom/ns#" term="vistas de sistema"/><title type='text'>Cómo averiguar el propietario (Owner) de una base de datos en SQL Server</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
En ocasiones necesitamos conocer quién es el &lt;b&gt;propietario de una base de datos&lt;/b&gt;. Normalmente podemos acceder a esta información a través del &lt;b&gt;SQL Server Management Studio&lt;/b&gt;, consultando las propiedades de la base de datos.&lt;br /&gt;
&lt;br /&gt;
Para ello, buscamos la base de datos que queramos consultar en el árbol de bases de datos del Object Explorer y hacemos clic derecho sobre ella. A continuación, elegimos la última opción del menú contextual que nos aparece: &lt;b&gt;Propiedades&lt;/b&gt;. Veremos esta ventana:&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIF1V-sWat9EwTRAIgdFQm_7ax6aVhnoeXktgFPAdV8MjsfocluOHcgcOWrAm54LFO3u2Dnu1jkIdzTx9I-0HYhEA3htzf-jQVpl3BUOf1Aai5Pj1zIwi_saMZTJDIBZ5aM8NJ0c2LzrzS/s1600/DatabaseProperties.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;Propiedades de una base de datos, que incluyen el propietario (en amarillo)&quot; border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIF1V-sWat9EwTRAIgdFQm_7ax6aVhnoeXktgFPAdV8MjsfocluOHcgcOWrAm54LFO3u2Dnu1jkIdzTx9I-0HYhEA3htzf-jQVpl3BUOf1Aai5Pj1zIwi_saMZTJDIBZ5aM8NJ0c2LzrzS/s1600/DatabaseProperties.PNG&quot; height=&quot;300&quot; title=&quot;Propiedades de una base de datos, que incluyen el propietario (en amarillo)&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Propiedades de una base de datos, que incluyen el propietario (en amarillo)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Sin embargo, en ocasiones no tenemos acceso a esta ventana de propiedades o, simplemente, queremos consultar el propietario de todas las bases de datos de un servidor. Para ello disponemos del siguiente &lt;b&gt;script T-SQL&lt;/b&gt;, que nos proporcionará la información deseada:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/ce3092cb244b51cfa7a4.js&quot;&gt;&lt;/script&gt;

La primera columna nos dirá el propietario de la base de datos (en concreto, su &lt;i&gt;login&lt;/i&gt; o nombre de usuario). A partir de este &lt;i&gt;script&lt;/i&gt;, podemos filtrar por base de datos, mediante el campo &quot;name&quot;:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/058a0c30e361e6a7ebd5.js&quot;&gt;&lt;/script&gt;

O podemos conocer todas las bases de datos cuyo propietario sea un login concreto, aplicando de nuevo al campo &quot;owner_sid&quot; la función &lt;a href=&quot;https://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&amp;amp;l=EN-US&amp;amp;k=k(SUSER_SNAME_TSQL);k(SQL12.SWB.TSQLRESULTS.F1);k(SQL12.SWB.TSQLQUERY.F1);k(MISCELLANEOUSFILESPROJECT);k(DevLang-TSQL)&amp;amp;rd=true&quot;&gt;suser_sname&lt;/a&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/d403573abcd31f5a5ebb.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/4362289935709012778/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2015/01/como-averiguar-el-propietario-owner-de.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/4362289935709012778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/4362289935709012778'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2015/01/como-averiguar-el-propietario-owner-de.html' title='Cómo averiguar el propietario (Owner) de una base de datos en SQL Server'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIF1V-sWat9EwTRAIgdFQm_7ax6aVhnoeXktgFPAdV8MjsfocluOHcgcOWrAm54LFO3u2Dnu1jkIdzTx9I-0HYhEA3htzf-jQVpl3BUOf1Aai5Pj1zIwi_saMZTJDIBZ5aM8NJ0c2LzrzS/s72-c/DatabaseProperties.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-5452838014348216264</id><published>2014-10-27T08:58:00.000+01:00</published><updated>2014-10-27T12:08:14.703+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="DELETE"/><category scheme="http://www.blogger.com/atom/ns#" term="in-memory OLTP"/><category scheme="http://www.blogger.com/atom/ns#" term="INSERT"/><category scheme="http://www.blogger.com/atom/ns#" term="networking"/><category scheme="http://www.blogger.com/atom/ns#" term="Power BI"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Saturday"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014"/><category scheme="http://www.blogger.com/atom/ns#" term="UPDATE"/><title type='text'>Notas del SQL Saturday Barcelona (#338): Conocimiento compartido</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot;&gt;
Volvemos de Barcelona con la sensación de haber sido partícipes de una experiencia enriquecedora: el primer &lt;b&gt;SQL Saturday&lt;/b&gt; celebrado en España ha sido todo un éxito.&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
La encomiable labor organizativa del grupo &lt;b&gt;PASS España&lt;/b&gt; -encabezados por &lt;a href=&quot;https://twitter.com/rpertusa&quot;&gt;&lt;b&gt;Rubén Pertusa&lt;/b&gt;&lt;/a&gt;-, la generosidad a la hora de compartir su conocimiento de los expertos venidos de diversos países para realizar sus excelentes ponencias y el entusiasmo de todos los profesionales registrados, allí reunidos durante &lt;b&gt;más de 10 horas de sesiones&lt;/b&gt;, con un gran afán por compartir y aprender han hecho del SQL Saturday Barcelona un evento del que salimos con un &lt;b&gt;bagaje positivo y muchas ganas de repetir&lt;/b&gt;.&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu4ZZ-ebQSfdY5mLFOKEXBB03CA2l4-1alCjuOAFg6m63eZsnCrRrSy6Yslh3OBN_cI0xoxloZBMThEK2KKVXG3e-BJc-D-Y1XQ07e-2j99awaFUaEAj9JnD1tADvu7p2lCy24l6ne9BOq/s1600/sqlsat338_web.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu4ZZ-ebQSfdY5mLFOKEXBB03CA2l4-1alCjuOAFg6m63eZsnCrRrSy6Yslh3OBN_cI0xoxloZBMThEK2KKVXG3e-BJc-D-Y1XQ07e-2j99awaFUaEAj9JnD1tADvu7p2lCy24l6ne9BOq/s1600/sqlsat338_web.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
Como bien expuso &lt;a href=&quot;https://twitter.com/FernanSQL&quot;&gt;&lt;b&gt;Fernando G. Guerrero&lt;/b&gt;&lt;/a&gt;, CEO de &lt;a href=&quot;https://twitter.com/solidq&quot;&gt;SolidQ&lt;/a&gt; -uno de los &lt;i&gt;sponsors&lt;/i&gt; del evento-, &lt;b&gt;&quot;la curiosidad es lo que nos mueve&quot;&lt;/b&gt;. El apetito por aprender, las ganas de compartir experiencias y conocer a quienes también las viven son el motor de los SQL Saturday. Nada más acertado que el lema de &lt;i&gt;&lt;b&gt;&quot;Share what you know, learn what you don&#39;t&quot;&lt;/b&gt;&lt;/i&gt; (Comparte lo que sabes, aprende lo que no).&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
Nuestro sábado dio comienzo poco después de las ocho y media de la mañana. Tras el pertinente registro, llegaba la presentación del evento.&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
La primera sensación fue de sorpresa, pues el número de profesionales inscrito, dispuestos a sacrificar su tiempo libre para no perderse la cita -a centenares de kilómetros de su hogar, en muchos casos-, era elevado.&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
Tras la bienvenida en uno de los salones de actos del &lt;b&gt;IQS&lt;/b&gt; (lugar donde se desarrollaría la jornada), comenzaban las sesiones. Distribuidas entre tres salas, las rutas a elegir eran claras: Business Intelligence, Big Data o DBA (y developers, añadiríamos).&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
Escogimos, por supuesto, la que más se ajustaba a nuestro perfil, la tercera de ellas. Comenzamos la mañana aprendiendo muchas cosas nuevas sobre &lt;b&gt;SQL Server 2014&lt;/b&gt;, de la mano de &lt;a href=&quot;https://twitter.com/enriquecatala&quot;&gt;&lt;b&gt;Enrique Catalá&lt;/b&gt;&lt;/a&gt;.&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
No entraremos en detalles técnicos, puesto que no es el propósito de esta entrada en la bitácora, pero las &lt;b&gt;Transacciones de Durabilidad Diferida&lt;/b&gt; enseguida captaron nuestra atención. Ya había merecido la pena el esfuerzo realizado por estar presente.&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
La segunda sesión, también en manos de Enrique, nos dejó con ganas de más. El tiempo destinado a explicar los &lt;b&gt;planes de ejecución&lt;/b&gt; -que nos explican qué hace el motor de bases de datos para devolvernos lo que le pedimos- fue a todas luces escaso. Es un tema que da para muchas horas, y que conviene conocer a la perfección. Por cierto, Enrique sólo lo mencionó de pasada porque se quedó sin tiempo para más: si has de verte las caras con planes de ejecución, no dudes en usar &lt;a href=&quot;http://www.sqlsentry.com/products/plan-explorer/sql-server-query-view&quot;&gt;SQL Sentry Plan Explorer&lt;/a&gt;.&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
Llegó el tiempo para el primer descanso. Un café y la primera oportunidad para conversar con compañeros de fatigas. Allí conocimos a &lt;b&gt;&lt;a href=&quot;http://es.linkedin.com/pub/eduardo-burillo/13/890/972&quot;&gt;Eduardo Burillo&lt;/a&gt;&lt;/b&gt;, alicantino él, con el que fue un placer compartir inquietudes.&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
Dos sesiones más antes de comer: En la primera,&amp;nbsp;&lt;a href=&quot;https://twitter.com/SergeyOlontsev&quot;&gt;&lt;b&gt;Sergey Olontsev&lt;/b&gt;&lt;/a&gt; nos habló de una &lt;b&gt;utopía&lt;/b&gt; en &quot;Cómo sacar provecho de &lt;b&gt;In-Memory OLTP (Hekaton)&lt;/b&gt; en nuestras aplicaciones&quot;. Imposible. No se puede. Parece que el afán por competir con otras soluciones para Big Data ha provocado el parto prematuro de Hekaton. SQL Server 2014 salió mucho antes de que esta tecnología estuviese madura. Si es que algún día lo está. Habrá que estar pendientes de su evolución en próximas ediciones. Por ahora solamente alguna aplicación de nuevo cuño y con finalidad muy específica podría sacarle partido sin sufrir alguna se sus casi infinitas restricciones. Eso, y el rayo de luz final que supuso conocer la existencia de una alternativa en memoria a las tablas temporales y variables tipo tabla.&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
Llegaba el turno después para &lt;a href=&quot;https://twitter.com/mauridb&quot;&gt;&lt;b&gt;Davide Mauro&lt;/b&gt;&lt;/a&gt;, hablándonos de un tema en el que somos más bien profanos: &quot;Cómo elegir el hardware adecuado para SQL Server&quot;. Apuntamos algunas cosas interesantes, como las herramientas &lt;a href=&quot;http://www.tpc.org/&quot; style=&quot;font-weight: bold;&quot;&gt;TPC&lt;/a&gt;&amp;nbsp;(&lt;i&gt;Transaction Processing Performance Council&lt;/i&gt;) para banco de pruebas. Las usaremos.&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
Tras la hora de la comida, aún restaban tres sesiones más. Descubrimos el potencial de &lt;b&gt;Power BI&lt;/b&gt;, de la mano &lt;a href=&quot;https://twitter.com/SQLBeat&quot;&gt;&lt;b&gt;Rodney Landrum&lt;/b&gt;&lt;/a&gt; como antesala a otra de las sesiones más interesantes del día, de la mano del divertido alemán &lt;a href=&quot;https://twitter.com/dbBerater&quot;&gt;&lt;b&gt;Uwe Ricken&lt;/b&gt;&lt;/a&gt;. Su charla sobre lo que ocurre en las entrañas de SQL Server -esto es, a nivel de páginas de datos- cada vez que modificamos datos mediante instrucciones &lt;b&gt;INSERT, UPDATE y DELETE&lt;/b&gt; fue realmente reveladora. No hubo tiempo para completarla, pero nos sumergió de lleno en lo que ocurre cuando ejecutamos dichas sentencias.&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
Finalizamos el día con la sesión más relajada del sábado. &lt;a href=&quot;https://twitter.com/qwalgrande&quot;&gt;&lt;b&gt;Alberto López Grande&lt;/b&gt;&lt;/a&gt; nos propuso una reflexión, desarrollada en un agradable debate colectivo, sobre el día a día del &lt;b&gt;DBA&lt;/b&gt;, centrada en el desafío que supone mantener los servidores en las versiones más recientes para entornos productivos.&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot;&gt;
Las interesantes intervenciones de los allí presentes reflejó a la perfección el propósito y espíritu de los SQL Saturday: &lt;b&gt;participar, compartir, debatir&lt;/b&gt;. En resumen, &lt;b&gt;aprender&lt;/b&gt;. SQL Saturdays que, esperamos, se instauren y se conviertan en costumbre, no sólo en Barcelona, sino en cualquier ciudad donde los profesionales que trabajamos con SQL Server queramos seguir compartiendo conocimiento.&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/5452838014348216264/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/10/notas-del-sql-saturday-barcelona-338.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/5452838014348216264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/5452838014348216264'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/10/notas-del-sql-saturday-barcelona-338.html' title='Notas del SQL Saturday Barcelona (#338): Conocimiento compartido'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu4ZZ-ebQSfdY5mLFOKEXBB03CA2l4-1alCjuOAFg6m63eZsnCrRrSy6Yslh3OBN_cI0xoxloZBMThEK2KKVXG3e-BJc-D-Y1XQ07e-2j99awaFUaEAj9JnD1tADvu7p2lCy24l6ne9BOq/s72-c/sqlsat338_web.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-6525315802954268058</id><published>2014-07-04T12:04:00.003+02:00</published><updated>2014-07-07T10:24:26.062+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="best practices"/><category scheme="http://www.blogger.com/atom/ns#" term="buenas prácticas"/><category scheme="http://www.blogger.com/atom/ns#" term="inyección"/><category scheme="http://www.blogger.com/atom/ns#" term="seguridad"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><category scheme="http://www.blogger.com/atom/ns#" term="vulnerabilidad"/><title type='text'>Humor y SQL Server: inyección SQL y cómo evitarla (no llames a tu hijo DROP TABLE)</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
El portal &lt;a href=&quot;http://xkcd.com/327/&quot;&gt;xkcd&lt;/a&gt; publica esta viñeta sobre &lt;b&gt;inyección de código en SQL Server&lt;/b&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgag4MOptx2wIAlbzRiriwpAe8DponURwljLCgz-IlpHB_xAHkSAxZI4XMbGsp4d6Gj68L0vWSTCga3uDbva7ZNFVfqgxENmE0CgGgZUKZkYfbFYIB68H6lhkdmjJv67CIP38aBNAfhKSFh/s1600/exploits_of_a_mom.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;Inyección en SQL Server&quot; border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgag4MOptx2wIAlbzRiriwpAe8DponURwljLCgz-IlpHB_xAHkSAxZI4XMbGsp4d6Gj68L0vWSTCga3uDbva7ZNFVfqgxENmE0CgGgZUKZkYfbFYIB68H6lhkdmjJv67CIP38aBNAfhKSFh/s1600/exploits_of_a_mom.png&quot; height=&quot;168&quot; title=&quot;Inyección en SQL Server&quot; width=&quot;550&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Los peligros de llamar a tu hijo DROP TABLE&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Tratado con gran sentido del &lt;b&gt;humor&lt;/b&gt;, esta cómica situación nos pone en alerta frente a la &lt;a href=&quot;http://es.wikipedia.org/wiki/Inyecci%C3%B3n_SQL&quot;&gt;inyección de código SQL Server&lt;/a&gt;, que puede suponer una &lt;b&gt;vulnerabilidad &lt;/b&gt;seria para nuestras bases de datos.&lt;br /&gt;
&lt;br /&gt;
Una aplicación que no compruebe los datos que en ella se introducen a través de aplicaciones externas está &lt;b&gt;expuesta al desastre&lt;/b&gt;. En el cómic se introduce una instrucción &lt;b&gt;DROP TABLE&lt;/b&gt; en medio del supuesto nombre de un niño inscrito en un colegio. Al introducir el falso nombre en el sistema informático del centro, el resultado es catastrófico: &lt;b&gt;la tabla de estudiantes es eliminada por completo&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
La &lt;a href=&quot;http://es.wikipedia.org/wiki/Inyecci%C3%B3n_SQL&quot;&gt;Wikipedia&lt;/a&gt; presenta un &lt;b&gt;ejemplo &lt;/b&gt;similar para demostrar en qué consiste la inyección SQL Server, así como diversas soluciones a adoptar, dependiendo del lenguaje de programación de la aplicación:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px; margin-bottom: 0.5em; margin-top: 0.5em;&quot;&gt;
&quot;Por ejemplo, asumiendo que el siguiente código reside en una&amp;nbsp;&lt;a href=&quot;http://es.wikipedia.org/wiki/Aplicaci%C3%B3n_web&quot; style=&quot;background: none; color: #0b0080; text-decoration: none;&quot; title=&quot;Aplicación web&quot;&gt;aplicación web&lt;/a&gt;&amp;nbsp;y que existe un parámetro &quot;nombreUsuario&quot; que contiene el nombre de usuario a consultar, una inyección SQL se podría provocar de la siguiente forma:&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px; margin-bottom: 0.5em; margin-top: 0.5em;&quot;&gt;
&lt;span style=&quot;background-color: #f3f3f3;&quot;&gt;El código SQL original y&amp;nbsp;&lt;i&gt;vulnerable&lt;/i&gt;&amp;nbsp;es:&lt;br /&gt;consulta := &quot;&lt;span style=&quot;color: green;&quot;&gt;SELECT * FROM usuarios WHERE nombre = &#39;&lt;/span&gt;&quot; + &lt;span style=&quot;color: blue;&quot;&gt;nombreUsuario&lt;/span&gt; + &quot;&lt;span style=&quot;color: green;&quot;&gt;&#39;;&lt;/span&gt;&quot;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px; margin-bottom: 0.5em; margin-top: 0.5em;&quot;&gt;
Si el operador escribe un nombre, por ejemplo &quot;Alicia&quot;, nada anormal sucederá, la aplicación generaría una sentencia SQL similar a la siguiente, que es perfectamente correcta, en donde se seleccionarían todos los registros con el nombre &quot;Alicia&quot; en la base de datos:&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px; margin-bottom: 0.5em; margin-top: 0.5em;&quot;&gt;
&lt;span style=&quot;color: green;&quot;&gt;&lt;span style=&quot;background-color: #f3f3f3;&quot;&gt;SELECT * FROM usuarios WHERE nombre = &#39;&lt;span style=&quot;color: blue;&quot;&gt;Alicia&lt;/span&gt;&#39;;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px; margin-bottom: 0.5em; margin-top: 0.5em;&quot;&gt;
Pero si un operador malintencionado escribe como nombre de usuario a consultar:&lt;br /&gt;
&quot;&lt;code style=&quot;background-color: #f9f9f9; font-family: monospace, Courier;&quot;&gt;&lt;span style=&quot;color: blue;&quot;&gt;Alicia&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;&#39;; DROP TABLE usuarios; SELECT * FROM datos WHERE nombre LIKE &#39;%&lt;/span&gt;&lt;/code&gt;&quot;&lt;br /&gt;
(sin las comillas externas), se generaría la siguiente consulta SQL, (el color verde es lo que pretende el programador, el azul es el dato, y el rojo, el código SQL inyectado):&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px; margin-bottom: 0.5em; margin-top: 0.5em;&quot;&gt;
&lt;span style=&quot;background-color: #f3f3f3;&quot;&gt;&lt;span style=&quot;color: green;&quot;&gt;SELECT * FROM usuarios WHERE nombre = &#39;&lt;/span&gt;&lt;span style=&quot;color: blue;&quot;&gt;Alicia&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;&#39;;
DROP TABLE usuarios;
SELECT * FROM datos WHERE nombre LIKE &#39;%&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;DROP TABLE usuarios;&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;SELECT * FROM datos WHERE nombre LIKE &#39;%&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;&lt;span style=&quot;background-color: #f3f3f3;&quot;&gt;&#39;;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot; style=&quot;background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px; margin-bottom: 0.5em; margin-top: 0.5em;&quot;&gt;
En la base de datos se ejecutaría la consulta en el orden dado, se seleccionarían todos los registros con el nombre &#39;Alicia&#39;, se borraría la tabla &#39;usuarios&#39; y finalmente se seleccionaría toda la tabla &quot;datos&quot;, que no debería estar disponible para los usuarios web comunes.&quot;&lt;/blockquote&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/6525315802954268058/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/07/humor-y-sql-server-inyeccion-sql-y-como.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/6525315802954268058'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/6525315802954268058'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/07/humor-y-sql-server-inyeccion-sql-y-como.html' title='Humor y SQL Server: inyección SQL y cómo evitarla (no llames a tu hijo DROP TABLE)'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgag4MOptx2wIAlbzRiriwpAe8DponURwljLCgz-IlpHB_xAHkSAxZI4XMbGsp4d6Gj68L0vWSTCga3uDbva7ZNFVfqgxENmE0CgGgZUKZkYfbFYIB68H6lhkdmjJv67CIP38aBNAfhKSFh/s72-c/exploits_of_a_mom.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-1339831916995500847</id><published>2014-07-03T15:55:00.003+02:00</published><updated>2014-07-03T15:56:48.065+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aprendizaje"/><category scheme="http://www.blogger.com/atom/ns#" term="eventos"/><category scheme="http://www.blogger.com/atom/ns#" term="SQLSaturday"/><title type='text'>¡Nos vemos en el SQLSaturday Barcelona!</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
¡Por primera vez llegan a España los famosos eventos &lt;b&gt;SQLSaturday&lt;/b&gt;! Será en &lt;b&gt;Barcelona&lt;/b&gt;, el próximo sábado 25 de octubre de 2014.&lt;br /&gt;
&lt;br /&gt;
Ya me he &lt;b&gt;registrado&lt;/b&gt; en el evento. Será una buena oportunidad para conocer a otros profesionales de SQL Server y compartir experiencias y conocimiento, todo ello mientras aprendemos de los mejores expertos, incluidos algunos &lt;b&gt;MVP&lt;/b&gt; y &lt;b&gt;MCM&lt;/b&gt; de Microsoft, en las diferentes sesiones programadas.&lt;br /&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;es&quot;&gt;
&lt;a href=&quot;https://twitter.com/jaimeml&quot;&gt;@jaimeml&lt;/a&gt; is attending SQLSaturday #338 - Barcelona 2014 &lt;a href=&quot;https://twitter.com/hashtag/sqlsatBarcelona?src=hash&quot;&gt;#sqlsatBarcelona&lt;/a&gt;&lt;br /&gt;
— PASS SQLSaturday (@sqlsat) &lt;a href=&quot;https://twitter.com/sqlsat/statuses/482927818561425408&quot;&gt;junio 28, 2014&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; charset=&quot;utf-8&quot; src=&quot;//platform.twitter.com/widgets.js&quot;&gt;&lt;/script&gt;

SQLSaturday es un &lt;b&gt;evento gratuito de un día de duración&lt;/b&gt; para profesionales y futuros profesionales relacionados con SQL Server, Big Data y Business Intelligence; organizado por la &lt;a href=&quot;http://www.sqlpass.org/&quot;&gt;Asociación de Profesionales de SQL Server (PASS)&lt;/a&gt;.
Se han celebrado más de 300 eventos SQLSaturday alrededor de todo el mundo (el de Barcelona será el 338) y ésta va a ser la primera edición en España. El plazo de &lt;a href=&quot;http://www.sqlsaturday.com/338/register.aspx&quot;&gt;registro&lt;/a&gt; lleva abierto algunos días, en los que ya se han inscrito más de 70 asistentes.&lt;br /&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;es&quot;&gt;
Ya tenemos más de 70 asistentes registrados y sesiones de 13 MVPs, 3 MCMs...¡Qué acogida! &lt;a href=&quot;https://twitter.com/hashtag/sqlsatBarcelona?src=hash&quot;&gt;#sqlsatBarcelona&lt;/a&gt; Regístrate &lt;a href=&quot;http://t.co/v5ghJGvHwp&quot;&gt;http://t.co/v5ghJGvHwp&lt;/a&gt;&lt;br /&gt;
— SQL Sat Barcelona (@sqlsatbarcelona) &lt;a href=&quot;https://twitter.com/sqlsatbarcelona/statuses/483530571533254656&quot;&gt;junio 30, 2014&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; charset=&quot;utf-8&quot; src=&quot;//platform.twitter.com/widgets.js&quot;&gt;&lt;/script&gt;

Tal y como afirma &lt;a href=&quot;http://www.sqlsaturday.com/338/eventhome.aspx&quot;&gt;la web del evento&lt;/a&gt;, dentro de la multitud de temas que se van a tratar en las sesiones, podremos encontrar:&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Motor relacional (optimización, bloqueos, índices...)&lt;/li&gt;
&lt;li&gt;Alta disponibilidad&lt;/li&gt;
&lt;li&gt;SQL Server 2014&lt;/li&gt;
&lt;li&gt;Big Data (HDinsight, Pig, Hive...)&lt;/li&gt;
&lt;li&gt;Power BI&lt;/li&gt;
&lt;li&gt;Integration Services, Analysis Services, Reporting&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Powershell&amp;nbsp;&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
Habrá sesiones en inglés y en castellano. Los ponentes han ido enviando sus propuestas de sesiones, que aparecen &lt;a href=&quot;http://www.sqlsaturday.com/338/schedule.aspx&quot;&gt;listadas en la web del evento&lt;/a&gt;. En próximas fechas se publicará el calendario final del evento, para que cada asistente se programe aquéllas a las que tiene más interés en asistir.&lt;br /&gt;
&lt;br /&gt;
Además, el evento &lt;a href=&quot;http://www.sqlsaturday.com/338/networking.aspx&quot;&gt;favorece el networking&lt;/a&gt; entre profesionales de SQL Server, facilitando un lugar común en el que conocer al resto de asistentes mediante sus perfiles de &lt;a href=&quot;https://www.linkedin.com/profile/view?id=68726647&quot;&gt;LinkedId&lt;/a&gt; o sus cuentas de &lt;a href=&quot;https://twitter.com/jaimeml&quot;&gt;Twitter&lt;/a&gt;.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/1339831916995500847/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/07/nos-vemos-en-el-sqlsaturday-barcelona.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/1339831916995500847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/1339831916995500847'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/07/nos-vemos-en-el-sqlsaturday-barcelona.html' title='¡Nos vemos en el SQLSaturday Barcelona!'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-6345527689488913806</id><published>2014-05-23T16:06:00.002+02:00</published><updated>2014-05-23T16:10:27.113+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="consultas"/><category scheme="http://www.blogger.com/atom/ns#" term="esquemas"/><category scheme="http://www.blogger.com/atom/ns#" term="fully qualified name"/><category scheme="http://www.blogger.com/atom/ns#" term="name resolution"/><category scheme="http://www.blogger.com/atom/ns#" term="recomendaciones"/><category scheme="http://www.blogger.com/atom/ns#" term="rendimiento"/><title type='text'>Haz bien tus consultas: Llama a las cosas por su nombre (y esquema)</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
La MSDN nos explica cual es la forma correcta de referenciar a los objetos en tus consultas, y es la siguiente:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Esquema.Nombre&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
¿Por qué? Hay diversos motivos y, aunque parezca algo trivial, pueden evitarnos acceder a objetos incorrectos, errores en consultas para usuarios de la base de datos distintos al que creó el objeto e incluso &lt;b&gt;problemas de rendimiento&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;u&gt;
Resolución de nombres&lt;/u&gt;&lt;/h3&gt;
Cuando ejecutamos una consulta, el servidor SQL realiza un proceso llamado &lt;b&gt;resolución de nombres (&lt;i&gt;name resolution&lt;/i&gt;, en inglés)&lt;/b&gt; para identificar los objetos referidos en ella.&lt;br /&gt;
&lt;br /&gt;
Si identificamos cada objeto por su &lt;b&gt;nombre completo (&lt;i&gt;fully qualified name&lt;/i&gt;)&lt;/b&gt;, SQL sabrá determinar inmediatamente a qué objeto nos referimos y si existe o no. Por el contrario, si solamente especificamos su nombre, el motor de bases de datos tendrá que &lt;b&gt;determinar a qué objeto nos referimos&lt;/b&gt;. Para ello usará el &lt;i&gt;default schema&lt;/i&gt; del usuario conectado.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;u&gt;
Esquema por defecto o Default schema&lt;/u&gt;&lt;/h3&gt;
Cada usuario de una base de datos puede tener un esquema por defecto (desde SQL Server 2008 R2, también los grupos de Windows. Esto es importante, como veremos a continuación). &lt;b&gt;Si para un usuario no está definido el esquema por defecto, se asume que éste es &quot;dbo&quot;&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Para &lt;b&gt;comprobar el esquema por defecto&lt;/b&gt; que tienen los usuarios de nuestra base de datos, podemos ejecutar la siguiente consulta:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/8fbbdb6cf51a60531aca.js&quot;&gt;&lt;/script&gt;

Cuando SQL tiene que resolver un nombre de objeto sin esquema, primero busca en el esquema por defecto del usuario actual. Si no lo encuentra ahí, entonces lo buscará en el esquema dbo. Si tampoco estuviera ahí, la consulta fallaría.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Es conveniente que el esquema por defecto de todos los usuarios y grupos sea dbo&lt;/b&gt; o no esté definido (NULL), salvo que haya razones muy concretas para que no sea así.&lt;br /&gt;
&lt;br /&gt;
Cuando el esquema por defecto de un usuario es otro, se dan los problemas descritos a continuación.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;u&gt;
Problemas relacionados con el esquema por defecto&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Si un usuario tiene un esquema por defecto que no es dbo, cuando cree nuevos objetos en la base de datos, estos se llamarán esquema_usuario.nombre_objeto. Si cualquier otro usuario con un esquema por defecto distinto hace una consulta sobre dicho objeto sin especificar su esquema, &lt;b&gt;la consulta fallará&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;Si se crea un objeto con el esquema dbo, pero un usuario con el esquema por defecto distinto de dbo hace una consulta se hace sin especificar el esquema, SQL buscará el objeto primero en su esquema por defecto y después en dbo (name resolution). Esto puede producir &lt;b&gt;problemas de rendimiento&lt;/b&gt;. Si bien estos problemas no serían dramáticos, se han medido que &lt;a href=&quot;http://blogs.msdn.com/b/mssqlisv/archive/2007/03/23/upgrading-to-sql-server-2005-and-default-schema-setting.aspx&quot;&gt;entre el 10% y el 15% del proceso de ejecución de una consulta&lt;/a&gt; puede ser debido a la resolución de nombres.&lt;/li&gt;
&lt;/ul&gt;
Los esquemas existen desde SQL Server 2005 y ofrecen multitud de posibilidades de organización y control de seguridad sobre nuestros objetos. Sin embargo, aunque no los uses y todos tus objetos estén en el esquema dbo, que es el por defecto, es posible que el esquema por defecto de alguno de tus usuarios no sea dbo.&lt;br /&gt;
&lt;br /&gt;
Para &lt;b&gt;comprobar qué usuarios no tienen por defecto el esquema &quot;dbo&quot;&lt;/b&gt;, puedes ejecutar el siguiente &lt;i&gt;script&lt;/i&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/284afcb5f125952e9fcb.js&quot;&gt;&lt;/script&gt;

La &lt;b&gt;MSDN&lt;/b&gt; explica muy bien todo este proceso en su sección &lt;a href=&quot;http://msdn.microsoft.com/es-es/library/dd283095%28v=sql.100%29.aspx&quot;&gt;&quot;How to Refer to Objects&quot;&lt;/a&gt; (como referirse a objetos) del artículo -en inglés- &lt;a href=&quot;http://msdn.microsoft.com/es-es/library/dd283095%28v=sql.100%29.aspx&quot;&gt;&quot;SQL Server Best Practices - Implementation of Database Object&quot;&lt;/a&gt; (Prácticas recomendadas en SQL Server - Implementación de Objetos de Base de Datos):&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Es siempre una buena práctica referirse a los objetos de la base de datos por el nombre de esquema y el nombre de objeto separados por un punto.&lt;br /&gt;
...&lt;br /&gt;
El proceso [de resolución de nombres] puede mejorarse usando el nombre completo o configurando correctamente el esquema por defecto del usuario, eliminando un proceso innecesario de comprobación de propiedad. Esto puede mejorar considerablemente el rendimiento en sistemas utilizados intensivamente.&lt;/blockquote&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;u&gt;
Problema adicional con grupos de usuarios de Windows en versiones anteriores a SQL Server 2012&lt;/u&gt;&lt;/h3&gt;
Si asignas permisos a tus bases de datos a grupos de usuarios de Windows en versiones de SQL Server anteriores a 2012, cuando los usuarios de dichos grupos accedan a la base de datos, &lt;a href=&quot;https://connect.microsoft.com/SQLServer/feedback/details/328585/default-schema-for-windows-group&quot;&gt;SQL Server les creará un usuario cuyo esquema por defecto será su login de Windows&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Esto hace que &lt;b&gt;el problema descrito de resolución de nombres se agrave especialmente en este tipo de entornos con versiones de SQL Server 2005 o 2008&lt;/b&gt;, en los que el administrador de bases de datos gestione los permisos de esta manera.&lt;br /&gt;
&lt;br /&gt;
Por &lt;b&gt;ejemplo&lt;/b&gt;: Si el usuario MIDOMINIO\Usuario1 pertenece al grupo MIDOMINIO\Grupo1 y el Usuario1 se conecte por primera vez a una base de datos para la que tenga permisos asignados a través del Grupo1, SQL Server le asignará como esquema por defecto el valor &quot;MIDOMINIO\Usuario1&quot;.&lt;br /&gt;
&lt;br /&gt;
A partir de este momento, cada objeto que cree el Usuario1 sin definir el esquema correctamente se llamará de la forma:&lt;br /&gt;
&lt;br /&gt;
MIDOMINIO\Usuario1.NombreObjeto.&lt;br /&gt;
&lt;br /&gt;
Y todas las consultas que haga el usuario sin especificar el esquema en los nombres de objeto penalizarán el rendimiento de SQL Server. Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/2ce65f5ada56ee7b0a2f.js&quot;&gt;&lt;/script&gt;

Además, si otros usuarios realizan esta misma consulta, fallará, ya que SQL Server no será capaz de encontrar el objeto si no se especifica el nombre de esquema.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;u&gt;
Conclusiones&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Si eres &lt;b&gt;DBA&lt;/b&gt;: Asegúrate que los usuarios de tus bases de datos tengan asignado como esquema por defecto dbo o NULL.&lt;/li&gt;
&lt;li&gt;Si eres &lt;b&gt;programador&lt;/b&gt;: Escribe todas tus consultas haciendo referencia a los objetos por su nombre completo, de la forma nombre_de_esquema.nombre_de_objeto&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/6345527689488913806/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/05/haz-bien-tus-consultas-llama-las-cosas.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/6345527689488913806'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/6345527689488913806'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/05/haz-bien-tus-consultas-llama-las-cosas.html' title='Haz bien tus consultas: Llama a las cosas por su nombre (y esquema)'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-7876331608550208255</id><published>2014-04-14T13:00:00.000+02:00</published><updated>2014-04-14T18:15:30.341+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="DBCC"/><category scheme="http://www.blogger.com/atom/ns#" term="diagnóstico"/><category scheme="http://www.blogger.com/atom/ns#" term="Express Profiler"/><category scheme="http://www.blogger.com/atom/ns#" term="profiler"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server Express"/><category scheme="http://www.blogger.com/atom/ns#" term="sql server profiler"/><category scheme="http://www.blogger.com/atom/ns#" term="Trace Flags"/><title type='text'>Hacer trazas en SQL Server Express</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Si necesitas &lt;b&gt;diagnosticar problemas de rendimiento&lt;/b&gt;, encontrar consultas conflictivas o simplemente quieras trazar las consultas que hace una aplicación contra la base de datos, seguramente estés acostumbrado a usar el &lt;b&gt;SQL Server Profiler&lt;/b&gt;, la herramienta que principalmente hemos utilizado para realizar este tipo de diagnósticos sobre nuestras bases de datos y servidores. También es posible que te hayas decidido a dar el paso a &lt;b&gt;Extended Events&lt;/b&gt;, pero esa es otra cuestión.&lt;br /&gt;
&lt;br /&gt;
Si el Profiler es tu herramienta, muy seguramente la eches de menos en el caso de que el diagnóstico tengas que hacerlo sobre un &lt;b&gt;SQL Server Express&lt;/b&gt;. La edición gratuita del motor de bases de datos relacionales de Microsoft no incluye esta aplicación. Es un contratiempo, pero hay &lt;b&gt;alternativas&lt;/b&gt;. A continuación, os las presentamos:&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
ExpressProfiler&lt;/h3&gt;
&lt;br /&gt;
&lt;b&gt;&lt;a href=&quot;http://expressprofiler.codeplex.com/&quot;&gt;ExpressProfiler&lt;/a&gt;&amp;nbsp;&lt;/b&gt;es un ejecutable, &lt;b&gt;gratuito&lt;/b&gt;, de código abierto, anteriormente conocido como SqlExpress Profiler. Presenta una interfaz muy sencilla en un ejecutable que solamente tendremos que descargar y ejecutar, sin instalaciones. Simplemente tendremos que darle al botón de play y monitorizar la traza para ver qué consultas se están ejecutando.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJz8gr98kbF0MbYfOqBici8j2HdWOhayRs6mIEOkt6PxTO1K5kA66Cw-IuckkBkvnhB5nFxI4LErghGmu9lL5T2b-XwX_H4xFTST67cofAOLxx_2dIlbYYt_qC-8mXatp_8-ZQBbUb8w0x/s1600/expressprofiler.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;El ExpressProfiler v2.0, en acción&quot; border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJz8gr98kbF0MbYfOqBici8j2HdWOhayRs6mIEOkt6PxTO1K5kA66Cw-IuckkBkvnhB5nFxI4LErghGmu9lL5T2b-XwX_H4xFTST67cofAOLxx_2dIlbYYt_qC-8mXatp_8-ZQBbUb8w0x/s1600/expressprofiler.JPG&quot; height=&quot;197&quot; title=&quot;El ExpressProfiler v2.0, en acción&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
El ExpressProfiler v2.0, en acción&lt;/div&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Trace Flags o Marcas de Seguimiento&lt;/h3&gt;
&lt;br /&gt;
Existen en SQL Server una serie de características que pueden ser configuradas de manera temporal y dinámica, activando y desactivando lo que se conoce como &lt;a href=&quot;http://technet.microsoft.com/es-es/library/ms188396.aspx&quot;&gt;&lt;b&gt;trace flags o marcas de seguimiento&lt;/b&gt;&lt;/a&gt;, en castellano. Tal y como &lt;a href=&quot;http://technet.microsoft.com/es-es/library/ms188396.aspx&quot;&gt;explica la MSDN&lt;/a&gt;, las marcas de seguimiento se suelen utilizar para &lt;b&gt;diagnosticar problemas de rendimiento&lt;/b&gt; o para depurar procedimientos almacenados o sistemas complejos.&lt;br /&gt;
&lt;br /&gt;
Pues bien, dos de ellas nos sirven para nuestro propósito, tal y como se explica en &lt;a href=&quot;http://www.codeproject.com/Tips/332293/How-to-trace-SQL-Server-Express-without-using-SQL&quot;&gt;este artículo de CodeProject&lt;/a&gt;, escrito por &lt;a href=&quot;http://www.codeproject.com/script/Membership/View.aspx?mid=1632474&quot;&gt;BillyBoatGruff&lt;/a&gt; en febrero de 2012.&lt;br /&gt;
&lt;br /&gt;
Activando la marca&amp;nbsp;&lt;b&gt;4032&lt;/b&gt;, todas las consultas ejecutadas sobre SQL Server se trazan. El mecanismo habitual para activar una traza es mediante la instrucción &lt;a href=&quot;http://technet.microsoft.com/es-es/library/ms187329.aspx&quot;&gt;DBCC TRACEON&lt;/a&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/10532514.js&quot;&gt;&lt;/script&gt;

Sin embargo, si intentamos activar esta traza, obtendremos el siguiente mensaje:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&quot;Se omitirá la marca de seguimiento 4032. Se trata de una marca de seguimiento no válida o que solo se puede especificar durante el inicio del servidor.&quot;&lt;/blockquote&gt;
Tal y como explica el mensaje, esta traza ha de especificarse &lt;b&gt;durante el inicio del servidor&lt;/b&gt;. Para ello ejecutaremos la siguiente instrucción desde una línea de comandos que hayamos ejecutado como administrador:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/10533185.js&quot;&gt;&lt;/script&gt;

Para poder ejecutar la instrucción, el servidor deberá estar detenido. Si no lo está, &lt;b&gt;podemos pararlo&lt;/b&gt; desde la misma línea de comandos con la instrucción:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/10533218.js&quot;&gt;&lt;/script&gt;

&lt;br /&gt;
Una vez hecho esto, &lt;b&gt;volcaremos las consultas al log de errores &lt;/b&gt;de SQL Server para que podamos consultarla, activando la traza &lt;b&gt;3605&lt;/b&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/10532643.js&quot;&gt;&lt;/script&gt;

Con estas dos trazas activas, podremos revisar en el log de nuestro SQL Server &lt;b&gt;todas las consultas realizadas&lt;/b&gt; sobre el servidor. El log permite realizar &lt;b&gt;filtrados&lt;/b&gt; y &lt;b&gt;exportar&lt;/b&gt; su listado a un fichero de texto, desde donde podremos copiar las consultas.&lt;br /&gt;
&lt;br /&gt;
Hay que tener en cuenta que para poder utilizar este mecanismo, &lt;b&gt;es necesario ser administrador&lt;/b&gt; tanto del servidor de bases de datos como del equipo en el que esté instalado.&lt;br /&gt;
&lt;br /&gt;
Para deshabilitar las trazas, una vez hayamos acabado con las tareas de diagnóstico, ejecuta:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/10533376.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/7876331608550208255/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/04/hacer-trazas-en-sql-server-express.html#comment-form' title='5 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/7876331608550208255'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/7876331608550208255'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/04/hacer-trazas-en-sql-server-express.html' title='Hacer trazas en SQL Server Express'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJz8gr98kbF0MbYfOqBici8j2HdWOhayRs6mIEOkt6PxTO1K5kA66Cw-IuckkBkvnhB5nFxI4LErghGmu9lL5T2b-XwX_H4xFTST67cofAOLxx_2dIlbYYt_qC-8mXatp_8-ZQBbUb8w0x/s72-c/expressprofiler.JPG" height="72" width="72"/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-9053071833167066076</id><published>2014-03-14T12:12:00.004+01:00</published><updated>2014-03-14T15:05:52.261+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="clustered"/><category scheme="http://www.blogger.com/atom/ns#" term="heap"/><category scheme="http://www.blogger.com/atom/ns#" term="rendimiento"/><category scheme="http://www.blogger.com/atom/ns#" term="script"/><category scheme="http://www.blogger.com/atom/ns#" term="Índices"/><title type='text'>Heaps en SQL Server: tablas sin índice clustered y sus consecuencias</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Definición&lt;/h3&gt;
&lt;div&gt;
En SQL Server las tablas pueden tener o no tener un índice &lt;i&gt;clustered&lt;/i&gt;.
El índice &lt;i&gt;clustered&lt;/i&gt; es por el que SQL ordena físicamente los
datos (las filas de las tablas) en disco.&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
El índice &lt;i&gt;clustered&lt;/i&gt; le sirve a SQL para buscar,
ordenar y agrupar registros de manera eficiente. Así, &lt;b&gt;&lt;span style=&quot;background-color: white; background-position: initial initial; background-repeat: initial initial;&quot;&gt;no tener un índice &lt;i&gt;clustered&lt;/i&gt;
en una tabla puede llevarnos a problemas de rendimiento&lt;/span&gt;&lt;/b&gt;. Cuando una
tabla no tiene índice &lt;i&gt;clustered&lt;/i&gt;, se llama &lt;i&gt;&lt;b&gt;heap&lt;/b&gt;&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
El problema&lt;/h3&gt;
&lt;div&gt;
Los &lt;i&gt;heaps&amp;nbsp;&lt;/i&gt;mantienen los registros en las páginas de datos en el mismo orden en el que se han insertado. Esto hace que los &lt;i&gt;heaps&amp;nbsp;&lt;/i&gt;resulten más rápidos a la hora de realizar un INSERT, ya que no han de insertarse en una posición en concreto, sino directamente a continuación del último registro existente para la tabla en cuestión.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Sin embargo, &lt;b&gt;cualquier otra operación que requiera un orden en los datos será más lenta&lt;/b&gt;. Esto se aplica a SELECT, DELETE y UPDATE, salvo que se quieran efectuar estas operaciones sobre la tabla completa.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;a href=&quot;http://technet.microsoft.com/en-us/library/hh213609.aspx&quot;&gt;Lo que la MSDN nos dice de los &lt;i&gt;heaps&lt;/i&gt;&lt;/a&gt;&lt;i&gt; &lt;/i&gt;es que:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;A veces, hay buenos motivos para dejar una tabla como heap en lugar de crear un índice &lt;i&gt;clustered&lt;/i&gt;, pero &lt;b&gt;para usar los &lt;i&gt;heaps &lt;/i&gt;de forma eficaz se requieren conocimientos avanzados&lt;/b&gt;. La mayoría de las tablas deben tener un índice &lt;i&gt;clustered &lt;/i&gt;cuidadosamente elegido.&lt;/li&gt;
&lt;li&gt;Si una tabla es un &lt;i&gt;heap &lt;/i&gt;y no tiene ningún índice no &lt;i&gt;clustered&lt;/i&gt;, debe examinarse la tabla completa (&lt;b&gt;&lt;i&gt;table scan&lt;/i&gt;&lt;/b&gt;) cuando se busca una fila.&lt;/li&gt;
&lt;/ul&gt;
Es decir, &lt;b&gt;en general los &lt;i&gt;heaps&lt;/i&gt; no son aceptables&lt;/b&gt;.
Solamente bajo ciertos escenarios muy estudiados para los que una ordenación de
los datos no es necesaria y un mantenimiento de índices por parte de SQL
implicaría un sobrecoste innecesario (por ejemplo, una tabla con una lista de
provincias de España, para la que siempre se devuelve la lista completa y nunca
se busca información para un registro concreto).&lt;br /&gt;
&lt;br /&gt;
En cualquier otro caso, cualquier consulta sobre una tabla sin índice &lt;i&gt;clustered &lt;/i&gt;obligará a SQL Server a recorrer la tabla entera en busca del registro o registros solicitados. Evidentemente, &lt;b&gt;cuanto mayor sea la tabla, mayor será el problema de rendimiento&lt;/b&gt; que esta situación puede generar.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Cómo detectarlo&lt;/h3&gt;
&lt;div&gt;
El &lt;i&gt;&lt;b&gt;script&lt;/b&gt; &lt;/i&gt;a continuación ayuda a detectar &lt;i&gt;heaps &lt;/i&gt;en
nuestras bases de datos:&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span lang=&quot;EN-US&quot; style=&quot;color: blue; font-family: Consolas; font-size: 9.5pt; mso-ansi-language: EN-US;&quot;&gt;SELECT&lt;/span&gt;&lt;span lang=&quot;EN-US&quot; style=&quot;font-family: Consolas; font-size: 9.5pt; mso-ansi-language: EN-US;&quot;&gt;
&lt;span style=&quot;color: magenta;&quot;&gt;OBJECT_NAME&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: teal;&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: magenta;&quot;&gt;object_id&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: blue;&quot;&gt;AS&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;TableName&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: blue;&quot;&gt;rows&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span lang=&quot;EN-US&quot; style=&quot;color: blue; font-family: Consolas; font-size: 9.5pt; mso-ansi-language: EN-US;&quot;&gt;FROM&lt;/span&gt;&lt;span lang=&quot;EN-US&quot; style=&quot;font-family: Consolas; font-size: 9.5pt; mso-ansi-language: EN-US;&quot;&gt;
&lt;span style=&quot;color: green;&quot;&gt;sys&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;indexes&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;i&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span lang=&quot;EN-US&quot; style=&quot;color: grey; font-family: Consolas; font-size: 9.5pt; mso-ansi-language: EN-US;&quot;&gt;INNER&lt;/span&gt;&lt;span lang=&quot;EN-US&quot; style=&quot;font-family: Consolas; font-size: 9.5pt; mso-ansi-language: EN-US;&quot;&gt;
&lt;span style=&quot;color: grey;&quot;&gt;JOIN&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;sys&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;partitions&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;p&lt;/span&gt; &lt;span style=&quot;color: blue;&quot;&gt;ON&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: magenta;&quot;&gt;object_id&lt;/span&gt; &lt;span style=&quot;color: grey;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: magenta;&quot;&gt;object_id&lt;/span&gt; &lt;span style=&quot;color: grey;&quot;&gt;AND&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: teal;&quot;&gt;index_id&lt;/span&gt; &lt;span style=&quot;color: grey;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: teal;&quot;&gt;index_id&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span lang=&quot;EN-US&quot; style=&quot;color: blue; font-family: Consolas; font-size: 9.5pt; mso-ansi-language: EN-US;&quot;&gt;WHERE&lt;/span&gt;&lt;span lang=&quot;EN-US&quot; style=&quot;font-family: Consolas; font-size: 9.5pt; mso-ansi-language: EN-US;&quot;&gt;
&lt;span style=&quot;color: teal;&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: teal;&quot;&gt;index_id&lt;/span&gt; &lt;span style=&quot;color: grey;&quot;&gt;=&lt;/span&gt; 0&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span lang=&quot;EN-US&quot; style=&quot;color: blue; font-family: Consolas; font-size: 9.5pt; mso-ansi-language: EN-US;&quot;&gt;ORDER&lt;/span&gt;&lt;span lang=&quot;EN-US&quot; style=&quot;font-family: Consolas; font-size: 9.5pt; mso-ansi-language: EN-US;&quot;&gt;
&lt;span style=&quot;color: blue;&quot;&gt;BY&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: blue;&quot;&gt;rows&lt;/span&gt; &lt;span style=&quot;color: blue;&quot;&gt;DESC&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span lang=&quot;EN-US&quot; style=&quot;font-family: Consolas; font-size: 9.5pt; mso-ansi-language: EN-US;&quot;&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
La solución&lt;/h3&gt;
&lt;div&gt;
En general, con cada &lt;i&gt;heap&lt;/i&gt; hay que pararse y
determinar cuál debería ser su índice &lt;i&gt;clustered&lt;/i&gt;. &lt;b&gt;El candidato más
idóneo para ser índice &lt;i&gt;clustered&lt;/i&gt; suele ser siempre la clave primaria&lt;/b&gt;,
aunque existen excepciones. Si la tabla sólo tiene clave primaria, ésta debe
ser &lt;i&gt;clustered&lt;/i&gt; siempre. El resto de los casos podemos estudiarlo, aunque
existen algunas directrices:&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Suelen ser los campos que usamos para hacer búsquedas y &lt;i&gt;joins &lt;/i&gt;sobre la tabla.&lt;/li&gt;
&lt;li&gt;Suelen ser los campos por los que se referencia a la tabla desde otras tablas.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&amp;nbsp;Hay que intentar que el índice clustered de una tabla tenga el mínimo tamaño posible.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Todo esto señala, como decíamos, a la clave primaria de la
tabla. Pero, en ocasiones, creamos claves alternativas a la primaria que se
ajustan mejor a esta definición.&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Referencias:&lt;/u&gt;&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;i&gt;&lt;a href=&quot;http://basitaalishan.com/2014/03/13/tables-without-clustered-indexes/&quot;&gt;Tables without clustered indexes&lt;/a&gt;&lt;/i&gt;, por Basit Farooq. Basit nos ofrece &lt;i&gt;scripts &lt;/i&gt;alternativos para detectar &lt;i&gt;heaps &lt;/i&gt;basados en su utilización&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;a href=&quot;http://www.brentozar.com/blitz/heaps-tables-without-primary-key-clustered-index/&quot;&gt;Blitz Results: Tables without clustered indexes&lt;/a&gt;&lt;/i&gt;, &amp;nbsp;por Brent Ozar.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/9053071833167066076/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/03/heaps-en-sql-server-tablas-sin-indice.html#comment-form' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/9053071833167066076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/9053071833167066076'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/03/heaps-en-sql-server-tablas-sin-indice.html' title='Heaps en SQL Server: tablas sin índice clustered y sus consecuencias'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-740749103825174709</id><published>2014-03-12T16:26:00.001+01:00</published><updated>2014-03-12T16:28:47.250+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><category scheme="http://www.blogger.com/atom/ns#" term="tipos de datos"/><title type='text'>Tipos de datos por defecto en SQL Server</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
En ocasiones necesitamos que nuestras consultas devuelvan valores constantes. Por ejemplo, de manera muy sencilla, podemos tener una consulta como la siguiente:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/7b5a5b26cce7e33caf36.js&quot;&gt;&lt;/script&gt;

Si necesitamos recuperar los valores devueltos por la consulta en un recordset de ADO.NET, por ejemplo, &lt;b&gt;¿qué tipo de datos debemos esperar de columnas de este tipo?&lt;/b&gt; La respuesta: depende.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Depende del tipo de constante&lt;/b&gt; que hayamos introducido. Si se trata de un número que no desborde los 4 &lt;i&gt;bytes &lt;/i&gt;de capacidad de un entero (&lt;b&gt;int&lt;/b&gt;), como en el caso del 1 de nuestra consulta anterior, éste será el tipo de datos de dicha constante.&lt;br /&gt;
&lt;br /&gt;
Si escribimos la constante entre comillas simples, SQL lo tratará como un varchar del tamaño del literal que hayamos escrito. Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/9508980.js&quot;&gt;&lt;/script&gt;

Creará un campo varchar(1). Éste sería nvarchar(2) si hubiésemos escrito lo siguiente, indicando un literal Unicode mediante la N delante del literal:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/3f839c63a2d0d0d86e3a.js&quot;&gt;&lt;/script&gt;

Para un número con parte decimal, el tipo de datos será &lt;i&gt;&lt;b&gt;numeric&lt;/b&gt;&lt;/i&gt;; lo mismo que para un número de tamaño mayor que el máximo entero positivo. Si escribimos un símbolo de moneda, como €, SQL lo interpretará con el tipo de datos &lt;i&gt;&lt;b&gt;money&lt;/b&gt;&lt;/i&gt;. Y así, sucesivamente.&lt;br /&gt;
&lt;br /&gt;
Para comprobar todos los tipos de datos que queramos, podemos ejecutar el siguiente script:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/d2cb47652a9fc741cdd4.js&quot;&gt;&lt;/script&gt;

Y comprobar en sus resultados qué tipo de datos podemos esperar para cada tipo de constante que se nos ocurra:&lt;br /&gt;
&lt;br /&gt;
Llama especialmente la atención el tratamiento que recibe el &lt;b&gt;NULL &lt;/b&gt;de la columna 7: &lt;b&gt;su tipo de datos por defecto también es int&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/9faa7c6eb67b20b6bcdd.js&quot;&gt;&lt;/script&gt;

Éste es el comportamiento que cabe esperar de SQL Server. Sin embargo, lo recomendable sería controlar exactamente qué tipo de datos queremos que nos sea devuelto ejecutando los &lt;b&gt;&lt;a href=&quot;http://msdn.microsoft.com/es-es/library/ms187928.aspx&quot;&gt;CAST&lt;/a&gt;&lt;/b&gt; pertinentes sobre cada una de las constantes. En el ejemplo anterior, lo lógico es que queramos tratar el literal &#39;20140312&#39; como una fecha, por lo que la consulta sobre ese valor debería realizarse así:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/1c2f7d89af4772bf2f59.js&quot;&gt;&lt;/script&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/740749103825174709/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/03/tipos-de-datos-por-defecto-en-sql-server.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/740749103825174709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/740749103825174709'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/03/tipos-de-datos-por-defecto-en-sql-server.html' title='Tipos de datos por defecto en SQL Server'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-4433655579675570668</id><published>2014-02-20T17:15:00.003+01:00</published><updated>2014-02-20T17:23:25.478+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="configuración regional"/><category scheme="http://www.blogger.com/atom/ns#" term="fechas"/><category scheme="http://www.blogger.com/atom/ns#" term="Itzik Ben-Gan"/><category scheme="http://www.blogger.com/atom/ns#" term="SET DATEFORMAT"/><category scheme="http://www.blogger.com/atom/ns#" term="SET LANGUAGE"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><title type='text'>Formato de fechas en SQL Server</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;b&gt;Resumen:&lt;/b&gt; En cada país, en cada idioma, en cada región... usamos un formato diferente para representar las fechas. SQL Server permite comparar columnas que almacenan fechas contra cadenas de textos que convierte internamente al tipo de datos necesario. Sin embargo, según la configuración regional del servidor, la misma cadena puede ser interpretada de diferentes formas, generando errores que incluso pueden pasar inadvertidos. Para solucionarlo existe un formato de fecha estándar e independiente de cualquier configuración que hay que usar siempre: &#39;yyyymmdd&#39;.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;u&gt;El problema&lt;/u&gt;&lt;/h3&gt;
Todos sabemos que &lt;b&gt;las fechas no se representan igual en todas las partes del mundo&lt;/b&gt;. Mientras que en España, por ejemplo, es típico usar el formato dd/mm/yyyy, donde d es día, m es año y la y representa al año (la fecha de publicación de este artículo en dicho formato sería 20/02/2014), en Alemania se usaría dd.mm.yyyy, pero en Estados Unidos sería mm/dd/yyyy.&lt;br /&gt;
&lt;br /&gt;
Así pues, como se puede observar en &lt;a href=&quot;http://en.wikipedia.org/wiki/Date_format_by_country&quot;&gt;este extenso artículo de la Wikipedia&lt;/a&gt;, el mismo dato se puede representar de múltiples formas; una misma fecha puede representarse con distintas ordenaciones de sus componentes y con distintos separadores entre ellos.&lt;br /&gt;
&lt;br /&gt;
Por ello, es inevitable que cuando queramos poner una fecha en una consulta para compararla contra un campo de tipo date, datetime o datetime2 nos preguntemos: &quot;¿en qué formato la pongo?&quot;&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;u&gt;La importancia del formato&lt;/u&gt;&lt;/b&gt;&lt;/h3&gt;
El mismo formato puede funcionar, no funcionar o devolver resultados incorrectos, según lo que espere el servidor contra el que trabajemos. No es una cuestión trivial, ya que&lt;b&gt; equivocarse en el formato puede producir resultados inesperados en el peor momento&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Supongamos que tenemos una base de datos de compras en nuestro entorno de desarrollo con la que trabajamos en español y queremos obtener todos los pedidos hechos el 12 de febrero de 2014.&lt;br /&gt;
&lt;br /&gt;
La consulta que realizaríamos sería la siguiente:&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/9116703.js&quot;&gt;&lt;/script&gt;

Esta consulta funcionaría correctamente siempre y cuando la ejecutásemos solamente en servidores configurados en español. Sin embargo, si la ejecutásemos contra un servidor configurado en inglés, ¡estaríamos pidiendo de repente los pedidos generados el 2 de diciembre de 2014!&lt;br /&gt;
&lt;br /&gt;
Tendríamos, pues, &lt;b&gt;un error que pasaría inadvertido&lt;/b&gt; hasta que un usuario se diese cuenta de que no está obteniendo los resultados que esperaba. Esto puede tener consecuencias bastante desastrosas para consultas que afecten a fechas de caducidad, contabilidad, programas de fidelización de clientes... ¡cualquier cosa!&lt;br /&gt;
&lt;br /&gt;
Puedes hacer la siguiente prueba para comprender mejor lo que está ocurriendo (además de &lt;b&gt;SET LANGUAGE&lt;/b&gt;, existe el comando &lt;a href=&quot;http://technet.microsoft.com/es-es/library/ms189491.aspx&quot;&gt;SET DATEFORMAT&lt;/a&gt;, que también puede cambiar la forma de SQL Server de interpretar una fecha):&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/9116797.js&quot;&gt;&lt;/script&gt;Verás que &lt;b&gt;el resultado cambia&lt;/b&gt;. En inglés se nos devuelve el mes &lt;i&gt;December&lt;/i&gt; (diciembre), mientras que en español el mes resultante es mayo. Si la fecha consultada hubiese sido del día 13 en adelante de cualquier mes, se habría producido directamente un error ejecutando la consulta contra cualquier servidor configurado en inglés o cualquier otro idioma que espere un formato del tipo mm/dd/yyyy.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;u&gt;El formato independiente, al rescate&lt;/u&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
Para solucionar estos problemas &lt;b&gt;existe un formato universal&lt;/b&gt;, que SQL Server entiende siempre, y que es totalmente &lt;b&gt;independiente de cualquier configuración del servidor&lt;/b&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Cualquier fecha representada de la siguiente manera es interpretada siempre correctamente:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&#39;yyyymmdd&#39;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Así pues, en nuestro ejemplo anterior, para pedir los pedidos del día 12 de febrero de 2014, utilizaríamos la siguiente consulta:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/9117000.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;
Se puede comprobar, imitando el script de prueba anterior, que a SQL Server no le afecta en absoluto la configuración actual de idioma:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/9117060.js&quot;&gt;&lt;/script&gt;Esta vez hemos obtenido &lt;b&gt;el mismo resultado&lt;/b&gt; tanto para inglés como para español: Febrero.&lt;br /&gt;
&lt;br /&gt;
Otros formatos posibles son:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Para fechas cortas: &#39;yymmdd&#39;&lt;/li&gt;
&lt;li&gt;Para fechas con hora incluida: &#39;yyyymmdd hh:mm:ss.mmm&#39;&lt;/li&gt;
&lt;/ul&gt;
Estos tres formatos se resumen en el patrón &lt;b&gt;&#39;[yy]yymmdd [hh:mm[:ss][.mmm]]&#39;&lt;/b&gt; donde todo lo que está entre corchetes es opcional.&lt;br /&gt;
&lt;br /&gt;
También existe un formato universal con separador de fechas, que siempre ha de llevar hora (solamente los milisegundos son opcionales), y que es el siguiente: &#39;yyyy-mm-ddThh:mm:ss.[mmm]&#39;.&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Referencias:&lt;/u&gt;&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://www.microsoft.com/learning/en-us/book.aspx?ID=8564&amp;amp;locale=en-us&quot;&gt;Inside Microsoft SQL Server 2005: T-SQL Programming&lt;/a&gt;, by Itzik Ben-Gan&lt;/li&gt;
&lt;li&gt;Aaron Bertrand&#39;s &quot;&lt;a href=&quot;http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/16/bad-habits-to-kick-mishandling-date-range-queries.aspx&quot;&gt;Bad habits to kick: mis-handling date / range queries&lt;/a&gt;&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/4433655579675570668/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/02/formato-de-fechas-en-sql-server.html#comment-form' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/4433655579675570668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/4433655579675570668'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2014/02/formato-de-fechas-en-sql-server.html' title='Formato de fechas en SQL Server'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-2518698543235591839</id><published>2013-10-22T12:23:00.001+02:00</published><updated>2013-10-22T13:42:38.825+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="IDENTITY"/><category scheme="http://www.blogger.com/atom/ns#" term="OUTPUT"/><category scheme="http://www.blogger.com/atom/ns#" term="SET"/><title type='text'>Columnas Identity: Insertar valores en columnas con la propiedad Identity</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;a href=&quot;http://technet.microsoft.com/es-es/library/ms186775.aspx&quot;&gt;La propiedad Identity&lt;/a&gt; sobre una columna de una tabla de la base de datos, hace que en ésta sus valores se generen secuencialmente, a partir de una raíz, para cada registro que insertemos en ella. Las columnas identity son de tipo numérico, generalmente entero, quedando los tipos de datos que soportan dicha propiedad los siguientes:  &lt;b&gt;tinyint, smallint, int, bigint, decimal(p,0), o numeric(p,0)&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Identity&lt;/b&gt; supone una gran ayuda para &lt;b&gt;generar claves&lt;/b&gt; sobre tablas. Sus ventajas son, principalmente, que es SQL Server quien se encarga de rellenar su valor y que &lt;b&gt;jamás se va a repetir&lt;/b&gt; el valor de la misma, ya que SQL Server genera el siguiente valor disponible para cada registro insertado. &lt;b&gt;Esto evita problemas de concurrencia&lt;/b&gt;. Es muy típico en las aplicaciones obtener el máximo valor de la columna clave, sumarle 1 e insertar el siguiente registro. Este mecanismo no presenta ningún problema si somos el único usuario conectado a la base de datos. Sin embargo, en cuanto haya dos usuarios conectados a la misma base de datos, puede darse el escenario en el que ambos leen el mismo valor y, por consiguiente, intentan insertar el mismo valor, produciendo así una violación de la clave primaria.&lt;br /&gt;
&lt;br /&gt;
Por supuesto, este escenario es controlable, mediante gestión de concurrencia, transacciones, etc. Pero todo ello tiene un coste, tanto de programación como de rendimiento. &lt;b&gt;Identity &lt;/b&gt;aparece aquí al rescate.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Identity&lt;/b&gt; también tiene sus potenciales &lt;b&gt;problemas&lt;/b&gt;:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Si se borran registros, se quedarán saltos en la numeración que jamás se usarán.&lt;/li&gt;
&lt;li&gt;Inicialmente, no podemos elegir el valor que se inserta en cada registro&lt;/li&gt;
&lt;li&gt;Es más complicado obtener el número recién insertado para seguir operando con el objeto en nuestra aplicación (supongamos que creamos un cliente nuevo en nuestra aplicación de ventas, y queremos saber su código para mantener una referencia a él en caso de que queramos hacer posteriores actualizaciones).&lt;/li&gt;
&lt;/ul&gt;
El primero de los problemas no debería suponer inconveniente alguno, aunque puede ser un factor de decisión para acabar usando Identity o no.&lt;br /&gt;
&lt;br /&gt;
Para el último de los puntos, existe una solución desde SQL Server 2005, mediante el &lt;a href=&quot;http://www.sqlservercentral.com/blogs/glennberry/2010/03/03/using-the-output-clause-to-retrieve-new-identity-values-from-sql-server-2008/&quot;&gt;uso de la cláusula OUTPUT&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Centrémonos ahora en el punto intermedio, que es el que da título a esta entrada:&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Cómo insertar un valor en una columna Identity&lt;/h3&gt;
Es sencillo. En un principio, si intentamos insertar un valor en una columna de este tipo, obtendremos el siguiente mensaje de error:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: red;&quot;&gt;Msg 544, Level 16, State 1, Line 1&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: red;&quot;&gt;Cannot insert explicit value for identity column in table &#39;TestIdentity&#39; when IDENTITY_INSERT is set to OFF.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
En ese mensaje tenemos una pista de lo que podemos hacer. Activando la opción &lt;b&gt;IDENTITY_INSERT&lt;/b&gt; sobre la tabla, podremos insertar el valor que queramos. Por ejemplo, de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/dd323a1d5bc72e11e243.js&quot;&gt;&lt;/script&gt;

Es sencillo, y nos da cierto control sobre columnas con la propiedad Identity. La única restricción que debemos tener en cuenta, es que no podemos ejecutar simultáneamente &lt;a href=&quot;http://technet.microsoft.com/es-es/library/ms188059.aspx&quot;&gt;SET IDENTITY_INSERT ON&lt;/a&gt; para más de una tabla en una sesión/conexión.&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Actualización:&lt;/h4&gt;
Como decíamos al principio, &lt;b&gt;el propósito de las columnas de tipo Identity es el de servir de claves únicas&lt;/b&gt;, ya sean &lt;i&gt;clustered&lt;/i&gt; o no, ya sean la clave primaria o no. &lt;b&gt;Podemos pensar que&lt;/b&gt;, como delegamos en SQL Server la responsabilidad de insertar nuevos valores en estas columnas, de manera sucesiva y única, &lt;b&gt;nunca vamos a tener valores repetidos&lt;/b&gt; en la misma.&lt;br /&gt;
&lt;br /&gt;
Pero &lt;b&gt;¡ojo!&lt;/b&gt; si hacemos uso de SET IDENTITY_INSERT ON, nada ni nadie nos asegura que no vayamos a tener valores repetidos en las columnas Identity. Así pues, si no estamos usando estas columnas como clave primaria de la tabla, es conveniente crear una restricción de unicidad sobre ellas mediante la &lt;b&gt;creación de un índice único&lt;/b&gt;. La decisión de si ha de ser &lt;i&gt;clustered&lt;/i&gt; o no ya depende de otros factores que debemos valorar (si normalmente hacemos consultas en las que en el WHERE se va a usar esta columna u otra, etc).&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/2518698543235591839/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2013/10/columnas-identity-insertar-valores-en.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/2518698543235591839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/2518698543235591839'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2013/10/columnas-identity-insertar-valores-en.html' title='Columnas Identity: Insertar valores en columnas con la propiedad Identity'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-3497640190554635368</id><published>2013-09-23T09:24:00.001+02:00</published><updated>2013-09-23T09:24:13.534+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="funciones"/><category scheme="http://www.blogger.com/atom/ns#" term="procedimientos almacenados"/><category scheme="http://www.blogger.com/atom/ns#" term="rendimiento"/><category scheme="http://www.blogger.com/atom/ns#" term="script"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><category scheme="http://www.blogger.com/atom/ns#" term="triggers"/><category scheme="http://www.blogger.com/atom/ns#" term="vistas"/><title type='text'>Script para encontrar código SQL entre los objetos de tu base de datos</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
En algunas ocasiones, buscando problemas de rendimiento en bases de datos, nos enfrentamos a una lista de consultas que son las causantes de dichos problemas.&lt;br /&gt;
&lt;br /&gt;
Una vez obtenida esa lista de consultas, el problema a resolver es: ¿&lt;b&gt;Dónde están&lt;/b&gt; codificadas &lt;b&gt;esas consultas&lt;/b&gt;? ¿Forman parte del código de nuestra aplicación o, por el contrario, su código T-SQL está en alguno de nuestros objetos de la base de datos; véase un trigger, un procedimiento almacenado, una función o una vista?&lt;br /&gt;
&lt;br /&gt;
Si se da el segundo caso, y no somos capaces de reconocer el objeto que está ejecutando la consulta que buscamos, disponemos de una &lt;b&gt;vista de sistema (entre las vistas de objetos del catálogo)&lt;/b&gt; que nos ayudará a encontrar dónde se esconde: &lt;a href=&quot;http://sys.sql_modules/&quot;&gt;sys.sql_modules&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Así, una consulta como la siguiente es la que necesitamos para encontrar el código:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/155eba9639f84e8bd4eb.js&quot;&gt;&lt;/script&gt;

* Si tu versión de SQL Server es anterior a SQL Server 2005, hay que usar la tabla de sistema &lt;a href=&quot;http://sys.syscomments/&quot;&gt;sys.syscomments&lt;/a&gt;.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/3497640190554635368/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2013/09/script-para-encontrar-codigo-sql-entre.html#comment-form' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/3497640190554635368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/3497640190554635368'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2013/09/script-para-encontrar-codigo-sql-entre.html' title='Script para encontrar código SQL entre los objetos de tu base de datos'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-784818152164107559</id><published>2013-09-02T17:21:00.000+02:00</published><updated>2013-09-04T09:02:03.624+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="deleted"/><category scheme="http://www.blogger.com/atom/ns#" term="inserted"/><category scheme="http://www.blogger.com/atom/ns#" term="triggers"/><title type='text'>Programar triggers correctamente: qué son y cómo se usan inserted y deleted</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Revisando recientemente la programación de algunos &lt;b&gt;triggers&lt;/b&gt;, se han detectado algunos errores que se suelen cometer cuando se desconoce la idiosincrasia de estos objetos y sus tablas especiales &lt;b&gt;inserted&lt;/b&gt; y &lt;b&gt;deleted&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;En uno de los triggers revisados, se quería copiar el valor de un campo datetime de la tabla para la que se había programado el trigger a otra. El código usado en el trigger (simplificado) era algo como lo siguiente:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; CREATE TRIGGER Trigger1 ON Table1  
 AFTER UPDATE  
 AS  
 BEGIN  
  UPDATE Table2  
  SET Fecha = Table1.Fecha  
  FROM Table2  
  INNER JOIN Table1 ON Table1.PrimaryKeyField = Table2.PrimaryKeyField  
 END  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Como comprenderéis inmediatamente, un trigger así hace muchas más cosas que las pretendidas inicialmente. Sí, copiará la fecha de Table1 a Table2, pero, cada vez que actualicemos un solo registro en Table1, &lt;b&gt;se actualizarán ¡todas las fechas! en Table2&lt;/b&gt; a partir de Table1.&lt;br /&gt;
&lt;br /&gt;
Observad el código detenidamente y veréis que en el &lt;b&gt;trigger no hay ninguna condición que le diga a SQL Server &quot;haz esto solamente para los registros afectados por la instrucción desencadenante&quot;&lt;/b&gt;. El resultado puede ser &lt;b&gt;desastroso&lt;/b&gt;, ya que si se trata de tablas muy grandes estaremos actualizando multitud de registros innecesariamente, perjudicando el rendimiento de nuestro servidor gravemente.&lt;br /&gt;
&lt;br /&gt;
Como sabréis, &lt;b&gt;un trigger se ejecuta cada vez que hay una sentencia que modifica la tabla que contiene el trigger&lt;/b&gt;. Es decir, podemos definir &lt;b&gt;triggers que se ejecuten tras un DELETE, un INSERT o un UPDATE&lt;/b&gt;. Asimismo, también podemos definir triggers que se ejecuten para dos de estos tipos de instrucciones o para las tres. Para ello, debemos especificar tras la palabra clave &lt;b&gt;AFTER &lt;/b&gt;a qué tipo de instrucciones queremos que afecte el trigger.&lt;br /&gt;
&lt;br /&gt;
Bien, una vez hemos definido cuando ha de actuar el trigger, ¿cómo sabemos qué registros han sido afectados por la ejecución de la sentencia desencadenante?&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
¡inserted y deleted, al rescate!&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;b&gt;Los triggers definen dos tablas especiales&lt;/b&gt; que contienen toda la información que necesitamos: &lt;b&gt;inserted y deleted&lt;/b&gt;. Ambas son subconjuntos de la tabla que contiene el trigger, justamente con los registros que nos interesan: los afectados por la sentencia desencadenante.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;inserted contiene los registros con los nuevos valores&lt;/b&gt; para triggers que se desencadenan con sentencias INSERT (nuevos registros) y UPDATE (nuevo valor para registros actualizados).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;deleted, por su parte, contiene los registros con los viejos valores&lt;/b&gt; para triggers que se desencadenan con sentencias DELETE (registros borrados) y UPDATE (valor anterior para los registros actualizados).&lt;br /&gt;
&lt;br /&gt;
Así pues, en un trigger definido como AFTER INSERT sólo dispondremos de la tabla inserted, en uno definido como AFTER DELETE solamente tendremos la tabla deleted, mientras que, finalmente, ambas tablas estarán disponibles en triggers definidos para ejecutarse tras un UPDATE con AFTER UPDATE, pudiendo consultar así de los valores antes y después de actualizarse los registros correspondientes.&lt;br /&gt;
&lt;br /&gt;
Así pues, podemos pensar ahora en cómo reescribir el trigger anterior para que &lt;b&gt;solamente los registros afectados actualicen el valor del campo Fecha en Tabla1&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
El resultado sería el siguiente:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; CREATE TRIGGER Trigger1 ON Table1  
 AFTER UPDATE  
 AS  
 BEGIN  
  UPDATE Table2  
  SET Fecha = inserted.Fecha  
  FROM Table2  
  INNER JOIN inserted ON inserted.PrimaryKeyField = Table2.PrimaryKeyField  
 END  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Así, tendremos todos nuestros registros actualizados cada vez que se ejecute un UPDATE sobre Table1, sin alterar otros registros no implicados en la operación (cada registro de Table2 se actualizará únicamente en el momento en que se modifique el valor del campo Fecha para su registro correspondiente en Table1).&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Otros errores típicos al programar un trigger&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Finalmente, hay otro par de detalles que podemos comentar para mejorar nuestra programación de triggers. Como alguno ya os habréis preguntado: ¿y &lt;b&gt;qué pasa si el campo Fecha no ha sido actualizado?&lt;/b&gt; ¿No estamos haciendo UPDATES innecesarios sobre Table2?&lt;br /&gt;
&lt;br /&gt;
Efectivamente, pero también existe una solución. En un trigger del tipo AFTER UPDATE &lt;b&gt;podemos comprobar si un campo determinado ha sido afectado&lt;/b&gt; por la operación desencadenante mediante la función &lt;b&gt;UPDATE(campo)&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Así, nuestro trigger podría (y debería) mejorarse de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; CREATE TRIGGER Trigger1 ON Table1  
 AFTER UPDATE  
 AS  
 BEGIN  
  SET NOCOUNT ON;  
  IF UPDATE(Fecha)  
  BEGIN  
   UPDATE Table2  
   SET Fecha = inserted.Fecha  
   FROM Table2  
   INNER JOIN inserted ON inserted.PrimaryKeyField = Table2.PrimaryKeyField  
  END  
 END  
&lt;/code&gt;&lt;/pre&gt;
*Sobre el uso de &lt;a href=&quot;http://aprendiendosqlserver.blogspot.com.es/2010/03/set-nocount-on.html#more&quot;&gt;SET NOCOUNT&lt;/a&gt; ya hablamos en otra entrada anterior.&lt;br /&gt;
&lt;br /&gt;
Finalmente, los triggers deben programarse para que &lt;b&gt;funcionen independientemente de si el numero de registros afectados es uno, muchos o ninguno (¡Ojo! También se desencadenan los triggers si no hay registros afectados&lt;/b&gt;, y esto hay que tenerlo muy en cuenta).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Con inserted y con deleted hay que trabajar siempre como si de una tabla más se tratase y, ¡muy importante!, pensar que puede contener más de un registro&lt;/b&gt;. Siempre hay que programar los triggers pensando en que no solamente se verá afectada una fila. Muchas veces se programan así porque conocemos la aplicación cliente y sabemos que solamente opera con los registros de uno en uno. Pero, creedme, llegará el día en que haréis un UPDATE para más de un registro y vuestro trigger dejará de funcionar correctamente en ese momento.&lt;br /&gt;
&lt;br /&gt;
El &lt;b&gt;siguiente código es muy habitual&lt;/b&gt; en muchos triggers, y sólo funcionaría cuando hay un registro afectado:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; CREATE TRIGGER Trigger1 ON Table1  
 AFTER UPDATE  
 AS  
 BEGIN  
  SET NOCOUNT ON;  
  IF UPDATE(Fecha)  
  BEGIN  
   DECLARE @fecha datetime  
   DECLARE @primaryKeyField int  
   SELECT @primaryKeyField = PrimaryKeyField, @fecha = Fecha FROM inserted  
   UPDATE Table2  
   SET Fecha = @fecha  
   WHERE Table2.PrimaryKeyField = @primaryKeyField  
  END  
 END  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Y, por supuesto, &lt;b&gt;¡no vale abrir un cursor sobre inserted para iterar por los registros afectados y hacer lo que se muestra en el código anterior fila a fila!&lt;/b&gt; En el 99% de las veces que vayáis a usar un cursor, existe una alternativa basada en conjuntos de registros, mucho más eficiente, que podréis usar. Los cursores tienen su aplicación en SQL Server, pero casi nunca es la de iterar por conjuntos de resultados para operar con ellos uno a uno. Normalmente, un JOIN con inserted o deleted y la otra tabla o tablas con las que queremos operar en el trigger suele ser el mecanismo apropiado trabajar con todos los registros a la vez.&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/784818152164107559/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2013/09/programar-triggers-correctamente-que.html#comment-form' title='33 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/784818152164107559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/784818152164107559'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2013/09/programar-triggers-correctamente-que.html' title='Programar triggers correctamente: qué son y cómo se usan inserted y deleted'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>33</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-6819958819752948660</id><published>2013-04-09T12:24:00.001+02:00</published><updated>2013-04-09T12:25:28.368+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="OUTPUT"/><category scheme="http://www.blogger.com/atom/ns#" term="procedimientos almacenados"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><title type='text'>Parámetros OUTPUT en procedimientos almacenados: recuperar su valor desde la llamada</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Los procedimientos almacenados de SQL Server pueden &lt;b&gt;devolver valores&lt;/b&gt; bien sea a través de su valor de retorno, bien sea mediante los denominados &lt;b&gt;&lt;a href=&quot;http://msdn.microsoft.com/es-es/library/ms187004(v=sql.105).aspx&quot;&gt;parámetros OUTPUT&lt;/a&gt;.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Ahora bien, para que un procedimiento almacenado nos devuelva el valor de un parámetro OUPUT deberemos tener en cuenta &lt;b&gt;dos cosas&lt;/b&gt;: que sea &lt;b&gt;declarado como OUTPUT&lt;/b&gt; en el propio procedimiento y que &lt;b&gt;en la ejecución&lt;/b&gt; del mismo &lt;b&gt;se especifique la palabra clave OUPUT junto al parámetro&lt;/b&gt; en el que queremos que se nos devuelva el valor.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
1. La primera premisa es, obviamente, declarar el parámetro como OUPUT en la declaración del procedimiento almacenado. Por ejemplo, imaginemos que queremos crear un procedimiento almacenado que sume dos números y nos devuelva el resultado. Reservamos el valor de retorno del procedimiento almacenado para gestionar posibles errores (por ejemplo, parámetros incorrectos).&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
CREATE PROCEDURE Suma&lt;br /&gt;
&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;@sumando1 int,&lt;br /&gt;
&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;@sumando2 int,&lt;br /&gt;
&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&lt;b&gt;@resultado int OUTPUT&lt;/b&gt;&lt;br /&gt;
AS&lt;br /&gt;
BEGIN&lt;br /&gt;
&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;-- SET NOCOUNT ON added to prevent extra result sets from&lt;br /&gt;
&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;-- interfering with SELECT statements.&lt;br /&gt;
&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;SET NOCOUNT ON;&lt;br /&gt;
&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;IF @sumando1 &amp;lt; 0 OR @sumando2 &amp;lt; 0&lt;br /&gt;
&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;RETURN 1&lt;br /&gt;
&amp;nbsp; &amp;nbsp; -- Insert statements for procedure here&lt;br /&gt;
&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;SET @resultado = @sumando1 + @sumando2&lt;br /&gt;
&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;RETURN 0&lt;br /&gt;
END&lt;/blockquote&gt;
En este caso, queremos que nuestro procedimiento almacenado &quot;Suma&quot; sólo admita números enteros positivos o el cero, por lo que en caso de recibir algún valor negativo en alguno de los dos sumandos, se devolvería un 1, indicando así un error en la ejecución del procedimiento almacenado (Nota: la gestión de errores mediante el valor de retorno de los procedimientos almacenados es sencilla pero limitada. Para una gestión de errores más completa, existen &lt;a href=&quot;http://msdn.microsoft.com/es-es/library/ms178592.aspx&quot;&gt;mecanismos como RAISERROR o THROW en combinación con bloques TRY...CATCH&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. La segunda, imprescindible también, es responsabilidad de la llamada al procedimiento almacenado. Para que la variable en la que queremos obtener el valor de retorno sea rellenada por el procedimiento almacenado debemos &lt;b&gt;especificar la palabra clave OUTPUT&lt;/b&gt; junto al parámetro que hace las veces de parámetro de salida (en el orden correspondiente de la llamada, por supuesto). De lo contrario, nuestra variable no se rellenará con el valor devuelto por el procedimiento almacenado. Es decir, un código como el siguiente, producirá un resultado quizás inesperado de &lt;b&gt;NULL&lt;/b&gt;:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
DECLARE @resultado int&lt;br /&gt;
EXEC Suma 1, 2, @resultado&lt;br /&gt;
SELECT @resultado&lt;/blockquote&gt;
Para obtener el valor esperado, en este caso un 3, debemos escribir lo siguiente:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
DECLARE @resultado int&lt;br /&gt;
&lt;b&gt;EXEC Suma 1, 2, @resultado OUTPUT&lt;/b&gt;&lt;br /&gt;
SELECT @resultado&lt;/blockquote&gt;
Hay que observar que ambas ejecuciones son correctas, ninguna de ellas produce error. En ambas, la declaración del procedimiento almacenado es correcta. Sin embargo, solamente especificando que queremos obtener el valor del parámetro de salida mediante la palabra clave OUTPUT, la variable @resultado ha sido rellenada correctamente en el código cliente que llama al procedimiento almacenado.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/6819958819752948660/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2013/04/parametros-output-en-procedimientos.html#comment-form' title='8 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/6819958819752948660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/6819958819752948660'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2013/04/parametros-output-en-procedimientos.html' title='Parámetros OUTPUT en procedimientos almacenados: recuperar su valor desde la llamada'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-4558568410222076324</id><published>2013-01-17T09:52:00.002+01:00</published><updated>2013-01-17T09:52:37.831+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ExecuteNonQuery"/><category scheme="http://www.blogger.com/atom/ns#" term="procedimientos almacenados"/><category scheme="http://www.blogger.com/atom/ns#" term="SET NOCOUNT ON"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><title type='text'>ExecuteNonQuery devuelve -1 si se indica SET NOCOUNT ON</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Ejecutando un procedimiento almacenado que, a su vez llamaba a un método en un assembly instalado en el CLR de SQL Server, obtenía un error inesperado. El error me decía que una de las instrucciones SQL ejecutadas dentro del assembly estaba fallando. Sin embargo, si omitía el procesamiento del error, me daba cuenta de que la sentencia se había ejecutado correctamente.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;
¿Qué estaba ocurriendo?&lt;/h4&gt;
&lt;br /&gt;
La sentencia en el assembly se estaba ejecutando mediante el método &lt;a href=&quot;http://msdn.microsoft.com/es-es/library/system.data.sqlclient.sqlcommand.executenonquery(v=vs.110).aspx&quot;&gt;ExecuteNonQuery&lt;/a&gt; de la clase SQLCommand de ADO.NET. Según la MSDN, este método devuelve siempre el número de filas afectadas para instrucciones del tipo &lt;b&gt;UPDATE&lt;/b&gt;, &lt;b&gt;INSERT &lt;/b&gt;o &lt;b&gt;DELETE&lt;/b&gt;. En mi caso se trataba de un UPDATE. Sin embargo, &lt;b&gt;el valor devuelto siempre era -1&lt;/b&gt;, lo que el código del assembly procesaba como un error, ya que se esperaba afectar siempre a un registro de la base de datos.&lt;br /&gt;
&lt;br /&gt;
Intentando averiguar las causas del porqué de dicho -1, encontré &lt;a href=&quot;http://aspsoft.blogs.com/jonas/2006/10/executenonquery.html&quot;&gt;este artículo&lt;/a&gt;, en el que se explica muy claramente el motivo del valor negativo devuelto:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;b&gt;SET NOCOUNT ON&lt;/b&gt;&lt;/blockquote&gt;
Esa instrucción, habitual en los procedimientos almacenados, normalmente escrita al principio de los mismos, sirve para evitar que SQL Server nos devuelva la cuenta de filas afectadas por cada operación ejecutada en el procedimiento. Se evitan así dos cosas:&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Interferir en los resultados devueltos&lt;/li&gt;
&lt;li&gt;Mejorar el rendimiento del procedimiento almacenado, sobre todo si el número de sentencias ejecutadas es elevado.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Asegurándonos de poner &lt;b&gt;SET NOCOUNT OFF&lt;/b&gt; delante de la llamada al método del assembly, &lt;b&gt;¡problema resuelto!&lt;/b&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/4558568410222076324/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2013/01/executenonquery-devuelve-1-si-se-indica.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/4558568410222076324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/4558568410222076324'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2013/01/executenonquery-devuelve-1-si-se-indica.html' title='ExecuteNonQuery devuelve -1 si se indica SET NOCOUNT ON'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-613038296852909266</id><published>2013-01-09T16:39:00.000+01:00</published><updated>2015-07-30T10:38:14.636+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Microsoft"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><title type='text'>Microsoft quiere punto y coma al final de cada sentencia T-SQL</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Microsoft publica en la MSDN la &quot;&lt;a href=&quot;http://msdn.microsoft.com/es-es/library/ms143729.aspx&quot;&gt;Lista de características desusadas del motor de base de datos de SQL Server 2012&lt;/a&gt;&quot; o, lo que es lo mismo, las &lt;i&gt;deprecated features&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Esta lista es útil para mantener nuestra &lt;b&gt;aplicación actualizada&lt;/b&gt;, de tal forma que podamos seguir usando las nuevas funcionalidades de las sucesivas versiones SQL Server. Mantener en nuestro código alguna característica marcada como obsoleta o en desuso implicaría que no podríamos ejecutarlo en la versión de SQL que ya no la soportase.&lt;br /&gt;
&lt;br /&gt;
Pues bien, en dicha lista aparecen tanto las características que no serán soportadas en la próxima versión de SQL Server como las que estarán en desuso en futuras versiones. Esta segunda lista es muy amplia, pero si leemos detenidamente en ella nos encontraremos con, al menos, &lt;b&gt;una característica que nos llamará la atención&lt;/b&gt;:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&quot;Not ending Transact-SQL statements with a semicolon.&quot;
&lt;/blockquote&gt;
Es decir, Microsoft pretende que deje de ser opcional -como lo es hasta ahora- finalizar las sentencias SQL con o sin punto y coma. Hasta ahora, su opcionalidad ha provocado que&lt;b&gt; millones de líneas de código Transact SQL se haya escrito sin punto y coma&lt;/b&gt; al finalizar cada sentencia. Incluso el código que Microsoft implementa en las bases de datos de sistema no incluye este símbolo final.&lt;br /&gt;
&lt;br /&gt;
Así pues, parece descabellado que se pretenda que a partir de una incierta futura versión de SQL Server sea obligatorio, como así pretende Microsoft, finalizar cada sentencia con punto y coma. En tal circunstancia,&lt;b&gt; todo el código anterior debería ser revisado... ¡Todo, sin excepción!&lt;/b&gt; No se trataría de buscar una determinada característica en él y reemplazarla, sino de cambiarlo entero. Incluso aquel programador acostumbrado a finalizar sus sentencias con dicho signo de puntuación puede haber olvidado ponerlo en alguna ocasión, ya que su T-SQL era igualmente válido.&lt;br /&gt;
&lt;br /&gt;
A través del grupo &lt;a href=&quot;http://www.linkedin.com/groups?home=&amp;amp;gid=54395&amp;amp;trk=anet_ug_hm&quot;&gt;SQL Server Pofessionals&lt;/a&gt; de &lt;a href=&quot;http://www.linkedin.com/&quot;&gt;LinkedIn&lt;/a&gt; descubrimos que Microsoft ya mostró su intención &amp;nbsp;de obligarnos a finalizar las sentencias con punto y coma con la versión SQL Server 2005. A día de hoy, sigue pareciendo imposible que eso suceda. En cualquier caso, &lt;b&gt;¿empezaríais a programar usando punto y coma para terminar vuestras instrucciones?&lt;/b&gt; Parece una buena opción, salvo que se os olvide alguno en el camino y luego no seáis capaces de encontrar el punto y coma desaparecido entre las líneas de código que ya consideráis &quot;correctas&quot;.&lt;br /&gt;
&lt;br /&gt;
¿Qué opináis?&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/613038296852909266/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2013/01/microsoft-quiere-punto-y-coma-al-final.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/613038296852909266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/613038296852909266'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2013/01/microsoft-quiere-punto-y-coma-al-final.html' title='Microsoft quiere punto y coma al final de cada sentencia T-SQL'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-8045557106887541068</id><published>2012-11-13T11:01:00.003+01:00</published><updated>2017-10-20T08:04:52.660+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="DBA"/><category scheme="http://www.blogger.com/atom/ns#" term="rendimiento"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server Express"/><category scheme="http://www.blogger.com/atom/ns#" term="tablas"/><category scheme="http://www.blogger.com/atom/ns#" term="tamaño"/><title type='text'>Script para obtener el tamaño de todas las tablas de la base de datos</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
En algunas ocasiones podemos vernos con la necesidad de conocer qué tablas de nuestra base de datos están ocupando más espacio en disco. Por ejemplo, si disponemos de &lt;b&gt;SQL Server Express&lt;/b&gt;, cuyas bases de datos están limitadas a 4GB o 10GB, según la versión que estemos usando -4, hasta 2005; 10, a partir de 2008-, aparte de usar las opciones de comprimir la base de datos, poner el log en el modo simple de recuperación o &lt;b&gt;&lt;a href=&quot;http://aprendiendosqlserver.blogspot.com.es/2012/08/crecimiento-automatico-de-los-ficheros.html&quot;&gt;ajustar las políticas de crecimiento automático&lt;/a&gt;&lt;/b&gt; de nuestros ficheros, podemos necesitar averiguar qué tablas crecen más para tomar las decisiones oportunas.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;Para ello, podemos mirar tabla por tabla sus propiedades o usar el siguiente script que nos devolverá una fila por cada tabla, con su espacio usado y reservado:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;
SET NOCOUNT ON&amp;nbsp;
DBCC UPDATEUSAGE(0)&amp;nbsp;

-- Table row counts and sizes.&lt;br /&gt;
DECLARE @sizes TABLE&lt;br /&gt;
(&lt;br /&gt;
&amp;nbsp; &amp;nbsp; [name] NVARCHAR(128),
&amp;nbsp; &amp;nbsp; [rows] CHAR(11),
&amp;nbsp; &amp;nbsp; reserved VARCHAR(18),
&amp;nbsp; &amp;nbsp; data VARCHAR(18),
&amp;nbsp; &amp;nbsp; index_size VARCHAR(18),
&amp;nbsp; &amp;nbsp; unused VARCHAR(18)
)

INSERT @sizes EXEC sp_msForEachTable &#39;EXEC sp_spaceused &#39;&#39;?&#39;&#39;&#39;&amp;nbsp;

SELECT *
FROM &amp;nbsp; @sizes
ORDER BY convert(int, substring(data, 1, len(data)-3)) desc&lt;/pre&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/8045557106887541068/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/11/script-para-obtener-el-tamano-de-todas.html#comment-form' title='39 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/8045557106887541068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/8045557106887541068'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/11/script-para-obtener-el-tamano-de-todas.html' title='Script para obtener el tamaño de todas las tablas de la base de datos'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>39</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-2334350595734403456</id><published>2012-10-19T08:27:00.000+02:00</published><updated>2012-10-19T08:29:35.034+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="autocompletado"/><category scheme="http://www.blogger.com/atom/ns#" term="IntelliSense"/><category scheme="http://www.blogger.com/atom/ns#" term="Management Studio"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2012"/><title type='text'>Nuevo modo de autocompletado para IntelliSense en SQL Server Management Studio 2012. ¿Cómo cambiarlo?</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Con SQL Server 2008 llegó IntelliSense para T-SQL. &lt;b&gt;IntelliSense es una herramienta&lt;/b&gt; que nos ofrece el editor de SQL Server Management Studio para facilitarnos la escritura de código T-SQL. Básicamente, entre otras cosas, carga el catálogo de nuestra base de datos para facilitarnos la escritura de consultas.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;Así, si tenemos una tabla que se llama MiTabla y empezamos a escribir en el editor de consultas algo como&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
SELECT *&lt;br /&gt;
FROM Mi&lt;/blockquote&gt;
Intellisense nos mostrará rápidamente las opciones del catálogo que se pueden corresponder con lo que estamos escribiendo, para &lt;b&gt;facilitarnos así la escritura de textos&lt;/b&gt; y minimizar también la posibilidad de erratas en nuestro tecleo de código.&lt;br /&gt;
&lt;br /&gt;
Hasta SQL Server 2012, IntelliSense mostraba esta lista de miembros, seleccionando progresivamente el valor más parecido a lo que estábamos escribiendo. Si pulsábamos la tecla espacio, una coma, retorno de carror, un paréntesis, o cualquier otra tecla que indicase al editor que habíamos acabado de escribir el término actual, &lt;b&gt;IntelliSense lo completaba&amp;nbsp;automáticamente&lt;/b&gt;&amp;nbsp;con la selección actual.&lt;br /&gt;
&lt;br /&gt;
Esto conllevaba que, en algunas ocasiones, IntelliSense nos&amp;nbsp;auto-completase&amp;nbsp;palabras sin que nuestra intención real fuese escribirlas.&lt;br /&gt;
&lt;br /&gt;
Así pues, el&amp;nbsp;auto-completado&amp;nbsp;ha cambiado ligeramente en la nueva versión de SQL Server. Como podemos apreciar en la imagen siguiente, en la versión actual SQL Server &lt;b&gt;deja una línea encima&lt;/b&gt; de todos los posibles valores que encajan con lo que estamos escribiendo. En esa línea aparece simplemente lo que hemos escrito hasta el momento. Si lo que queremos es conservar lo tecleado y no elegir ninguno de los valores que IntelliSense nos ofrece, basta con pulsar espacio, coma o cerrar paréntesis y se mantendrá el texto tal cual.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyyr5qinN-GC4nJ58Kv1OuROIIq6HEJ86-jB8s1JnQGZoZAgDvIdAi_0OEvgMJmBYKNQl7o3amvoIVx4rnkZBvs_Qxwy-RAh1CORRxz7k1fTz4G3m8H1Moyohc3FS4dLFtM376uufXpv1S/s1600/Captura.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;125&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyyr5qinN-GC4nJ58Kv1OuROIIq6HEJ86-jB8s1JnQGZoZAgDvIdAi_0OEvgMJmBYKNQl7o3amvoIVx4rnkZBvs_Qxwy-RAh1CORRxz7k1fTz4G3m8H1Moyohc3FS4dLFtM376uufXpv1S/s200/Captura.PNG&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;El nuevo IntelliSense nos permite mantener lo que estamos escribiendo o seleccionar un valor propuesto.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
¿Y si quiero mantener el comportamiento anterior?&lt;/h4&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Es posible. SQL Server nos ofrece la posibilidad de mantener el mencionado comportamiento anterior total o parcialmente.&lt;br /&gt;
&lt;br /&gt;
Si nos gusta el nuevo modo de funcionamiento de IntelliSense, pero queremos poder elegir la palabra que queremos escribir cuando IntelliSense ya la ha encontrado, podemos usar el &lt;b&gt;tabulador&lt;/b&gt;, así: Vemos en la imagen que la selección más aproximada al texto que estamos escribiendo aparece &lt;b&gt;rodeada de un recuadro amarillo&lt;/b&gt;. Si pulsamos la tecla TAB se escribirá lo que aparece dentro de ese recuadro, como cuando en versiones anteriores se elegía automáticamente la opción más parecida a lo escrito.&lt;br /&gt;
&lt;br /&gt;
Aun así, si eres de los que prefiere el &lt;b&gt;modo de funcionamiento anterior de IntelliSense&lt;/b&gt;, SQL Server te ofrece la posibilidad de seguir usándolo, mediante la &lt;b&gt;combinación de teclas&amp;nbsp;Ctrl + Alt + Espacio&lt;/b&gt;. También podemos acceder a esta opción en el menú Edición / IntelliSense. Eso sí, con el inconveniente de que habrá que &lt;b&gt;cambiar el modo cada vez que abramos una ventana nueva del editor&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKUvZtKA7FwGLtwXkwV-N5tlHsaj1XLFdl-ZtvXiYAvnfCjZ4qEArYL1xxeDyffbb1rAk07JKizhugmNTc8fukMdK7KyJrKc2q053YCFDXief6Vtd3ftQc1FMRtMuSOEPMWGkrPnrox6at/s1600/Captura.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;115&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKUvZtKA7FwGLtwXkwV-N5tlHsaj1XLFdl-ZtvXiYAvnfCjZ4qEArYL1xxeDyffbb1rAk07JKizhugmNTc8fukMdK7KyJrKc2q053YCFDXief6Vtd3ftQc1FMRtMuSOEPMWGkrPnrox6at/s400/Captura.PNG&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Si queremos cambiar el modo del IntelliSense podemos pulsar Ctrl + Alt + Espacio.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Una vez cambiado al modo anterior, escribiendo lo que aparece en la imagen, SQL Server nos completará automáticamente la palabra MiTabla si pulsamos cualquiera de las teclas comentadas anteriormente.&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvljDc6mNsVZ1KrRulJKOyj8EBRCRGp6jKxf2Zkb5R1jrN5eRw3qbVrDHuDDq-se3yEZqkAHC6hT_SWbUsceAfW9Yj2q5a4_v37BqLQuPeegmEj9Kyg5qbJow0uqbrS09TZMjbtmv4TFij/s1600/Captura.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;108&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvljDc6mNsVZ1KrRulJKOyj8EBRCRGp6jKxf2Zkb5R1jrN5eRw3qbVrDHuDDq-se3yEZqkAHC6hT_SWbUsceAfW9Yj2q5a4_v37BqLQuPeegmEj9Kyg5qbJow0uqbrS09TZMjbtmv4TFij/s200/Captura.PNG&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Modo de funcionamiento anterior a SQL Server 2012 de IntelliSense.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;div&gt;
Recordad que en ambos modos podremos movernos con los cursores por la lista mostrada o usar el ratón para elegir el texto que realmente queremos escribir. En este caso, podríamos elegir MiTabla2 simplemente pulsando la tecla cursor con la flecha hacia abajo para seleccionarla.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/2334350595734403456/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/10/nuevo-modo-de-autocompletado-para.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/2334350595734403456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/2334350595734403456'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/10/nuevo-modo-de-autocompletado-para.html' title='Nuevo modo de autocompletado para IntelliSense en SQL Server Management Studio 2012. ¿Cómo cambiarlo?'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyyr5qinN-GC4nJ58Kv1OuROIIq6HEJ86-jB8s1JnQGZoZAgDvIdAi_0OEvgMJmBYKNQl7o3amvoIVx4rnkZBvs_Qxwy-RAh1CORRxz7k1fTz4G3m8H1Moyohc3FS4dLFtM376uufXpv1S/s72-c/Captura.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-2478097154387040970</id><published>2012-10-10T19:43:00.003+02:00</published><updated>2013-09-19T08:42:18.911+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="DBA"/><category scheme="http://www.blogger.com/atom/ns#" term="DMV"/><category scheme="http://www.blogger.com/atom/ns#" term="ficheros"/><category scheme="http://www.blogger.com/atom/ns#" term="log"/><category scheme="http://www.blogger.com/atom/ns#" term="vistas de sistema"/><title type='text'>Listar todos los ficheros de un servidor SQL Server</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;a href=&quot;http://www.projectenvision.com/blog/How-to-list-all-database-files-in-SQL-Server&quot;&gt;E&lt;/a&gt;xisten multitud de &lt;b&gt;vistas de sistema&lt;/b&gt; en SQL Server que nos ayudan a hacer las tareas de &lt;b&gt;administración &lt;/b&gt;y &lt;b&gt;mantenimiento &lt;/b&gt;mucho más sencillas. Una de ellas nos permite &lt;b&gt;listar todos los ficheros&lt;/b&gt;, tanto de datos como de log, relativos a las bases de datos que tenemos en nuestro servidor.&lt;br /&gt;
&lt;br /&gt;
Para ello, usaremos la vista &lt;b&gt;&lt;a href=&quot;http://sys.master_files/&quot;&gt;sys.master_files&lt;/a&gt;&lt;/b&gt;, que nos proporciona información de cada uno de los ficheros de nuestras bases de datos, con todas sus propiedades. Algunas de ellas, incluidas en la consulta de ejemplo, son: &lt;b&gt;nombre &lt;/b&gt;del fichero, &lt;b&gt;ruta &lt;/b&gt;completa del fichero en disco, &lt;b&gt;tamaño&lt;/b&gt;, &lt;b&gt;estado &lt;/b&gt;y &lt;b&gt;&lt;a href=&quot;http://aprendiendosqlserver.blogspot.com.es/2012/08/crecimiento-automatico-de-los-ficheros.html&quot;&gt;configuración sobre su crecimiento&lt;/a&gt;&lt;/b&gt;, del que ya &lt;a href=&quot;http://aprendiendosqlserver.blogspot.com.es/2012/08/crecimiento-automatico-de-los-ficheros.html&quot;&gt;hablamos en posts anteriores&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/anonymous/10cb0d04ed8fd540fa2d.js&quot;&gt;&lt;/script&gt;

&lt;b&gt;Actualizado el 19 de septiembre de 2013:&lt;/b&gt; Ahora el script muestra el tamaño de los ficheros en Megabytes, mientras que, anteriormente, lo hacía en número de páginas de 8KB.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/2478097154387040970/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/10/listar-todos-los-ficheros-de-un.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/2478097154387040970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/2478097154387040970'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/10/listar-todos-los-ficheros-de-un.html' title='Listar todos los ficheros de un servidor SQL Server'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-3837083361934693890</id><published>2012-10-10T12:46:00.001+02:00</published><updated>2012-10-10T12:47:27.327+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="FROM"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><category scheme="http://www.blogger.com/atom/ns#" term="TABLESAMPLE"/><title type='text'>TABLESAMPLE, o cómo obtener una muestra aleatoria de registros de una tabla</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
¿Alguna vez has necesitado obtener una &lt;b&gt;muestra de datos&lt;/b&gt; totalmente &lt;b&gt;aleatoria&lt;/b&gt; de tu base de datos? En SQL Server es posible hacerlo, mediante la cláusula &lt;b&gt;TABLESAMPLE&lt;/b&gt;, que se aplica a la definición del origen de datos que vamos a recuperar con la &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms177634(v=sql.105).aspx&quot;&gt;cláusula FROM&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms189108(v=SQL.105).aspx&quot;&gt;TABLESAMPLE &lt;/a&gt;nos permite indicar un &lt;b&gt;número de filas o un porcentaje de filas a devolver&lt;/b&gt;, de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
--devuelve el 10% de las filas totales&lt;br /&gt;
--(dependiendo del tamaño de los registros en la base de datos, no del número de filas).&lt;br /&gt;
SELECT *&lt;br /&gt;
FROM YourTable&lt;br /&gt;
TABLESAMPLE (10 PERCENT)&amp;nbsp;&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
--devuelve una muestra de 15 filas del conjunto de resultados&lt;br /&gt;
SELECT *&lt;br /&gt;
FROM YourTable&lt;br /&gt;
TABLESAMPLE (15 ROWS)&amp;nbsp;&lt;/blockquote&gt;
&lt;br /&gt;
Algunas &lt;b&gt;consideraciones&lt;/b&gt; a la hora de usar TABLESAMPLE incluyen:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;No se puede usar en la definición de vistas&lt;/li&gt;
&lt;li&gt;No se puede usar en la definición de funciones de tabla inline&lt;/li&gt;
&lt;li&gt;No se puede aplicar a tablas devueltas por funciones tipo tabla&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/3837083361934693890/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/10/tablesample-o-como-obtener-una-muestra.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/3837083361934693890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/3837083361934693890'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/10/tablesample-o-como-obtener-una-muestra.html' title='TABLESAMPLE, o cómo obtener una muestra aleatoria de registros de una tabla'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-2845758155477659002</id><published>2012-10-03T09:48:00.001+02:00</published><updated>2012-10-03T12:23:52.100+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="concurso"/><category scheme="http://www.blogger.com/atom/ns#" term="puzzle"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><title type='text'>¡Ganador del premio por resolver los puzzles T-SQL!</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;a href=&quot;http://blog.sqlauthority.com/&quot;&gt;Pinal Dave&lt;/a&gt; ha anunciado a través de twitter el ganador del premio por resolver los dos puzzles SQL que planteaba ahora hace unos días, y de los que &lt;b&gt;&lt;a href=&quot;http://aprendiendosqlserver.blogspot.com.es/2012/09/puzzles-en-t-sql-te-atreves-encontrar.html&quot;&gt;nos hicimos eco en este mismo blog&lt;/a&gt;&lt;/b&gt;. Pues bien, parece que nuestras respuestas eran correctas :)

&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;es&quot; tw-align-center=&quot;tw-align-center&quot;&gt;
The winner of 2 T-SQL Puzzles and Win USD 50 worth Amazon Gift Card &lt;a href=&quot;http://t.co/uYiPigO4&quot; title=&quot;http://bit.ly/Odx9Wy&quot;&gt;bit.ly/Odx9Wy&lt;/a&gt;is @&lt;a href=&quot;https://twitter.com/jaimeml&quot;&gt;jaimeml&lt;/a&gt; - Congratulations!&lt;br /&gt;
— Pinal Dave (@pinaldave) &lt;a data-datetime=&quot;2012-10-03T06:30:35+00:00&quot; href=&quot;https://twitter.com/pinaldave/status/253381513536741376&quot;&gt;octubre 3, 2012&lt;/a&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;twitter-tweet tw-align-center&quot; lang=&quot;es&quot;&gt;
Great! :) RT @&lt;a href=&quot;https://twitter.com/pinaldave&quot;&gt;pinaldave&lt;/a&gt;: winner of 2 T-SQL Puzzles and Win USD 50 worth Amazon Card &lt;a href=&quot;http://t.co/UYEWrGpX&quot; title=&quot;http://bit.ly/Odx9Wy&quot;&gt;bit.ly/Odx9Wy&lt;/a&gt;is @&lt;a href=&quot;https://twitter.com/jaimeml&quot;&gt;jaimeml&lt;/a&gt; - Congratulations!&lt;br /&gt;
— Jaime Mtnz Lafargue (@jaimeml) &lt;a data-datetime=&quot;2012-10-03T06:38:26+00:00&quot; href=&quot;https://twitter.com/jaimeml/status/253383492849778688&quot;&gt;octubre 3, 2012&lt;/a&gt;&lt;/blockquote&gt;
&lt;script charset=&quot;utf-8&quot; src=&quot;//platform.twitter.com/widgets.js&quot;&gt;&lt;/script&gt;
&lt;script charset=&quot;utf-8&quot; src=&quot;//platform.twitter.com/widgets.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/2845758155477659002/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/10/ganador-del-premio-por-resolver-los.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/2845758155477659002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/2845758155477659002'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/10/ganador-del-premio-por-resolver-los.html' title='¡Ganador del premio por resolver los puzzles T-SQL!'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-7867699847247126064</id><published>2012-09-27T13:03:00.000+02:00</published><updated>2012-09-27T13:03:15.929+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Cast"/><category scheme="http://www.blogger.com/atom/ns#" term="COUNT"/><category scheme="http://www.blogger.com/atom/ns#" term="puzzle"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><title type='text'>Puzzles en T-SQL ¿te atreves a encontrar la respuesta?</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Recientemente, &lt;b&gt;Pinal Dave&lt;/b&gt; publicó en su blog &lt;a href=&quot;http://blog.sqlauthority.com/&quot;&gt;SQL Authority&lt;/a&gt; un &lt;a href=&quot;http://blog.sqlauthority.com/2012/09/20/sql-server-2-t-sql-puzzles-and-win-usd-50-worth-amazon-gift-card-and-25-other-prizes/&quot;&gt;post con dos puzzles&lt;/a&gt; para Transact SQL. La curiosidad nos hizo intentar averiguar las respuestas, y aquí va lo que descubrimos (podéis intentar adivinarlas antes de leer la solución):&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
&lt;b&gt;Puzzle 1.&lt;/b&gt; &lt;b&gt;¿Por qué la siguiente query produce como resultado un asterisco (*)?&lt;/b&gt;&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
SELECT CAST (100 AS varchar(2))&lt;/blockquote&gt;
Podríamos esperar un error de desbordamiento, que el 100 se truncara por alguna de sus extramos y quedase reducido a un 10 o a un doble cero (00). Pero no, SQL Server nos retorna un asterisco.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;u&gt;Solución:&lt;/u&gt;&lt;/b&gt; La &lt;a href=&quot;http://msdn.microsoft.com/es-es/library/ms187928.aspx&quot;&gt;MSDN&lt;/a&gt; nos explica cómo actúa el motor de la base de datos a la hora de convertir un número (smallint, int...) a una cadena. Si la cadena soporta caracteres Unicode (nchar o nvarchar), se producirá un error. Sin embargo, si estamos intentando convertir el número en un char o varchar con menor longitud de la necesaria, obtendremos un asterisco. Dicho asterisco -&lt;a href=&quot;http://msdn.microsoft.com/es-es/library/ms187928.aspx&quot;&gt;nos explica el artículo&lt;/a&gt;- quiere decir que la longitud resultante es demasiado corta para mostrar el valor.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii9f34FNw0Qm3BcUszbNyzKItsCvIt-5vW9wPZVa3QbnK4klw98P7ufHRSC2PrJLpMUQYAE4FEsAUvX3m9PuZp6BmnYiUhPkixg336RZ1KCQA4gRSLII4TSuil4M5_YMamAwxU_RgFddT9/s1600/Captura.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;160&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii9f34FNw0Qm3BcUszbNyzKItsCvIt-5vW9wPZVa3QbnK4klw98P7ufHRSC2PrJLpMUQYAE4FEsAUvX3m9PuZp6BmnYiUhPkixg336RZ1KCQA4gRSLII4TSuil4M5_YMamAwxU_RgFddT9/s640/Captura.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Conversiones de números en cadenas de tamaño insuficiente, según la MSDN&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;b&gt;Puzzle 2. ¿Cuál es la sentencia más corta que produce un 1 como resultado, sin usar números?&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Para esta pregunta encontramos una discusión abierta en el grupo &lt;a href=&quot;http://www.linkedin.com/groups/SQL-Server-Developers-86080&quot;&gt;SQL Server Developers&lt;/a&gt; de &lt;b&gt;&lt;a href=&quot;http://www.linkedin.com/in/jaimemartinezlafargue&quot;&gt;LinkedIn&lt;/a&gt;&lt;/b&gt;. Allí, el ingenio de algunos de los participantes nos llevó a respuestas cada vez más cortas. Os intentamos explicar cada una de ellas.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;u&gt;Solución:&lt;/u&gt;&lt;/b&gt;&amp;nbsp;Inicialmente nos encontramos con la siguiente query:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
SELECT COUNT(*)&lt;/blockquote&gt;
COUNT(*) nos devuelve el recuento del número de filas afectadas por la sentencia SELECT. Como no estamos devolviendo filas de una tabla, SQL asume que el número de filas devueltas es uno (como si ejecutásemos una SELECT de una lista de valores constantes - SELECT constante1, N&#39;constante2&#39;, dia-mes-año...)&lt;br /&gt;
&lt;br /&gt;
Con la misma longitud existe otra solución: Pedirle a SQL Server la longitud de una cadena de texto de un solo carácter. Así:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
SELECT LEN(&#39;a&#39;)&lt;/blockquote&gt;
Buenos intentos, pero se pueden mejorar. SQL Server acepta los tipos de datos money y smallmoney. Para representar estos tipos de datos, se pueden usar símbolos de moneda. Así, 100€ se pueden representar como €100. Si dejamos la parte numérica vacía, SQL Server interpreta que la cantidad es cero. Así, SELECT $ nos devolvería 0.00.&lt;br /&gt;
&lt;br /&gt;
A partir de un cero, ¿qué funciones SQL nos pueden devolver un uno? Son las siguientes:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
SELECT EXP($) -- El número e elevado a cero es uno.&lt;br /&gt;SELECT DAY($) -- El día cero para SQL Server es el 1 de enero de 1900, así que cogemos el día&lt;br /&gt;SELECT COS($) -- El coseno de 0 es 1.&lt;/blockquote&gt;
&lt;br /&gt;
&lt;br /&gt;
¿Podéis mejorarlo? :)&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/7867699847247126064/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/09/puzzles-en-t-sql-te-atreves-encontrar.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/7867699847247126064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/7867699847247126064'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/09/puzzles-en-t-sql-te-atreves-encontrar.html' title='Puzzles en T-SQL ¿te atreves a encontrar la respuesta?'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii9f34FNw0Qm3BcUszbNyzKItsCvIt-5vW9wPZVa3QbnK4klw98P7ufHRSC2PrJLpMUQYAE4FEsAUvX3m9PuZp6BmnYiUhPkixg336RZ1KCQA4gRSLII4TSuil4M5_YMamAwxU_RgFddT9/s72-c/Captura.PNG" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153574442463741229.post-3009415888876353310</id><published>2012-09-06T16:47:00.002+02:00</published><updated>2012-09-07T08:31:04.072+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Data Annotations"/><category scheme="http://www.blogger.com/atom/ns#" term="Entity Framework"/><category scheme="http://www.blogger.com/atom/ns#" term="Fluent API"/><category scheme="http://www.blogger.com/atom/ns#" term="MVC"/><category scheme="http://www.blogger.com/atom/ns#" term="POCO"/><title type='text'>Cómo determinar la clave primaria en una entidad con Entity Framework y Data Annotations</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Con Entity Framework 4.1, a las opciones del modelo primero (Model First) y base de datos primero (Database First), se añadió &lt;a href=&quot;http://msdn.microsoft.com/en-us/data/ee712907&quot;&gt;Code First&lt;/a&gt;. Con esta aproximación, el programador escribe clases (objetos &lt;a href=&quot;http://blogs.msdn.com/b/adonet/archive/2009/05/11/sneak-preview-persistence-ignorance-and-poco-in-entity-framework-4-0.aspx&quot;&gt;POCO&lt;/a&gt;) para cada una de las entidades que quiere manejar en su aplicación. Estas entidades pueden generar tablas en una nueva base de datos o ser mapeadas a una base de datos ya existente.&lt;br /&gt;
&lt;br /&gt;
En general, EF usa una serie de &lt;a href=&quot;http://blogs.msdn.com/b/efdesign/archive/2010/06/01/conventions-for-code-first.aspx&quot;&gt;convenciones&lt;/a&gt; para definir el modelo y mapearlo a la base de datos de forma automática.&amp;nbsp;Por ejemplo, Entity Framework puede&amp;nbsp;&lt;b&gt;reconocer automáticamente el campo que es clave primaria&lt;/b&gt;&amp;nbsp;de una tabla si éste se llama de la forma NombreTablaId&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
El problema.&lt;/h4&gt;
&lt;br /&gt;
Supongamos que estamos desarrollando una nueva aplicación para una colección de discos. Se trata de una aplicación web, que estamos programando con la arquitectura MVC. Si en ella tenemos una tabla que se llama Disco, &lt;b&gt;EF espera que el campo que sea clave primaria de la tabla se llame DiscoId&lt;/b&gt;. De no ser así, cuando intentemos crear, por ejemplo, el controlador para el modelo Disco, obtendremos el siguiente &lt;b&gt;error&lt;/b&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeLLYQM6KRNdvvUkn2qNM3SBTgCFEPWqmxDukrp0-u__QkwOXpyo5szh8lyvNaWPJzPS1mDY-JxpFZcczHJMKxcS6W4ZEULJznEgts_8vTG-O_DzBVx6aEoCWFrkbvDMMj7UJGffRhOnXL/s1600/Captura.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;205&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeLLYQM6KRNdvvUkn2qNM3SBTgCFEPWqmxDukrp0-u__QkwOXpyo5szh8lyvNaWPJzPS1mDY-JxpFZcczHJMKxcS6W4ZEULJznEgts_8vTG-O_DzBVx6aEoCWFrkbvDMMj7UJGffRhOnXL/s400/Captura.PNG&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Visual Studio nos dice que hay un error de validación en el modelo. Discography no tiene clave definida.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Si estamos creando una base de datos nueva, puede que lo más sencillo sea cambiar el nombre de nuestro campo clave primaria para adaptarlo a las necesidades del Entity Framework. Sin embargo, si&lt;b&gt; nuestra clave es una clave compuesta o estamos trabajando sobre una base de datos ya existente&lt;/b&gt; sobre la que no tenemos la posibilidad de cambiar el nombre de los campos, necesitamos una alternativa.&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;/h4&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
La solución.&lt;/h4&gt;
&lt;br /&gt;
Aquí es donde las &lt;a href=&quot;http://nicolocodev.wordpress.com/2012/05/31/entity-framework-sobre-data-annotations/&quot;&gt;Data Annotations&lt;/a&gt; vienen al rescate: Podemos indicarle a las propiedades de nuestra&lt;br /&gt;
entidad (nuestro modelo) ciertas características que lo definen mejor, para que Entity Framework comprenda correctamente cómo está definida. Una de ellas es la propiedad &lt;b&gt;KeyAttribute&lt;/b&gt;, representada como [Key]. Así le podemos decir al EF cuál de las columnas de nuestro objeto POCO es la que ejerce de clave primaria:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
[Key]&lt;br /&gt;
public int TableKey { get; set; }&lt;/blockquote&gt;
Si, además la &lt;b&gt;clave primaria&lt;/b&gt; es &lt;b&gt;compuesta&lt;/b&gt;, tenemos también solución: debemos indicar el atributo Key a todas las columnas que forman parte de la clave primara, indicando el orden de éstas en la misma, de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
[Key]&lt;br /&gt;
[Column(&quot;
TableKey1&quot;, Order = 0)]&lt;br /&gt;
public int&amp;nbsp;TableKey1&amp;nbsp;&amp;nbsp;{ get; set; }&lt;br /&gt;
[Key]&lt;br /&gt;
[Column(&quot;&amp;nbsp;TableKey2&quot;, Order = 1)]&lt;br /&gt;
public int&amp;nbsp;TableKey2 &amp;nbsp;{ get; set; }&lt;/blockquote&gt;
&lt;br /&gt;
Si hemos instalado las &lt;a href=&quot;http://visualstudiogallery.msdn.microsoft.com/72a60b14-1581-4b9b-89f2-846072eff19d&quot;&gt;Entity Framework Power Tools&lt;/a&gt;&amp;nbsp;(recomendable, aunque todavía en fase Beta), podremos ver cómo queda nuestro modelo tras realizar estas anotaciones (mediante clic derecho sobre el fichero contexto y eligiendo en el menú la opción Entity Framework / View Entity Data Model):&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFFTMnB-aOsxLcWzwFhoNpkTpalhB9Hv1tb00RiHHEQzGStf20GOxP3C-k-TO8Dprt6VYg-Yg4iIV3pn9x-h4bQ6c9ZH_7MRMucLTgrVnUUodI9AgkSpHbYYUQ96422X7UWM0erdIKkmGs/s1600/Captura.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFFTMnB-aOsxLcWzwFhoNpkTpalhB9Hv1tb00RiHHEQzGStf20GOxP3C-k-TO8Dprt6VYg-Yg4iIV3pn9x-h4bQ6c9ZH_7MRMucLTgrVnUUodI9AgkSpHbYYUQ96422X7UWM0erdIKkmGs/s1600/Captura.PNG&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Diagrama de nuestra entidad Disco, con los dos campos formando parte de la clave primaria.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;/h4&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Data Annotations vs Fluent API.&lt;/h4&gt;
&lt;br /&gt;
Existe una alternativa a las Data Annotations, llamada Fluent API, que veremos más adelante. Data Annotations presenta una manera más sencilla de configurar el modelo, mientras que Fluent API ofrece más posibilidades. Además, las Data Annotations son usadas al mismo tiempo por Entity Framework y por MVC, para validar los datos que el usuario introduce en las vistas (páginas web). Sin embargo, es posible que si nuestro modelo es ligeramente complejo, necesitemos de la potencia de Fluent API.&lt;br /&gt;
&lt;br /&gt;
Puedes leer más acerca de Data Annotations y Fluent API &lt;a href=&quot;http://msdn.microsoft.com/en-us/data/ee712907&quot;&gt;aquí&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Puedes encontrar más información acerca de las anotaciones en:&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://sankarsan.wordpress.com/2011/06/05/entity-framework-4-1-annotationspart-1/&quot;&gt;http://sankarsan.wordpress.com/2011/06/05/entity-framework-4-1-annotationspart-1/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://aprendiendosqlserver.blogspot.com/feeds/3009415888876353310/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/09/como-determinar-la-clave-primaria-en.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/3009415888876353310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153574442463741229/posts/default/3009415888876353310'/><link rel='alternate' type='text/html' href='http://aprendiendosqlserver.blogspot.com/2012/09/como-determinar-la-clave-primaria-en.html' title='Cómo determinar la clave primaria en una entidad con Entity Framework y Data Annotations'/><author><name>lafargue</name><uri>http://www.blogger.com/profile/14455232775259438470</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeLLYQM6KRNdvvUkn2qNM3SBTgCFEPWqmxDukrp0-u__QkwOXpyo5szh8lyvNaWPJzPS1mDY-JxpFZcczHJMKxcS6W4ZEULJznEgts_8vTG-O_DzBVx6aEoCWFrkbvDMMj7UJGffRhOnXL/s72-c/Captura.PNG" height="72" width="72"/><thr:total>0</thr:total></entry></feed>