<?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: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-3525590579238673765</id><updated>2012-02-08T09:55:07.990-03:00</updated><category term='DATETIME2FROMPARTS'/><category term='RAISE ERROR'/><category term='SQL'/><category term='seguridad'/><category term='SQL Denali'/><category term='UNIQUEIDENTIFIER'/><category term='grant'/><category term='simulacion'/><category term='job name'/><category term='SQL 11'/><category term='test'/><category term='EXECUTE AS'/><category term='restore'/><category term='Auditoria'/><category term='LEAD'/><category term='SMALLDATETIMEFROMPARTS'/><category term='recursividad'/><category term='Managment Studio'/><category term='sp_who'/><category term='roles'/><category term='IP'/><category term='performance'/><category term='CodeCamp'/><category term='Contained Databases'/><category term='Windows Cluster'/><category term='Analisys Services'/><category term='Multiples servidores'/><category term='DBCC PAGE'/><category term='SQL2008'/><category term='secuencia'/><category term='sp_change_users_login'/><category term='TIMEFROMPARTS'/><category term='sp_who2'/><category term='DATEPART'/><category term='SPID'/><category term='stress test'/><category term='sp_cdc_disable_db'/><category term='xp_sqlagent_enum_jobs'/><category term='LDAP'/><category term='certificado'/><category term='common table expression'/><category term='fin de mes'/><category term='MERGE'/><category term='SQL 2012'/><category term='logins'/><category term='certificate'/><category term='sys.partitions'/><category term='cmdshell'/><category term='licencia'/><category term='ChangeDataCapture'/><category term='Sequence'/><category term='CREATE USER WITHOUT LOGIN'/><category term='MeasureGroups'/><category term='UNIX'/><category term='$system.discover'/><category term='FETCH'/><category term='SQL 2008'/><category term='SQL 2008 SP3'/><category term='LOGIN'/><category term='renombrar'/><category term='drop and create'/><category term='SQL Server'/><category term='Service Pack'/><category term='SP3'/><category term='Server 2012 Release Candidate 0'/><category term='Oracle'/><category term='IDENTITY'/><category term='TOP'/><category term='LAG'/><category term='PowerShell'/><category term='NEXT VALUE FOR'/><category term='recursión'/><category term='SP_REFRESHVIEW'/><category term='DATEFROMPARTS'/><category term='local_net_address'/><category term='Eliminar tabla temporal'/><category term='TRY_PARSE'/><category term='dm_exec_sessions'/><category term='CREATE USER'/><category term='WITHOUT LOGIN'/><category term='NEXTVAL'/><category term='job_id'/><category term='local_tcp_port'/><category term='EOMONTH'/><category term='DATETIMEOFFSETFROMPARTS'/><category term='linked servers'/><category term='Eliminar tabla temporaria'/><category term='SQL Server 2008'/><category term='sp_MSForeachdb'/><category term='execute'/><category term='colgado'/><category term='DATEDIFF MAXRECURSION'/><category term='CREATE TABLE'/><category term='TRY_CONVERT'/><category term='RML'/><category term='CHOOSE'/><category term='FILENAME'/><category term='TSQL'/><category term='Waitresource'/><category term='OFFSET'/><category term='DATETIMEFROMPARTS'/><category term='sysjobhistory'/><category term='jobs'/><category term='multisql'/><category term='CTE'/><category term='SELF JOIN'/><category term='Active Directory'/><category term='policys'/><category term='Server Groups'/><category term='microsoft'/><category term='licenciamiento'/><category term='FILESTREAM'/><category term='SQL2012'/><category term='THROW'/><category term='CDC'/><category term='ALTER DATABASE'/><category term='AD'/><category term='DATEFIRST'/><title type='text'>Aiello DBA</title><subtitle type='html'>Mi día a día con SQL</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>48</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-1393782113940831089</id><published>2012-02-08T09:55:00.000-03:00</published><updated>2012-02-08T09:55:08.005-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2012'/><category scheme='http://www.blogger.com/atom/ns#' term='CHOOSE'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Denali'/><title type='text'>Nueva funcion CHOOSE en SQL 2012</title><content type='html'>En esta oportunidad veremos la función CHOOSE es una de las novedades de SQL 2012. Nos permite pasar un número (primer parámetro) y seleccionar un valor en base a éste.&lt;br /&gt;Este mismo funcionamiento lo podíamos obtener con una tabla de códigos con la cual hacer el INNER JOIN, pero de esta forma podemos hacerlo mas simple. Veamos un ejemplo.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 18/01/12&lt;br /&gt;-- Description: Nueva funcion CHOOSE en SQL 2012&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;-- Primero creamos una tabla con valores de ejemplo para poder probar la funcion&lt;br /&gt;CREATE TABLE #PruebaCHOOSE(&lt;br /&gt;id INT PRIMARY KEY, codigo INT&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;INSERT INTO #PruebaCHOOSE VALUES&lt;br /&gt;(1, -2),&lt;br /&gt;(2, 3),&lt;br /&gt;(3, 2),&lt;br /&gt;(4, 1),&lt;br /&gt;(5, 5),&lt;br /&gt;(6, 2),&lt;br /&gt;(7, 1)&lt;br /&gt;&lt;br /&gt;-- Utilizamos el campo codigo para seleccionar una de las tres posibles descripciones&lt;br /&gt;SELECT id, CHOOSE(codigo, 'CODIGO1', 'CODIGO2', 'CODIGO3')&lt;br /&gt;FROM #PruebaCHOOSE&lt;br /&gt;&lt;br /&gt;DROP TABLE #PruebaCHOOSE&lt;/pre&gt;&lt;br /&gt;Como podemos ver en el ejemplo el uso es muy simple, y en caso de que el índice no se encuentre entre 1 y la cantidad de opciones retorna null. &lt;br /&gt;Esta función requiere siempre que como mínimo se le pasen dos parámetros, el primero el del índice y el segundo un código (al menos uno).&lt;br /&gt;&lt;br /&gt;Pro&lt;br /&gt;Muy simple de utilizar y muy clara&lt;br /&gt;Contra&lt;br /&gt;Va contra la normalización&lt;br /&gt;No genera error de fuera de índice. Esto es muy personal pero me parece que es para problemas que no genere una excepción cuando el valor ingresado no corresponde a una de las opciones&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-1393782113940831089?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/1393782113940831089/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2012/02/nueva-funcion-choose-en-sql-2012.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/1393782113940831089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/1393782113940831089'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2012/02/nueva-funcion-choose-en-sql-2012.html' title='Nueva funcion CHOOSE en SQL 2012'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-8922533406267656361</id><published>2012-02-03T13:01:00.003-03:00</published><updated>2012-02-03T13:01:58.642-03:00</updated><title type='text'>Lanzamiendo online de SQL2012</title><content type='html'>El 7 de marzo es el lanzamiento online del SQL2012! les dejo un link con la agenda para que puedan ir palpitandolo: &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.sqlserverlaunch.com/LATAM/agenda"&gt;http://www.sqlserverlaunch.com/LATAM/agenda&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-8922533406267656361?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/8922533406267656361/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2012/02/lanzamiendo-online-de-sql2012.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/8922533406267656361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/8922533406267656361'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2012/02/lanzamiendo-online-de-sql2012.html' title='Lanzamiendo online de SQL2012'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-4868584656590187292</id><published>2012-02-03T09:42:00.000-03:00</published><updated>2012-02-03T09:42:13.434-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2012'/><category scheme='http://www.blogger.com/atom/ns#' term='SELF JOIN'/><category scheme='http://www.blogger.com/atom/ns#' term='LAG'/><category scheme='http://www.blogger.com/atom/ns#' term='LEAD'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Denali'/><title type='text'>LAG y LEAD, ver el registro anterior o siguiente en SQL 2012</title><content type='html'>El SQL 2012 sigue teniendo novedades interesantes para mostrar, así que continuaré con la introducción a las nuevas funciones TSQL. Hoy es el turno de LAG y LEAD.&lt;br /&gt;Una cosa que siempre me molestó es cuando un cliente decía "pero esto es fácil, en el excel lo hago" y quizá en SQL no era tan simple de expresar. Un caso común de esto es cuando una "celda" se calculaba utilizando valores de su registro pero también del anterior.&lt;br /&gt;La forma habitual de hacer esto en sql es con un self join, y ahí empezar a remarla. En la versión 2012 contamos con una forma mucho mas cómoda y es con las funciones LAG y LEAD.&lt;br /&gt;La función LAG nos permite consultar el registro inmediatamente anterior al que estamos procesando, y si lo deseamos tambien dos anteriores o el número deseado. Veamos con un ejemplo que es mas claro.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 18/01/12&lt;br /&gt;-- Description: Hacer un cálculo en base al registro anterior en SQL 2012: LAG y LEAD&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;-- Primero creamos una tabla con valores de ejemplo para poder probar la funcion&lt;br /&gt;CREATE TABLE #PruebaLAG_LEAD(&lt;br /&gt;id INT PRIMARY KEY, dia DATE, ventas INT&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;INSERT INTO #PruebaLAG_LEAD VALUES&lt;br /&gt;(1, '20120101', 10),&lt;br /&gt;(2, '20120102', 11),&lt;br /&gt;(3, '20120103', 13),&lt;br /&gt;(4, '20120104', 8),&lt;br /&gt;(5, '20120105', 10),&lt;br /&gt;(6, '20120106', 15),&lt;br /&gt;(7, '20120107', 10)&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;Dada la siguiente tabla deseamos saber la diferencia de ventas de un día con el anterior, así que con los valores de ejemplo obtendriamos:&lt;br /&gt;(1, '20120101', NULL),&lt;br /&gt;(2, '20120102', 1),&lt;br /&gt;(3, '20120103', 2),&lt;br /&gt;(4, '20120104', -5),&lt;br /&gt;(5, '20120105', 2),&lt;br /&gt;(6, '20120106', 5),&lt;br /&gt;(7, '20120107', -5)&lt;br /&gt;*/&lt;br /&gt;-- En la forma tradicional esto lo podríamos hacer así:&lt;br /&gt;SELECT t1.id, t1.dia, t1.ventas, t2.ventas ventaAnterior, t1.ventas - t2.ventas ventaDiferencia&lt;br /&gt;&amp;nbsp; FROM #PruebaLAG_LEAD t1&lt;br /&gt;&amp;nbsp;LEFT JOIN #PruebaLAG_LEAD t2 ON t1.id -1 = t2.id&lt;br /&gt;&lt;br /&gt;-- Es importante resaltar el null del primer registro, causado por el LEFT JOIN. Esto se debe a que en mi primer registro no tiene sentido comparar con el valor anterior, se va fuera de la lógica de negocio.&lt;br /&gt;&lt;br /&gt;-- Ahora veamos como podríamos escribir esto mismo en SQL 2012&lt;br /&gt;&lt;br /&gt;SELECT *, LAG(ventas, 1, null)OVER(ORDER BY dia) as ventaAnterior, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ventas - LAG(ventas, 1)OVER(ORDER BY dia) as ventaDiferencia&lt;br /&gt;&amp;nbsp; FROM #PruebaLAG_LEAD&lt;br /&gt;&lt;br /&gt;DROP TABLE #PruebaLAG_LEAD&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como ven es muy comodo de utilizar y viene en diferentes sabores. Los tres parámetros que toma (los últimos dos opcionales) son:&lt;br /&gt;LAG(campo, cantidad de registros anteriores a buscar, valor default si es nulo)&lt;br /&gt;&lt;br /&gt;En caso de que no se indique cuantos registros atras mirar se asume uno. Y en caso de no indicar un valor default es null (tal como en el ejemplo que utilice una vez null de forma explícita y otra implícita).&lt;br /&gt;&lt;br /&gt;Lo único que no vimos es que pasaría si quisiera ignorar el registro inicial, para no tener ese valor nulo. En las versiones anteriores me bastaría con cambiar el LEFT JOIN por un INNER JOIN, pero ahora debo poner un poco mas de mano y utilizar una CTE.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 18/01/12&lt;br /&gt;-- Description: Hacer un cálculo en base al registro anterior en SQL 2012: LAG y LEAD&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;-- Primero creamos una tabla con valores de ejemplo para poder probar la funcion&lt;br /&gt;CREATE TABLE #PruebaLAG_LEAD(&lt;br /&gt;id INT PRIMARY KEY, dia DATE, ventas INT&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;INSERT INTO #PruebaLAG_LEAD VALUES&lt;br /&gt;(1, '20120101', 10),&lt;br /&gt;(2, '20120102', 11),&lt;br /&gt;(3, '20120103', 13),&lt;br /&gt;(4, '20120104', 8),&lt;br /&gt;(5, '20120105', 10),&lt;br /&gt;(6, '20120106', 15),&lt;br /&gt;(7, '20120107', 10)&lt;br /&gt;&lt;br /&gt;-- Como ignorar el registro inicial para que no quede el NULL&lt;br /&gt;&lt;br /&gt;;WITH cte AS(&lt;br /&gt;SELECT ROW_NUMBER()OVER(ORDER BY dia) rn, *, LAG(ventas, 1, null)OVER(ORDER BY dia) as ventaAnterior, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ventas - LAG(ventas, 1)OVER(ORDER BY dia) as ventaDiferencia&lt;br /&gt;&amp;nbsp; FROM #PruebaLAG_LEAD&lt;br /&gt;)&lt;br /&gt;SELECT * &lt;br /&gt;&amp;nbsp; FROM cte&lt;br /&gt;WHERE rn&amp;gt;1&lt;br /&gt;&lt;br /&gt;DROP TABLE #PruebaLAG_LEAD&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La función LEAD es equivalente pero para el siguiente registro en lugar del anterior así que no entraremos en mas detalle.&lt;br /&gt;&lt;br /&gt;Pro&lt;br /&gt;Hace que sea mucho mas simple el tipo de cálculos de valores precedentes&lt;br /&gt;Es mas declarativo y eficiente que la vieja forma&lt;br /&gt;Es muy flexible, puede ser variable el segundo campo, pudiendo utilizar algo rebuscado como comparar todo contra el principio de mes&lt;br /&gt;Contra&lt;br /&gt;Es incomodo si no se quiere incluir el registro inicial&lt;br /&gt;&lt;br /&gt;Mas info de LAG: http://msdn.microsoft.com/es-us/library/hh231256(v=sql.110).aspx&lt;br /&gt;Mas info de LEAD: http://msdn.microsoft.com/es-us/library/hh213125(v=sql.110).aspx&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-4868584656590187292?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/4868584656590187292/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2012/02/lag-y-lead-ver-el-registro-anterior-o.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4868584656590187292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4868584656590187292'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2012/02/lag-y-lead-ver-el-registro-anterior-o.html' title='LAG y LEAD, ver el registro anterior o siguiente en SQL 2012'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-661892087736676341</id><published>2012-01-30T09:33:00.000-03:00</published><updated>2012-01-30T09:33:42.595-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2012'/><category scheme='http://www.blogger.com/atom/ns#' term='fin de mes'/><category scheme='http://www.blogger.com/atom/ns#' term='TSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='EOMONTH'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Denali'/><title type='text'>Saber el fin de mes en SQL 2012: EOMONTH</title><content type='html'>Buenas a todos!!! En este articulo continuaremos contando las novedades del TSQL de SQL 2012.&lt;br /&gt;En esta oportunidad quiero presentarles la función EOMONTH. Esta función se puede utilizar de dos maneras, con un solo parámetro o con dos.&lt;br /&gt;Cuando la utilizamos con un solo parámetro, éste debe ser de tipo fecha y la función lo que retorna es el último día del mes correspondiente al parámetro. Esto en versiones anteriores de SQL se podía hacer de varias formas, pero de todas era bastante engorroso.&lt;br /&gt;En el ejemplo veremos alguna de esas alternativas.&lt;br /&gt;La segunda opción, muy práctica por cierto, es pasandole la fecha y otro parámetro que indica cuantos meses sumar o restar. Esto lo que hará es retornar el fin de mes siguiente. Veamos como funcionan.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 18/01/12&lt;br /&gt;-- Description: Saber el fin de mes en SQL 2012&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;-- Primero declaramos una variable de tipo fecha para la prueba. Puede ser datetime sin inconveniente.&lt;br /&gt;DECLARE @date DATE;&lt;br /&gt;SET @date = GETDATE();&lt;br /&gt;&lt;br /&gt;-- Veamos una de las opciones de como calcular el principio de mes y fin de mes con la sintaxis permitida en versiones anteriores de SQL.&lt;br /&gt;-- Repito, esta es una forma de hacerlo pero hay varias&lt;br /&gt;SELECT @date AS FechaOriginal,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DATEADD(DAY,-1 * (DATEPART(DAY, @date))+1, @date) AS PrincipioDeMes,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEADD(DAY,-1 * (DATEPART(DAY, @date))+1, @date))) AS FinDeMes&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;-- Ahora con la función EOMONTH podemos expresarlo de forma directa&lt;br /&gt;SELECT EOMONTH ( @date ) as FinDeMes,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EOMONTH ( @date, 1 ) as FinSiguienteMes,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EOMONTH ( @date, -1 ) as FinMesAnterior;&lt;br /&gt;&lt;br /&gt;-- Y si en cambio no queremos el fin de mes sino el comienzo, podemos hacer lo siguiente&lt;br /&gt;-- -&amp;gt; Calcular el fin del mes anterior y sumarle un dia&lt;br /&gt;SELECT DATEADD(DAY, 1, EOMONTH ( @date, -1 )) as PrincipioDeMes;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Pro&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Permite escribir de forma muy declarativa y simple el fin de mes, algo que es muy utilizado&lt;/li&gt;&lt;li&gt;La sintaxis es muy intuitiva&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Contra&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No entiendo porque no se aplica lo mismo para principio de mes, esto hacer perder ortogonalidad. Podria ser otra o un parámetro que indique si se desea el fin o el comienzo de mes&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Para mas información: http://msdn.microsoft.com/en-us/library/hh213020%28v=sql.110%29.aspx&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-661892087736676341?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/661892087736676341/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2012/01/saber-el-fin-de-mes-en-sql-2012-eomonth.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/661892087736676341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/661892087736676341'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2012/01/saber-el-fin-de-mes-en-sql-2012-eomonth.html' title='Saber el fin de mes en SQL 2012: EOMONTH'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-3409934367122549694</id><published>2012-01-24T08:57:00.000-03:00</published><updated>2012-01-24T08:57:48.693-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DATETIMEOFFSETFROMPARTS'/><category scheme='http://www.blogger.com/atom/ns#' term='TIMEFROMPARTS'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2012'/><category scheme='http://www.blogger.com/atom/ns#' term='DATEPART'/><category scheme='http://www.blogger.com/atom/ns#' term='TSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='SMALLDATETIMEFROMPARTS'/><category scheme='http://www.blogger.com/atom/ns#' term='DATETIMEFROMPARTS'/><category scheme='http://www.blogger.com/atom/ns#' term='DATEFROMPARTS'/><category scheme='http://www.blogger.com/atom/ns#' term='DATETIME2FROMPARTS'/><title type='text'>Funciones de fechas en SQL 2012</title><content type='html'>En éste articulo hablaremos de las nuevas funciones para manejo de fechas que se incoporan en SQL 2012. Son un conjunto de funciones que se llaman xxxFROMPARTS y lo que permiten es ingresar los valores numéricos que forman cada parte de una fecha y retornar en el tipo fecha que corresponda.&lt;br /&gt;Estas funciones son 6, una para que tipo de fecha que maneja el SQL Server. Tomemos como ejemplo la primera para poder fijar la idea.&lt;br /&gt;Si yo tengo tres campos numericos, en uno guardo el dia, en otro el mes y en otro el año, antes debíamos hacer varias operaciones para poder pasar eso a una fecha (string mediante), lo cual siempre me pareció extraño, porque el camino inverso (dada una fecha obtener el número del mes) era posible facilmente con la función DATEPART.&lt;br /&gt;Ahora utilizando la función DATEFROMPARTS le pasamos esos 3 argumentos y nos retorna algo de tipo fecha.&lt;br /&gt;Si en lugar de hacerlo para una fecha lo queremos hacer para una hora, tenemos TIMEFROMPARTS, y así para que tipo de datos "tiempo" que tiene el SQL Server. &lt;br /&gt;Veamos el ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 13/01/12&lt;br /&gt;-- Description: Manejo de fechas en SQL 2012&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;SELECT DATEFROMPARTS&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ( 2010, 12, 31 ) AS Salida;&lt;br /&gt;SELECT TIMEFROMPARTS&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ( 23, 59, 59, 0, 0 ) AS Salida;&lt;br /&gt;&lt;br /&gt;SELECT SMALLDATETIMEFROMPARTS&amp;nbsp;&amp;nbsp;&amp;nbsp; ( 2010, 12, 31, 23, 59 ) AS Salida&lt;br /&gt;SELECT DATETIMEFROMPARTS&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ( 2010, 12, 31, 23, 59, 59, 0 ) AS Salida;&lt;br /&gt;SELECT DATETIME2FROMPARTS&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ( 2010, 12, 31, 23, 59, 59, 0, 0 ) AS Salida;&lt;br /&gt;SELECT DATETIMEOFFSETFROMPARTS&amp;nbsp;&amp;nbsp; ( 2010, 12, 31, 14, 23, 23, 0, 12, 0, 7 ) AS Salida;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Pros&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Es muy cómodo de utilizar&lt;/li&gt;&lt;li&gt;Era algo deseable visto que el camino inverso (fecha-&amp;gt;número) ya era posible con DATEPART&lt;/li&gt;&lt;li&gt;Deja de ser necesario y trabajoso pasar por un VARCHAR para poder transformar una fecha desde sus partes numéricas&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Contras&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Para una transformación es DATEPART pero la vuelta es con otra, no junta los conceptos&lt;/li&gt;&lt;li&gt;Muchas funciones para lo mismo en lugar de hacer una sobrecarga y que lo defina el motor&lt;/li&gt;&lt;li&gt;Funciones muy "sensibles". Siempre esperan todos los parámetros. Calculo que ésto es consecuencia del punto anterior&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Espero sus opiniones.&lt;br /&gt;Saludos!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-3409934367122549694?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/3409934367122549694/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2012/01/funciones-de-fechas-en-sql-2012.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/3409934367122549694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/3409934367122549694'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2012/01/funciones-de-fechas-en-sql-2012.html' title='Funciones de fechas en SQL 2012'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-3439373665188607057</id><published>2012-01-17T09:59:00.000-03:00</published><updated>2012-01-19T09:16:04.197-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2012'/><category scheme='http://www.blogger.com/atom/ns#' term='TOP'/><category scheme='http://www.blogger.com/atom/ns#' term='FETCH'/><category scheme='http://www.blogger.com/atom/ns#' term='OFFSET'/><title type='text'>OFFSET y FETCH, paginando sin el TOP en SQL 2012</title><content type='html'>Siguiendo con los artículos sobre nuevas funcionalidades para desarrolladores en SQL 2012 ahora les presento el concepto de paginación.&lt;br /&gt;Hay otras bases del mercado que ya hace bastante tiempo tienen este concepto, pero en SQL Server si queriamos no traer toda la consulta sino solamente una parte la única herramienta con la que contabamos era la sentencia TOP (o algunas trampas para poder simular la paginacion). La sentencia TOP nos permitía traer solamente los N primeros valores de una consulta. Pero es muy habitual tener una interfaz de cara al cliente que le muestra un gran resultado por páginas, entonces desearía poder traer solamente lo que voy a mostrar, y para la primer página me sirve el TOP pero para el resto no.&lt;br /&gt;Con el objetivo de apalear este problema es que se incorporó OFFSET y FETCH. Al utilizar estas sentencias en lugar de devolver todos los valores, devuelve a partir del valor indicado en OFFSET. ¿Cuantos valores retirna? la cantidad que se indique en FETCH.&lt;br /&gt;Para que esto funcione es necesario que la consulta tenga un ORDER BY. Veamos un ejemplo.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 13/01/12&lt;br /&gt;-- Description: Paginacion en SQL 2012&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;-- Llenemos una tabla con valores para poder probar&lt;br /&gt;CREATE TABLE #Temp(id INT PRIMARY KEY, campo2 INT, campo3 VARCHAR(100))&lt;br /&gt;DECLARE @i INT&lt;br /&gt;SET @i = 0&lt;br /&gt;WHILE @i&amp;lt;100&lt;br /&gt;BEGIN&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; INSERT INTO #Temp&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT @i, @i*7, 'Fila ' + CAST(@i AS VARCHAR)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SET @i = @i + 1&lt;br /&gt;END&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- Primera prueba: ver el contenido&lt;br /&gt;SELECT * FROM #Temp&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- Forma vieja de paginar&lt;br /&gt;SELECT TOP 10 * &lt;br /&gt;&amp;nbsp; FROM #Temp&lt;br /&gt;ORDER BY campo2&lt;br /&gt;&lt;br /&gt;SELECT TOP 10 * &lt;br /&gt;&amp;nbsp; FROM #Temp&lt;br /&gt;&amp;nbsp;WHERE campo2&amp;gt;=70&lt;br /&gt;ORDER BY campo2&lt;br /&gt;&lt;br /&gt;-- Forma nueva de paginar&lt;br /&gt;-- Obtengo los primeros 10 resultados&lt;br /&gt;SELECT * &lt;br /&gt;&amp;nbsp; FROM #Temp&lt;br /&gt;ORDER BY campo2&lt;br /&gt;OFFSET 0 ROWS&lt;br /&gt;FETCH NEXT 10 ROWS ONLY;&lt;br /&gt;&lt;br /&gt;-- Obtengo los siguientes 10!!!&lt;br /&gt;SELECT * &lt;br /&gt;&amp;nbsp; FROM #Temp&lt;br /&gt;ORDER BY campo2&lt;br /&gt;OFFSET 10 ROWS&lt;br /&gt;FETCH NEXT 10 ROWS ONLY;&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;DROP TABLE #Temp&lt;br /&gt;GO&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Según la documentación oficial se recomienda utilizar FETCH en lugar del viejo TOP. El motivo es que con el TOP es necesario ejecutar tantas consultas como páginas si deseen, y siempre es necesario hacer nuevamente una búsqueda. Con el FETCH el motor se encarga de que cuando volvamos a pedir algo no requiera reprocesarlo sino utilizar lo que ya se calculó.&lt;br /&gt;Para que esto funcione correctamente se deben cumplir algunas simples condiciones:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;La informacion a consultar no debe cambiar entre consulta y consulta&lt;/li&gt;&lt;li&gt;El ORDER BY debería ser sobre una columna (o varias) que sea única&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Si todo esto se cumple (lo cual no es complicado) podremos comenzar a disfrutar de los beneficios del FETCH.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-3439373665188607057?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/3439373665188607057/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2012/01/offset-y-fetch-el-reemplazo-del-top-en.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/3439373665188607057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/3439373665188607057'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2012/01/offset-y-fetch-el-reemplazo-del-top-en.html' title='OFFSET y FETCH, paginando sin el TOP en SQL 2012'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-198580351254939139</id><published>2012-01-13T09:35:00.001-03:00</published><updated>2012-01-13T11:43:07.537-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='THROW'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2012'/><category scheme='http://www.blogger.com/atom/ns#' term='RAISE ERROR'/><title type='text'>Manejo de excepciones en SQL 2012</title><content type='html'>Antes que nada quiero saludar a todo el mundo luego de un mes de descanzo totalmente alejado de la pc! Ahora con todas las ganas de comenzar el 2012! Ahora a comenzar con el artículo.&lt;br /&gt;En SQL 2008R2 o inferior la forma que teniamos de hacer el manejo de errores era utilizando el TRY y CATCH y luego en caso de ser necesario generar un error con RAISE ERROR. Cualquiera que esté familiarizado con el paradigma de objetos también lo está con el concepto de "lanzar excepciones". Este paso es lo que se ha implementado en esta nueva versión de SQL con la instrucción THROW.&lt;br /&gt;Veamos un ejemplo de como manejabamos las excepciones antes:&lt;br /&gt;&lt;pre class="sql" name="code"&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 13/01/12&lt;br /&gt;-- Description: Ejemplo de manejo de errores en SQL2012&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;BEGIN TRY&lt;br /&gt;&amp;nbsp;SELECT 1/0&lt;br /&gt;END TRY&lt;br /&gt;BEGIN CATCH&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DECLARE @ErrMsg nvarchar(4000), @ErrSeverity int&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT @ErrMsg = ERROR_MESSAGE(),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; @ErrSeverity = ERROR_SEVERITY()&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; RAISERROR(@ErrMsg, @ErrSeverity, 1)&lt;br /&gt;END CATCH&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;En cambio ahora con esta nueva instrucción sería:&lt;br /&gt;&lt;pre class="sql" name="code"&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 13/01/12&lt;br /&gt;-- Description: Ejemplo de manejo de errores en SQL2012&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;BEGIN TRY&lt;br /&gt;&amp;nbsp;SELECT 1/0&lt;br /&gt;END TRY&lt;br /&gt;BEGIN CATCH&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; THROW 51000, 'Mensaje de error a elección!', 1;&lt;br /&gt;END CATCH&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Nuestra lógica no sufrió grandes cambios pero esto permite empezar a pensar en un paradigma de excepciones nuestro código.&lt;br /&gt;Algunas diferencias entre el comportamiento de una y otra son:&lt;br /&gt;RAISE ERROR&lt;br /&gt;&lt;ul&gt;&lt;li&gt;El error debe estar definido en la sys.messages&lt;/li&gt;&lt;li&gt;Los mensajes pueden utilizar el caracter % para ser parametrizados&lt;/li&gt;&lt;li&gt;Se puede definir la severidad del error, siendo esta cualquier número, incluyendo las mas graves&lt;/li&gt;&lt;li&gt;No se puede arrojar en cadena (hacia los llamadores) la excepción. Cuando se genera una nueva "pisa" la anterior&lt;/li&gt;&lt;/ul&gt;En cambio con la nueva instrucción THROW&lt;br /&gt;&lt;ul&gt;&lt;li&gt; El mensaje de error se define al momento de lanzar la excepción&lt;/li&gt;&lt;li&gt;Los mensajes NO pueden ser parametrizados. Tener en cuenta que al generarse en el momento los mensajes, esto no debería ser un gran problema&lt;/li&gt;&lt;li&gt;La severidad del error es siempre la misma, severidad 16&lt;/li&gt;&lt;li&gt;Un sp que captura una excepción puede relanzarla tal como en cualquier entorno de objetos&lt;/li&gt;&lt;/ul&gt;A mi ver es algo muy cómodo. Lo bueno es que no deberán salir todos corriendo a cambiar su código porque aún se mantendrá compatibilidad con ambas.&lt;br /&gt;Espero que les haya servido.&lt;br /&gt;&lt;br /&gt;Para mas info:&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ee677615%28v=sql.110%29.aspx"&gt;http://msdn.microsoft.com/en-us/library/ee677615%28v=sql.110%29.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-198580351254939139?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/198580351254939139/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2012/01/nuevas-manejo-de-excepciones-en-sql.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/198580351254939139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/198580351254939139'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2012/01/nuevas-manejo-de-excepciones-en-sql.html' title='Manejo de excepciones en SQL 2012'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-5636241654344492734</id><published>2011-11-29T10:31:00.001-03:00</published><updated>2011-11-29T10:32:06.576-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2012'/><category scheme='http://www.blogger.com/atom/ns#' term='TSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='TRY_CONVERT'/><category scheme='http://www.blogger.com/atom/ns#' term='TRY_PARSE'/><title type='text'>Nuevas funciones TRY_PARSE y TRY_CONVERT en SQL 2012</title><content type='html'>Hay muchas funciones nuevas en SQL 2012 apuntadas al desarrollo, y me gustaría ir dedicandole un lugar. La primera que veremos es TRY_PARSE y TRY_CONVERT que permiten ejecutar lo mismo que sus predecesoras pero sin dar error cuando la conversión no se puede realizar. Veremos algunos ejemplos de su aplicación:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 17/11/11&lt;br /&gt;-- Description: Ejemplo de manejo de errores en SQL2012 aca Denali&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;-- Llenemos una tabla con valores para poder probar&lt;br /&gt;CREATE TABLE #Temp(id INT PRIMARY KEY, campo2 INT, campo3 VARCHAR(100))&lt;br /&gt;INSERT INTO #Temp SELECT 1, 1, '1'&lt;br /&gt;INSERT INTO #Temp SELECT 2, 1, '001'&lt;br /&gt;INSERT INTO #Temp SELECT 3, 1, 'fake1'&lt;br /&gt;INSERT INTO #Temp SELECT 4, 1, 'fullfake'&lt;br /&gt;INSERT INTO #Temp SELECT 5, 1, '01/31/2012'&lt;br /&gt;INSERT INTO #Temp SELECT 6, 1, '31/01/2012'&lt;br /&gt;&lt;br /&gt;-- Primera prueba: ver el contenido&lt;br /&gt;SELECT * FROM #Temp&lt;br /&gt;&lt;br /&gt;-- Segunda prueba: Castear la columna 3 a entero usando la vieja forma&lt;br /&gt;SELECT CONVERT(INT, campo3) FROM #Temp&lt;br /&gt;/* Resultado:&lt;br /&gt;Msg 245, Level 16, State 1, Line 1&lt;br /&gt;Conversion failed when converting the varchar value 'fake1' to data type int.&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;-- Tercera prueba: Hacer lo mismo pero con Try_Convert&lt;br /&gt;SELECT TRY_CONVERT(INT, campo3) FROM #Temp&lt;br /&gt;-- No hay error!!! Los dos primeros registros se convirtieron y los siguientes 3 son nulos&lt;br /&gt;&lt;br /&gt;-- Cuarta prueba: Hacer lo mismo pero con fechas&lt;br /&gt;SELECT CONVERT(DATE, campo3) FROM #Temp&lt;br /&gt;/* Resultado:&lt;br /&gt;Msg 241, Level 16, State 1, Line 1&lt;br /&gt;Conversion failed when converting date and/or time from character string.&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;-- Cuarta prueba: Hacer lo mismo pero con Parse&lt;br /&gt;SELECT PARSE(campo3 AS DATETIME) FROM #Temp&lt;br /&gt;-- Error!!! pero si usamos TRY_PARSE...&lt;br /&gt;SELECT id, TRY_PARSE(campo3 AS DATETIME USING 'en-US') FROM #Temp&lt;br /&gt;-- La salida parsea los valores que pudo y deja en nulo el resto!&lt;br /&gt;&lt;br /&gt;-- Y si cambiamos la referencia cultural...&lt;br /&gt;SELECT id, TRY_PARSE(campo3 AS DATETIME USING 'es-ES') FROM #Temp&lt;br /&gt;-- Obtenemos otro de los registros!!! sin tener que recordar los odiosos codigos 101 etc&lt;br /&gt;&lt;br /&gt;DROP TABLE #Temp&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Mas info: http://msdn.microsoft.com/en-us/library/hh213126%28v=sql.110%29.aspx&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-5636241654344492734?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/5636241654344492734/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/11/nuevas-funciones-tryparse-y-tryconvert.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/5636241654344492734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/5636241654344492734'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/11/nuevas-funciones-tryparse-y-tryconvert.html' title='Nuevas funciones TRY_PARSE y TRY_CONVERT en SQL 2012'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-5649540034634895624</id><published>2011-11-23T14:47:00.001-03:00</published><updated>2011-11-23T14:51:46.953-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL2008'/><category scheme='http://www.blogger.com/atom/ns#' term='TSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='DATEDIFF MAXRECURSION'/><category scheme='http://www.blogger.com/atom/ns#' term='CTE'/><title type='text'>Listar todas las fechas de un intervalo en TSQL</title><content type='html'>Hace poco en un foro alguien preguntó como hacer una consulta SQL para obtener todas las fechas en un intervalo dado, y como me gustó la solución la reescribi de forma mas generica y me gustaría compartirla con todos&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;&lt;br /&gt;-- Declaro las variables&lt;br /&gt;DECLARE @desde DATETIME&lt;br /&gt;DECLARE @hasta DATETIME&lt;br /&gt;-- Seteo un valor inicial&lt;br /&gt;SELECT @desde='20110101',@hasta='20111101';&lt;br /&gt;-- Primero calculo la cantidad de dias y luego listo tantos numeros como diferencia de dias&lt;br /&gt;WITH &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CantDias AS (SELECT DATEDIFF(DAY, @desde, @hasta) Cantidad),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Numeros AS(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT 1 numero&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; UNION ALL&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT n.numero + 1 numero&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM Numeros n, CantDias c &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; WHERE n.numero&amp;lt;=c.Cantidad&lt;br /&gt;)&lt;br /&gt;SELECT DATEADD(DAY, Numeros.numero-1, @desde) FROM Numeros OPTION (MAXRECURSION 0);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-5649540034634895624?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/5649540034634895624/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/11/listar-todas-las-fechas-de-un-intervalo.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/5649540034634895624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/5649540034634895624'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/11/listar-todas-las-fechas-de-un-intervalo.html' title='Listar todas las fechas de un intervalo en TSQL'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-4120801740918068576</id><published>2011-11-17T14:58:00.001-03:00</published><updated>2011-11-17T14:59:51.179-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL2012'/><category scheme='http://www.blogger.com/atom/ns#' term='Server 2012 Release Candidate 0'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Denali'/><title type='text'>Microsoft SQL Server 2012 Release Candidate 0 (RC0)</title><content type='html'>Ya se encuentra disponible el RC0 del SQL2012!!! para el que lo quiera bajar dejo el link: &lt;br /&gt;&lt;a href="http://www.microsoft.com/download/en/details.aspx?id=28145"&gt;http://www.microsoft.com/download/en/details.aspx?id=28145&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Entre esta semana y la que viene estaré subiendo algunos pequeños artículos apuntando a las novedades, pero para variar voy a enfocar en los cambios que afectan a los desarrolladores.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-4120801740918068576?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/4120801740918068576/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/11/microsoft-sql-server-2012-release.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4120801740918068576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4120801740918068576'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/11/microsoft-sql-server-2012-release.html' title='Microsoft SQL Server 2012 Release Candidate 0 (RC0)'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-2249843425040677735</id><published>2011-11-16T14:02:00.001-03:00</published><updated>2011-11-16T14:06:10.125-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DATEPART'/><category scheme='http://www.blogger.com/atom/ns#' term='TSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='DATEFIRST'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>Como saber si un dia es fin de semana en SQL</title><content type='html'>Hace poco en un foro vi dos veces seguida esta pregunta así que lo comparto con todos. La pregunta era como hacer para obtener si un día es fin de semana o no. Esto era para poder sumar cierta información solamente de los días hábiles.&lt;br /&gt;&lt;br /&gt;La solución propuesta es la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;DECLARE @fecha1 DATETIME = '20111111 14:30'&lt;br /&gt;SELECT CASE WHEN (DATEPART(WEEKDAY, @fecha1) + @@DATEFIRST)%7 IN (0, 1) THEN 'Fin de semana' ELSE 'Dia laboral' END&lt;/pre&gt;&lt;br /&gt;Es interesante como hay que tener en cuenta DATEFIRST para independizarse de como se ha configurado el servidor.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-2249843425040677735?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/2249843425040677735/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/11/como-saber-si-un-dia-es-fin-de-semana.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2249843425040677735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2249843425040677735'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/11/como-saber-si-un-dia-es-fin-de-semana.html' title='Como saber si un dia es fin de semana en SQL'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-2993764010432020319</id><published>2011-11-10T13:16:00.000-03:00</published><updated>2011-11-10T13:37:06.958-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2012'/><category scheme='http://www.blogger.com/atom/ns#' term='licenciamiento'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='licencia'/><title type='text'>Licencias de SQL 2012</title><content type='html'>Dejo un link explicando los cambios que se vienen en el licenciamiento de SQL 2012&lt;br /&gt;Link oficial: &lt;a href="http://www.microsoft.com/sqlserver/en/us/future-editions/sql2012-licensing.aspx"&gt;http://www.microsoft.com/sqlserver/en/us/future-editions/sql2012-licensing.aspx&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;Buen link al respecto: &lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.flexerasoftware.com/elo/2011/11/revolutionary-changes-to-microsoft-sql-server-2012-license-models.html"&gt;http://blogs.flexerasoftware.com/elo/2011/11/revolutionary-changes-to-microsoft-sql-server-2012-license-models.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Creo que lo que mas me apena es que nos deja la version Datacenter, pero era un final anunciado...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-2993764010432020319?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/2993764010432020319/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/11/licencias-de-sql-2012.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2993764010432020319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2993764010432020319'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/11/licencias-de-sql-2012.html' title='Licencias de SQL 2012'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-8539519622847252647</id><published>2011-11-09T11:05:00.000-03:00</published><updated>2011-11-09T11:05:02.275-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SP_REFRESHVIEW'/><category scheme='http://www.blogger.com/atom/ns#' term='TSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>Recompilando vistas en SQL Server</title><content type='html'>&lt;div style="color: #351c75; text-align: justify;"&gt;Esta vez haré un post mas corto de lo habitual. Ayer a un colega se le presentó una situación, que por un cambio en varias cosas de su motor debía recompilar una vista. Esto es facil utilizando&lt;/div&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;EXEC SP_REFRESHVIEW [miVista];&lt;br /&gt;&lt;/pre&gt;&lt;div style="color: #351c75; text-align: justify;"&gt;El problema es que ocurre cuando en lugar de una vista son cientas y potencialmente divididas en varias bases de datos. La solución que le brindé es un TSQL que le generase un script con todos los refresh para que despues pueda ejecutarlo y guardarlo como documentación. Para esto me valí de un procedimiento no documentado del sql que es el sp_MSforeachdb.&lt;/div&gt;&lt;div style="color: #351c75; text-align: justify;"&gt;Les comparto como quedó el script final&lt;/div&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 09/11/11&lt;br /&gt;-- Description: Como recompilar todas las vistas&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;sp_MSforeachdb '&lt;br /&gt;SELECT ''USE [?]&lt;br /&gt;GO &lt;br /&gt;EXEC SP_REFRESHVIEW [''+NAME+''];&lt;br /&gt;GO'' FROM SYSOBJECTS WHERE TYPE = ''V'' AND NOT ''?'' IN (''master'', ''tempdb'', ''msdb'', ''model'');&lt;br /&gt;'&lt;br /&gt;&amp;nbsp;&lt;/pre&gt;&lt;span style="color: #351c75;"&gt;More&lt;/span&gt;: &lt;a href="http://msdn.microsoft.com/en-us/library/ms187821.aspx"&gt;http://msdn.microsoft.com/en-us/library/ms187821.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-8539519622847252647?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/8539519622847252647/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/11/recompilando-vistas-en-sql-server.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/8539519622847252647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/8539519622847252647'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/11/recompilando-vistas-en-sql-server.html' title='Recompilando vistas en SQL Server'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-4007855346320258996</id><published>2011-10-25T15:16:00.001-03:00</published><updated>2011-10-25T15:16:02.427-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sp_who'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='sp_who2'/><title type='text'>Aplicar filtros al sp_who2 en SQL Server</title><content type='html'>Muchas veces usamos el sp_who2 para ver las conexiones activas y determinada información sobre esta, pero esto es comodo si los resultados son pocos, en el caso de ser muchos registros, cientos o miles esto ya no es aplicable.&lt;br /&gt;Para estos casos deseariamos poder aplicar un filtro al sp_who2 pero esto lamentablemente no es posible. Lo que veremos en este ejemplo es como hacer un script, que podemos tener siempre a mano, que se encargue de aplicar los filtros.&lt;br /&gt;El primer paso será crear una tabla temporal donde gaurdará los datos devueltos por el sp_who2. Como siempre primero controlo si la tabla ya existe para que no me arroje error al ejecutar.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;&lt;br /&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 25/10/11&lt;br /&gt;-- Description: Filtrar los resultados del sp_who2&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;-- Creo la tabla temporaria donde guardaré la salida del sp_who&lt;br /&gt;IF NOT OBJECT_ID('tempdb.dbo.#sp_who2') IS NULL&lt;br /&gt;DROP TABLE dbo.#sp_who2&lt;br /&gt;&lt;br /&gt;CREATE TABLE #sp_who2&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; (SPID INT, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Status VARCHAR(1000) NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Login SYSNAME NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; HostName SYSNAME NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BlkBy SYSNAME NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DBName SYSNAME NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Command VARCHAR(1000) NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CPUTime INT NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DiskIO INT NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; LastBatch VARCHAR(1000) NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ProgramName VARCHAR(1000) NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SPID2 INT,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; REQUESTID INT) &lt;br /&gt;&lt;br /&gt;GO&lt;/pre&gt;&lt;br /&gt;Una vez creada guardo en ella la salida del sp_who2&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;&lt;br /&gt;-- Inserto los valores&lt;br /&gt;INSERT INTO #sp_who2&lt;br /&gt;EXEC sp_who2&lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El paso siguiente es solamente hacer un select sobre dicha tabla, pero ahora aplicando filtro u orden, es decir lo mismo que haría en cualquier tabla. Por ejemplo filtrar solo las conexiones de mi usuario ordenadas por fecha.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;&lt;br /&gt;SELECT *&lt;br /&gt;&amp;nbsp; FROM #sp_who2&lt;br /&gt;-- Pongo el filtro que deseo&lt;br /&gt;&amp;nbsp;WHERE Login = 'AAIELLO'&lt;br /&gt;-- O el orden que deseo!!!&lt;br /&gt;ORDER BY LastBatch DESC&lt;br /&gt;GO&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Por último elimino las estructuras creadas para no dejar "sucia" la base.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;-- Elimino las estructuras temporarias&lt;br /&gt;DROP TABLE #sp_who2&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;Espero que les sirva!!! dejo a continuación el script copleto para que sea comodo de guardar.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt; &lt;br /&gt;&lt;br /&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 25/10/11&lt;br /&gt;-- Description: Filtrar los resultados del sp_who2&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;-- Creo la tabla temporaria donde guardaré la salida del sp_who&lt;br /&gt;IF NOT OBJECT_ID('tempdb.dbo.#sp_who2') IS NULL&lt;br /&gt;DROP TABLE dbo.#sp_who2&lt;br /&gt;&lt;br /&gt;CREATE TABLE #sp_who2&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; (SPID INT, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Status VARCHAR(1000) NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Login SYSNAME NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; HostName SYSNAME NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BlkBy SYSNAME NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DBName SYSNAME NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Command VARCHAR(1000) NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CPUTime INT NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DiskIO INT NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; LastBatch VARCHAR(1000) NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ProgramName VARCHAR(1000) NULL, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SPID2 INT,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; REQUESTID INT) &lt;br /&gt;&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- Inserto los valores&lt;br /&gt;INSERT INTO #sp_who2&lt;br /&gt;EXEC sp_who2&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;SELECT *&lt;br /&gt;&amp;nbsp; FROM #sp_who2&lt;br /&gt;-- Pongo el filtro que deseo&lt;br /&gt;&amp;nbsp;WHERE Login &amp;lt;&amp;gt; 'sa'&lt;br /&gt;-- O el orden que deseo!!!&lt;br /&gt;ORDER BY LastBatch DESC&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- Elimino las estructuras temporarias&lt;br /&gt;DROP TABLE #sp_who2&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-4007855346320258996?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/4007855346320258996/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/10/aplicar-filtros-al-spwho2-en-sql-server.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4007855346320258996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4007855346320258996'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/10/aplicar-filtros-al-spwho2-en-sql-server.html' title='Aplicar filtros al sp_who2 en SQL Server'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-4074138058716635629</id><published>2011-10-23T15:16:00.000-03:00</published><updated>2011-10-23T15:16:43.720-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>Screencast: Local Server Groups en SQL</title><content type='html'>Hola!!! para los que les pareció interesante el artículo de como ejecutar un mismo script sql sobre varios servidores, acá dejo un screencast explicando de forma mas didáctica como hacer esto.&lt;br /&gt;Saludos!&lt;br /&gt;&lt;br /&gt;&lt;!-- copy and paste. Modify height and width if desired. --&gt;       &lt;object id="scPlayer"  width="480" height="290" type="application/x-shockwave-flash" data="http://content.screencast.com/users/AndresAiello/folders/SQL/media/25599818-55b4-4b4b-ab5b-16bc16d3546e/scplayer.swf" &gt;&lt;param name="movie" value="http://content.screencast.com/users/AndresAiello/folders/SQL/media/25599818-55b4-4b4b-ab5b-16bc16d3546e/scplayer.swf" /&gt;&lt;param name="quality" value="high" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;param name="flashVars" value="thumb=http://content.screencast.com/users/AndresAiello/folders/SQL/media/25599818-55b4-4b4b-ab5b-16bc16d3546e/FirstFrame.png&amp;containerwidth=640&amp;containerheight=464&amp;autohide=true&amp;autostart=false&amp;loop=false&amp;showendscreen=true&amp;showsearch=false&amp;showstartscreen=true&amp;tocdoc=left&amp;xmp=sc.xmp&amp;content=http://content.screencast.com/users/AndresAiello/folders/SQL/media/25599818-55b4-4b4b-ab5b-16bc16d3546e/local%20server%20groups.mp4&amp;blurover=false" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="scale" value="showall" /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;param name="base" value="http://content.screencast.com/users/AndresAiello/folders/SQL/media/25599818-55b4-4b4b-ab5b-16bc16d3546e/" /&gt;&lt;iframe type="text/html" frameborder="0" scrolling="no" style="overflow:hidden;" src="http://www.screencast.com/users/AndresAiello/folders/SQL/media/25599818-55b4-4b4b-ab5b-16bc16d3546e/embed" height="464" width="640" &gt;&lt;/iframe&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-4074138058716635629?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/4074138058716635629/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/10/screencast-local-server-groups-en-sql.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4074138058716635629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4074138058716635629'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/10/screencast-local-server-groups-en-sql.html' title='Screencast: Local Server Groups en SQL'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-8886147427894290931</id><published>2011-10-21T10:00:00.001-03:00</published><updated>2011-11-16T14:06:42.146-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='local_tcp_port'/><category scheme='http://www.blogger.com/atom/ns#' term='IP'/><category scheme='http://www.blogger.com/atom/ns#' term='SPID'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='local_net_address'/><title type='text'>Obtener la IP del servidor desde SQL</title><content type='html'>En esta oportunidad me gustaría hacer un pequeño artículo sobre como obtener la ip del servidor en el cual se encuentra corriendo el SQL. La gracia es hacerlo sin salir al sistema operativo o el registro obviamente.&lt;br /&gt;La primer opción es:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;&lt;br /&gt;-- =============================================&lt;br /&gt;-- Create:&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Andrés Aiello&lt;br /&gt;-- Create date: 17/10/11&lt;br /&gt;-- Description: Como obtener la ip y puerto del servidor&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;-- Obtengo la info basandome en mi conexion&lt;br /&gt;SELECT local_net_address, local_tcp_port&lt;br /&gt;&amp;nbsp; FROM sys.dm_exec_connections c&lt;br /&gt;&amp;nbsp;WHERE c.session_id = @@SPID&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Esta opción lo que hace es buscar en la metadata de la conexion que yo tengo establecida cual es la ip de destino. Suena muy práctico y lo es en la mayoría de los casos. Esto puedo usarlo tanto de forma directa como dentro de un sp.&lt;br /&gt;Ahora bien, si deseo programar esto para, por ejemplo, guardar una auditoría, entonces llamaré a el sp correspondiente desde un job (suena lógico). Y sorpresivamente me dará como resultado NULL. ¿a que se debe? Si miramos con mas detalle, cuando ejecutamos desde el job hay una diferencia en una de las columnas que no nos estamos trayendo, y esta es net_transport. En esa columna el primer caso nos diría TCP porque es una conexion TCP/IP. Pero en el caso del job nos arrojaría "shared memory".&lt;br /&gt;Para solucionar esto podemos reemplazar nuestra consulta inicial por:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;&lt;br /&gt;-- Obtengo la info basandome en cualquier conexion&lt;br /&gt;SELECT TOP 1 local_net_address, local_tcp_port, net_transport&lt;br /&gt;&amp;nbsp; FROM sys.dm_exec_connections c&lt;br /&gt;&amp;nbsp;ORDER BY local_net_address DESC&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Para mas info: &lt;a href="http://msdn.microsoft.com/en-us/library/ms181509.aspx"&gt;http://msdn.microsoft.com/en-us/library/ms181509.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-8886147427894290931?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/8886147427894290931/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/10/obtener-la-ip-del-servidor-desde-sql.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/8886147427894290931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/8886147427894290931'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/10/obtener-la-ip-del-servidor-desde-sql.html' title='Obtener la IP del servidor desde SQL'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-3497659341388443426</id><published>2011-10-18T09:22:00.004-03:00</published><updated>2011-10-18T14:08:51.732-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeCamp'/><title type='text'>Post CodeCamp: Codigo seguro en SQL</title><content type='html'>&lt;div style="color: #073763;"&gt;Que buen sábado!!! la pasé genial con mucha gente copada, algunos que esperaba encontrarme y otros que no. En particular en mi presentación me gustó mucho el público que se copo con el tema, y por los comentarios se notó que es algo que muchos viven en el día a día. Gracias a todos!!! en particular a Microsoft, Daniel Levi y Miguel Saez por invitarme a participar.&lt;/div&gt;&lt;div style="color: #073763;"&gt;Y como no podía faltar unas fotos de la charla!!!&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-VaBAu6pWhHU/Tp1u9qPY5WI/AAAAAAAAAnE/Y9lIGXN9zdg/s1600/PA150208.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://2.bp.blogspot.com/-VaBAu6pWhHU/Tp1u9qPY5WI/AAAAAAAAAnE/Y9lIGXN9zdg/s320/PA150208.JPG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-O-9Lnbr_c1E/Tp1u-_nQm9I/AAAAAAAAAnk/ZTKEuzfYpVs/s1600/PA150209.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-O-9Lnbr_c1E/Tp1u-_nQm9I/AAAAAAAAAnk/ZTKEuzfYpVs/s320/PA150209.JPG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-hRv_2j4E6-w/Tp1u_B4QrdI/AAAAAAAAAnY/AoTisnUJZNw/s1600/PA150210.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-hRv_2j4E6-w/Tp1u_B4QrdI/AAAAAAAAAnY/AoTisnUJZNw/s320/PA150210.JPG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-kZhsKegot4E/Tp1vARUnHdI/AAAAAAAAAnw/dKVOGSkRN_k/s1600/PA150211.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-kZhsKegot4E/Tp1vARUnHdI/AAAAAAAAAnw/dKVOGSkRN_k/s320/PA150211.JPG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-r1cazXv7IRQ/Tp1vAciLu8I/AAAAAAAAAns/XLxPDyDCDgs/s1600/PA150212.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://4.bp.blogspot.com/-r1cazXv7IRQ/Tp1vAciLu8I/AAAAAAAAAns/XLxPDyDCDgs/s320/PA150212.JPG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/--oCEhuLdVy0/Tp1vBCxuGjI/AAAAAAAAAn0/5jycRRs0nkc/s1600/PA150213.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/--oCEhuLdVy0/Tp1vBCxuGjI/AAAAAAAAAn0/5jycRRs0nkc/s320/PA150213.JPG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-3497659341388443426?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/3497659341388443426/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/10/post-codecamp-codigo-seguro-en-sql.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/3497659341388443426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/3497659341388443426'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/10/post-codecamp-codigo-seguro-en-sql.html' title='Post CodeCamp: Codigo seguro en SQL'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-VaBAu6pWhHU/Tp1u9qPY5WI/AAAAAAAAAnE/Y9lIGXN9zdg/s72-c/PA150208.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-5214414888491276227</id><published>2011-10-17T10:30:00.002-03:00</published><updated>2011-10-17T10:30:50.891-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Managment Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='Server Groups'/><category scheme='http://www.blogger.com/atom/ns#' term='multisql'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Multiples servidores'/><title type='text'>Ejecutar el mismo script en multiples servidores SQL</title><content type='html'>&lt;div style="color: #073763; text-align: justify;"&gt;En esta oportunidad quiero comentar algo muy comodo y poco usado del Managment y es la opción de ejecutar el mismo script en varios servidores SQL al mismo tiempo.&lt;/div&gt;&lt;div style="color: #073763; text-align: justify;"&gt;Para esto abriremos el Managment Studio y seleccionaremos "Registered Servers" en la parte inferior izquierda como se ve en la siguiente imagen&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-Nkac1lkPp8M/TpwpztCEweI/AAAAAAAAAkg/kH5_fVUlDz8/s1600/ServerGroups.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="167" src="http://1.bp.blogspot.com/-Nkac1lkPp8M/TpwpztCEweI/AAAAAAAAAkg/kH5_fVUlDz8/s320/ServerGroups.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="color: #20124d; text-align: justify;"&gt;Eso me muestra dos subcarpetas:&lt;/div&gt;&lt;ul style="color: #20124d; text-align: justify;"&gt;&lt;li&gt;Local Servers Groups&lt;/li&gt;&lt;li&gt;Central Managment Servers&lt;/li&gt;&lt;/ul&gt;&lt;div style="color: #20124d; text-align: justify;"&gt;Lo ideal es utilizar el CMS, pero esto requiere tener un servidor dedicado a esta tarea y lo veremos en otro post. La forma que encararemos hoy es con Local Server Groups, donde uno puede ir agregando diferentes instancias simplemente haciendo click derecho y escribiendo "New Server Registration".&lt;/div&gt;&lt;div style="color: #20124d; text-align: justify;"&gt;Una vez que se hayan agregado todos los que uno quiera (estos quedan guardados de forma local en la pc) podemos hacer click derecho y elegir "New query". Nos abrirá una ventana en blanco pero a diferencia de la ventana standard, esta tendrá la barra inferior rosa en lugar de amarillo. Esto indica que lo que se ejecute en esa ventana se disparará contra todos los servidores registrados.&amp;nbsp;&lt;/div&gt;&lt;div style="color: #20124d; text-align: justify;"&gt;Es importante jugar también con la opción de registrar "grupos", para de esta forma hacer click derecho sobre el grupo y que la consulta no vaya contra todos los servidores registrados sino solamente contra los del grupo.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="color: #20124d;"&gt;Saludos!&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-5214414888491276227?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/5214414888491276227/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/10/ejecutar-el-mismo-script-en-multiples.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/5214414888491276227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/5214414888491276227'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/10/ejecutar-el-mismo-script-en-multiples.html' title='Ejecutar el mismo script en multiples servidores SQL'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-Nkac1lkPp8M/TpwpztCEweI/AAAAAAAAAkg/kH5_fVUlDz8/s72-c/ServerGroups.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-5249804632693661431</id><published>2011-10-15T23:30:00.003-03:00</published><updated>2011-10-15T23:30:42.040-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeCamp'/><title type='text'>CodeCampBA: Charla SQL</title><content type='html'>&lt;div style="color: #0b5394;"&gt;Muchas gracias a todos los que estuvieron en la charla!!! les dejo el ppt y los ejemplos y prometo en la semana subir algunas fotos ;)&lt;/div&gt;&lt;div style="color: #0b5394;"&gt;Saludos y gracias!!!&lt;/div&gt;&lt;br /&gt;&lt;a href="https://sites.google.com/site/aaiello/CodeCamp_Que_No_Te_Ataquen.rar"&gt;https://sites.google.com/site/aaiello/CodeCamp_Que_No_Te_Ataquen.rar&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-5249804632693661431?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/5249804632693661431/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/10/codecampba-charla-sql.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/5249804632693661431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/5249804632693661431'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/10/codecampba-charla-sql.html' title='CodeCampBA: Charla SQL'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-7826407629110618102</id><published>2011-10-13T12:20:00.002-03:00</published><updated>2011-10-13T12:20:21.148-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UNIX'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>Conectarse a SQL Server desde UNIX</title><content type='html'>&lt;div style="color: #073763;"&gt;Les comparto un artículo que encontré y me pareció interesante que explica diferentes formas de conectarse al SQL Server desde UNIX&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.sommarskog.se/mssqlperl/unix.html"&gt;http://www.sommarskog.se/mssqlperl/unix.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-7826407629110618102?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/7826407629110618102/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/10/conectarse-sql-server-desde-unix.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/7826407629110618102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/7826407629110618102'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/10/conectarse-sql-server-desde-unix.html' title='Conectarse a SQL Server desde UNIX'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-6652235979564785656</id><published>2011-10-07T09:44:00.001-03:00</published><updated>2011-10-07T09:44:54.975-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Service Pack'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008 SP3'/><category scheme='http://www.blogger.com/atom/ns#' term='SP3'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>SQL Server 2008 SP3!</title><content type='html'>&lt;span style="color: #0b5394;"&gt;Está disponible el SP3 del SQL Server 2008: &lt;/span&gt;&lt;br /&gt;&lt;a href="http://blogs.technet.com/b/dataplatforminsider/archive/2011/10/06/sql-server-2008-sp3-is-now-available.aspx"&gt;http://blogs.technet.com/b/dataplatforminsider/archive/2011/10/06/sql-server-2008-sp3-is-now-available.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-6652235979564785656?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/6652235979564785656/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/10/sql-server-2008-sp3.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/6652235979564785656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/6652235979564785656'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/10/sql-server-2008-sp3.html' title='SQL Server 2008 SP3!'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-7432000017805738535</id><published>2011-10-04T15:45:00.000-03:00</published><updated>2011-10-04T15:46:58.615-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='is_expiration_checked'/><category scheme='http://www.blogger.com/atom/ns#' term='check policy'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='is_policy_checked'/><category scheme='http://www.blogger.com/atom/ns#' term='expiration password'/><category scheme='http://www.blogger.com/atom/ns#' term='Auditoria'/><category scheme='http://www.blogger.com/atom/ns#' term='expiration'/><title type='text'>Setea el check_policy para los logins que no lo tengan</title><content type='html'>&lt;div style="color: #333399; text-align: justify;"&gt;Esta vez voy a hacer un post bien simple pero útil. Hay dos opciones muy interesantes al crear logins que son el check_policy y el check_expiration. La primera nos permite controlar que las contraseñas ingresadas por los usuarios cumplan con los requisitos de seguridad de complejidad de contraseña mientras que la segunda habilita que las contraseñas expiran una vez vencido cierto tiempo. Es importante notar (error muy común) que el check_policy se evalúa AL MOMENTO de setear la contraseña. Esto quiere decir que si creo un usuario, le pongo como contraseña '1' y luego habilito el check_poclicy, dicho usuario va a poder conectarse sin problema. Pero sin en cambio creo el usuario, habilito el check_policy y luego pongo como contraseña '1' no me dejará definirla por no cumplir los requisitos de seguridad. En el primer caso la contraseña '1' le permitirá loguearse pero al momento de querer cambiarla no podrá poner como contraseña '2' sino que ahi si deberá cumplir las reglas definidas.&lt;br /&gt;&lt;br /&gt;Una vez terminada la introducción y dejando los conceptos en claro vamos a los bifes. La idea es hacer una consulta que me liste todos los usuarios que no cumplen esta buena práctica y poder cambiar su estado. El script que armé es el siguiente:&lt;/div&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;-- =============================================&lt;br /&gt;-- Author: Andrés Aiello&lt;br /&gt;-- Create date: 02/05/2011&lt;br /&gt;-- Setea el check_policy para los logins que no lo tengan&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;DECLARE @SQLQuery varchar(1000)&lt;br /&gt;DECLARE @LoginName varchar(255)&lt;br /&gt;&lt;br /&gt;DECLARE cLogins CURSOR FORWARD_ONLY FOR&lt;br /&gt;SELECT name&lt;br /&gt;--,is_policy_checked,'ALTER LOGIN [' + name + '] WITH CHECK_POLICY=ON' Query&lt;br /&gt;FROM sys.sql_logins&lt;br /&gt;WHERE is_policy_checked = 0&lt;br /&gt;/* Ignoro los logins que considere que por algun motivo no deben ser tenidos en cuenta */&lt;br /&gt;AND NOT name IN ('xxxxxxxxxxx')&lt;br /&gt;ORDER BY NAME&lt;br /&gt;&lt;br /&gt;OPEN cLogins&lt;br /&gt;FETCH NEXT FROM cLogins INTO @LoginName&lt;br /&gt;WHILE @@FETCH_STATUS = 0&lt;br /&gt;BEGIN&lt;br /&gt;SET @SQLQuery = 'ALTER LOGIN [' + @LoginName + '] WITH CHECK_POLICY=ON'&lt;br /&gt;PRINT @SQLQuery&lt;br /&gt;FETCH NEXT FROM cLogins INTO @LoginName&lt;br /&gt;END&lt;br /&gt;CLOSE cLogins&lt;br /&gt;DEALLOCATE cLogins&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #333399; font-weight: bold; text-align: justify;"&gt;&lt;span style="font-weight: normal;"&gt;Este script como pueden ver no ejecuta el código sino que lo saca por la salida. Esto se debe a que una buena idea sería previo a hacer los cambios documentarlos salvando el script y luego ejecutarlo.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: normal;"&gt;En este ejemplo fue para el check_policy, pero si quisieran hacer lo mismo para el expiration es igual solamente que el campo a filtrar es is_expiration_checked.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: normal;"&gt;Andrés&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-7432000017805738535?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/7432000017805738535/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/05/setea-el-checkpolicy-para-los-logins.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/7432000017805738535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/7432000017805738535'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/05/setea-el-checkpolicy-para-los-logins.html' title='Setea el check_policy para los logins que no lo tengan'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-8231484891237698437</id><published>2011-10-04T09:33:00.004-03:00</published><updated>2011-10-17T15:51:10.531-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sp_MSForeachdb'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='cmdshell'/><title type='text'>Controlar CMDShell en SQL</title><content type='html'>&lt;div style="text-align: justify;"&gt;Todos saben que no es deseable tener el CMDShell activado en los servidores, pero hay veces que uno llega a un server y ya se encuentra activado y ahí surge la pregunta de que hacer. La primer medida es cambiar las credenciales para que se ejecute con permisos mínimos, pero no hablaremos de eso ahora. Junto con esto es importante identificar donde se utiliza visto que los permisos dependerán de las llamadas que haga. Como no podemos recorrer base por base viendo si se utiliza, les dejo una consulta que hice para este fin&lt;/div&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;EXEC sp_MSForeachdb 'SELECT ''?'' DBName, text FROM [?].SYS.SYSCOMMENTS WHERE text LIKE ''%XP_CMDSHELL%'''&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;Esta consulta retorna todos los lugares donde se utiliza el cmdshell. Hay algunas referencias del sistema que las deberán ignorar.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Saludos!&lt;br /&gt;&lt;br /&gt;nota: recordar que la función &lt;span style="color: #b45f06;"&gt;sp_MSForeachdb &lt;/span&gt;es una función no documentada&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-8231484891237698437?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/8231484891237698437/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/10/controlar-cmdshell-en-sql.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/8231484891237698437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/8231484891237698437'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/10/controlar-cmdshell-en-sql.html' title='Controlar CMDShell en SQL'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-3112926241681249788</id><published>2011-09-21T14:12:00.000-03:00</published><updated>2011-10-04T15:15:39.715-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='FILENAME'/><category scheme='http://www.blogger.com/atom/ns#' term='renombrar'/><category scheme='http://www.blogger.com/atom/ns#' term='ALTER DATABASE'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>Renombrar filename de una base SQL</title><content type='html'>&lt;div style="color: #351c75; text-align: justify;"&gt;Hoy quiero contar un problema que me presentó un amigo hace unos días y me parece que a muchos les puede pasar. La persona en cuestión muchas veces había renombrado una base de datos, o había cambiado su nombre lógico, pero las veces que tenía que cambiar el nombre físico el procedimiento era:&lt;br /&gt;1) Deatach de la base&lt;br /&gt;2) Renombrado del file&lt;br /&gt;3) Atach de la base&lt;br /&gt;&lt;br /&gt;Es procedimiento es un poco extremo y aprovecharé para explicarles como hacerlo de forma mas simple.&lt;br /&gt;El primer paso es asegurarme cuales son los files que tengo definidos en la base, en el ejemplo consideraremos la base "Librería". Para obtener esta información ejecutamos:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;SELECT name, physical_name AS CurrentLocation, state_desc&lt;br /&gt;FROM sys.master_files&lt;br /&gt;WHERE database_id = DB_ID('Libreria');&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahí obtendremos como resultado tres columnas, Name (nombre lógico), CurrentLocation (donde se encuentra actualmente el file) y state_desc (estado del file). Es importante que se recuerde que el nombre lógico es como se refenciará internamente al archivo, mientras que el físico es su nombre real. Puedo cambiar uno sin cambiar el otro.&lt;br /&gt;La consulta dará como mínimo dos registros de salida, una para el archivo mdf (data) y otra para el ldf&amp;nbsp; (log).&lt;br /&gt;&lt;br /&gt;Supongamos que quiero cambiar ambos archivos y renombrarlos LibreriaDATA y LibreriaLOG respectivamente, entonces debo poner offline la base y luego ejecutar la siguiente sentencia:&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;-- Pongo a la base offline&lt;br /&gt;ALTER DATABASE Libreria SET OFFLINE WITH ROLLBACK IMMEDIATE&lt;br /&gt;&lt;br /&gt;-- Cambio los nombres a donde apuntan. El NAME es el nombre logico que quiero modificar y el FILENAME es el NUEVO nombre fisico&lt;br /&gt;ALTER DATABASE Libreria&lt;br /&gt;MODIFY FILE (NAME = Libreria, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQL2008R2\MSSQL\DATA\LibreriaDATA.mdf' )&lt;br /&gt;ALTER DATABASE Libreria&lt;br /&gt;MODIFY FILE (NAME = Libreria_log, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQL2008R2\MSSQL\DATA\LibreriaLOG.LDF' )&lt;br /&gt;-- Muevo los archivos a nivel sistema operativo&lt;br /&gt;&lt;/pre&gt;Si todo está ok pongo la base nuevamente en línea. Es importante que noten que puedo hacer el alter apuntando a un archivo inexistente, el control se hará al momento de poner la base online.&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;-- Una vez renombrados la pongo nuevamente en linea&lt;br /&gt;ALTER DATABASE Libreria SET ONLINE&lt;br /&gt;&lt;br /&gt;-- Controlo que todo quede como yo quería&lt;br /&gt;SELECT name, physical_name AS CurrentLocation, state_desc&lt;br /&gt;FROM sys.master_files&lt;br /&gt;&lt;/pre&gt;Si todo está ok ya terminé mi trabajo. En caso de que haya por error apuntado a un archivo inexistente (ej. me faltó renombrar un archivo) la base no se pondrá online arrojando el siguiente error:&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #cc0000;"&gt;Msg 5120, Level 16, State 101, Line 1&lt;br /&gt;Unable to open the physical file&lt;/div&gt;&lt;br /&gt;Es una buena práctica al finalizar ejecutar nuevamente la consulta inicial y corroborar que realmente todo quedó como queríamos que quedara.&lt;br /&gt;Espero que les sirva!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-3112926241681249788?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/3112926241681249788/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/09/renombrar-filename-de-una-base-sql.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/3112926241681249788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/3112926241681249788'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/09/renombrar-filename-de-una-base-sql.html' title='Renombrar filename de una base SQL'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-4921050220990656962</id><published>2011-09-21T08:42:00.003-03:00</published><updated>2011-10-17T09:54:22.878-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeCamp'/><title type='text'>Que no te ataquen!!! Desarrollando código seguro en SQL</title><content type='html'>&lt;div style="color: #0b5394;"&gt;Les dejo la invitación al Codecamp de este año.Estaré dando una charla sobre código seguro en SQL junto a mi amigo Mariano Alvarez (&lt;a href="http://blog.josemarianoalvarez.com/"&gt;http://blog.josemarianoalvarez.com&lt;/a&gt;).Espero que pueda ir mucha gente!!!!&lt;/div&gt;&lt;pre class="brush:xml;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="brush:xml;"&gt;&lt;a href="https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032493728&amp;amp;Culture=es-AR" target="_blank"&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;img &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;="" alt="Banner CodeCamp 300x250" src="http://www.codecamp.com.ar/themes/codecamp/content/media/misc/ban_ar-uru_codecamp_300x250.jpg" style="height: 250px; width: 300px;" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-4921050220990656962?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/4921050220990656962/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/09/que-no-te-ataquen-desarrollando-codigo.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4921050220990656962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4921050220990656962'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/09/que-no-te-ataquen-desarrollando-codigo.html' title='Que no te ataquen!!! Desarrollando código seguro en SQL'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-1561440043700426127</id><published>2011-09-12T21:37:00.001-03:00</published><updated>2011-09-21T15:22:59.954-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='recursividad'/><category scheme='http://www.blogger.com/atom/ns#' term='recursión'/><category scheme='http://www.blogger.com/atom/ns#' term='common table expression'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='CTE'/><title type='text'>Screencast: CTE recursivas en SQL Server</title><content type='html'>&lt;div style="color: #0b5394;"&gt;Mi primer Screencast!!! Espero que les guste mi primer screencast, trata sobre CTE recursivas (ver post anterior)&lt;/div&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;object &amp;nbsp;="" data="http://content.screencast.com/users/AndresAiello/folders/SQL/media/1b0eb750-3780-43aa-96ab-11fd571e6be0/scplayer.swf" height="290" id="scPlayer" type="application/x-shockwave-flash" width="448"&gt;&lt;param name="movie" value="http://content.screencast.com/users/AndresAiello/folders/SQL/media/1b0eb750-3780-43aa-96ab-11fd571e6be0/scplayer.swf" /&gt;&lt;param name="quality" value="high" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;param name="flashVars" value="thumb=http://content.screencast.com/users/AndresAiello/folders/SQL/media/1b0eb750-3780-43aa-96ab-11fd571e6be0/FirstFrame.jpg&amp;amp;containerwidth=640&amp;amp;containerheight=415&amp;amp;autohide=true&amp;amp;autostart=false&amp;amp;loop=false&amp;amp;showendscreen=true&amp;amp;showsearch=false&amp;amp;showstartscreen=true&amp;amp;tocdoc=left&amp;amp;xmp=sc.xmp&amp;amp;content=http://content.screencast.com/users/AndresAiello/folders/SQL/media/1b0eb750-3780-43aa-96ab-11fd571e6be0/cte%20recursivas.mp4&amp;amp;blurover=false" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="scale" value="showall" /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;param name="base" value="http://content.screencast.com/users/AndresAiello/folders/SQL/media/1b0eb750-3780-43aa-96ab-11fd571e6be0/" /&gt;&lt;iframe type="text/html" frameborder="0" scrolling="no" style="overflow:hidden;" src="http://www.screencast.com/users/AndresAiello/folders/SQL/media/1b0eb750-3780-43aa-96ab-11fd571e6be0/embed" height="290" width="448" &gt;&lt;/iframe&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-1561440043700426127?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/1561440043700426127/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/09/screencast-cte-recursivas.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/1561440043700426127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/1561440043700426127'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/09/screencast-cte-recursivas.html' title='Screencast: CTE recursivas en SQL Server'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-2754585438238109697</id><published>2011-09-12T13:14:00.000-03:00</published><updated>2011-10-04T15:19:58.620-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='recursividad'/><category scheme='http://www.blogger.com/atom/ns#' term='recursión'/><category scheme='http://www.blogger.com/atom/ns#' term='common table expression'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='CTE'/><title type='text'>La recursion es divina - Consultas recursivas en SQL</title><content type='html'>&lt;div style="color: #351c75; text-align: justify;"&gt;El lenguaje SQL no solía ser lo mas comodo para realizar consultas en donde participe el concepto de "recursión", pero claramente algunos problemas son muy incomodos si los abordamos de otra forma. Por suerte para nosotros, desde la aparición de las CTE, esto ha cambiado y ahora es "simple" realizar consultas recursivas, veremos un ejemplo de como podemos realizarlo.&lt;/div&gt;&lt;div style="color: #351c75; text-align: justify;"&gt;&lt;/div&gt;&lt;div style="color: #351c75; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="color: #351c75;"&gt;Consideremos la siguiente tabla con datos de ejemplo:&lt;/span&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;CREATE TABLE #Empleados(idEmpleado INT, Nombre VARCHAR(10), idJefe INT)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Empleados&lt;br /&gt;SELECT 0, 'Bob', null UNION&lt;br /&gt;SELECT 1, 'Tom', 0 UNION&lt;br /&gt;SELECT 2, 'Joe', null UNION&lt;br /&gt;SELECT 3, 'John', 2 UNION&lt;br /&gt;SELECT 4, 'Ringo', 1 UNION&lt;br /&gt;SELECT 5, 'Paul', 4 &lt;br /&gt;&lt;br /&gt;SELECT * FROM #Empleados&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div style="color: #351c75; text-align: justify;"&gt;Esta tabla contiene los empleados de una empresa e indica sus respectivos jefes. Lo divertido es que los jefes son también empleados, por lo tanto son registros de la misma tabla.&lt;/div&gt;&lt;span style="color: #351c75;"&gt;Supongamos que quiero averiguar el nombre del jefe de cada empleado. Esto lo puedo realizar con un "self join" sin necesidad de recursividad.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;SELECT e.Nombre Empleado, j.Nombre Jefe&lt;br /&gt;FROM #Empleados e&lt;br /&gt;INNER JOIN #Empleados j ON e.idJefe=j.idEmpleado;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="color: #351c75; text-align: justify;"&gt;Pero ahora supongamos que quiero una consulta mas compleja, una que me retorne no el jefe directo, sino el jefe superior de cada empleado. Cualquiera que tenga conocimientos de algoritmos sabe que la mejor forma de responder a esta pregunta es con una estructura recursiva. No pretendo en éste artículo escribir que es la recursión, sino como utilizarla en SQL, así que daré por sentado que saben de que hablo.&lt;/div&gt;&lt;div style="color: #351c75; text-align: justify;"&gt;Una estructura recursiva requiere básicamente de dos partes:&lt;/div&gt;&lt;div style="color: #351c75; text-align: justify;"&gt;1) El caso base&lt;/div&gt;&lt;div style="color: #351c75; text-align: justify;"&gt;2) El caso recursivo&lt;/div&gt;&lt;div style="color: #351c75; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="color: #351c75;"&gt;Para escribir esto utilizaremos una CTE que tendrá estas dos partes, y deben unirse con un UNION ALL. La primer parte será el caso base (en el WHERE debo filtrar para que lo sea) y en la segunda el caso recursivo, el cual hace un JOIN con la CTE. Este join es lo que indica que es un caso recursivo. Nótese que defino la cte utilizandola a ella misma, por eso mismo es recursiva.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;WITH cte&lt;br /&gt;AS(&lt;br /&gt;-- Caso base&lt;br /&gt;SELECT e.idEmpleado, e.Nombre Nombre, e.idEmpleado Jefe&lt;br /&gt;FROM #Empleados e&lt;br /&gt;WHERE e.idJefe IS NULL&lt;br /&gt;-- Fin Caso base&lt;br /&gt;UNION ALL&lt;br /&gt;-- Caso recursivo&lt;br /&gt;SELECT e.idEmpleado, e.Nombre Nombre, j.Jefe&lt;br /&gt;FROM #Empleados e&lt;br /&gt;INNER JOIN cte j ON e.idJefe=j.idEmpleado&lt;br /&gt;-- Fin Caso recursivo&lt;br /&gt;)&lt;br /&gt;SELECT c.Nombre Empleado, j.Nombre Jefe&lt;br /&gt;FROM cte c&lt;br /&gt;INNER JOIN #Empleados j ON c.Jefe=j.idEmpleado&lt;br /&gt;&lt;br /&gt;DROP TABLE #Empleados&lt;br /&gt;&lt;/pre&gt;&lt;div style="color: #351c75; text-align: justify;"&gt;Con esto obtengo el código del jefe superior de cada uno, entonces en el SELECT lo cruzo con la tabla de empleados para obtener su nombre. Parece medio confuso pero es cuestión de acostumbrarse.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="color: #351c75;"&gt;Hay algunos inconvenientes que pueden presentarse, pero eso lo comentaré en el próximo artículo.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-2754585438238109697?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/2754585438238109697/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/09/la-recursion-es-divina.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2754585438238109697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2754585438238109697'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/09/la-recursion-es-divina.html' title='La recursion es divina - Consultas recursivas en SQL'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-7674867670047952845</id><published>2011-09-08T11:47:00.000-03:00</published><updated>2011-09-08T11:47:47.055-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Analisys Services'/><category scheme='http://www.blogger.com/atom/ns#' term='MeasureGroups'/><category scheme='http://www.blogger.com/atom/ns#' term='PowerShell'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>Como leer desde SQL los MeasureGroups de AS</title><content type='html'>&lt;div style="color: #351c75; text-align: justify;"&gt;Hace poco me pasó que necesitaba trabajar con los id de los MeasureGroups desde SQL, y me encontré con que las consultas que podía hacer retornaban siempre el nombre pero no el id. Por este motivo hice un script de powershell que me brinde la información y la cargue en una tabla. La parte de SQL la hice rápido y podría mejorarse con objetos de powershell pero lo importante es lo otro.&lt;/div&gt;&lt;br /&gt;&lt;div style="color: #38761d;"&gt;#Datos del ejemplo:&lt;/div&gt;&lt;div style="color: #38761d;"&gt;#Servidor de AS: AS1&lt;/div&gt;&lt;div style="color: #38761d;"&gt;#Base en AS: DB1&lt;/div&gt;&lt;div style="color: #38761d;"&gt;#Cubo: Cub1&lt;/div&gt;&lt;div style="color: #38761d;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="color: #6aa84f;"&gt;&lt;span style="color: #38761d;"&gt;## El primer parametro es la instancia donde guarda la informacion, segundo base&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$sqlServer = $args[0];&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$dbName = $args[1];&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$tbl = "mgRecolectadas"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #38761d;"&gt;# Recolecto la informacion del AS&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.AnalysisServices") &amp;gt; $null&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Microsoft.AnalysisServices.Server]$svr = new-Object([Microsoft.AnalysisServices.Server])&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #38761d;"&gt;# Tomo uno como ejemplo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$svr.Connect("AS1") &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$DatabaseID = "DB1"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$db = $svr.Databases.Item($DatabaseID)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$cubo = $db.Cubes.Item("Cub1") &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #38761d;"&gt;#Variables donde armaré la cadena de SQL&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$mgid = ""&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$mgname = ""&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$sql = ""&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #38761d;"&gt;#Recorro la coleccion de MeasureGroups&lt;/span&gt; &lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;foreach ($mg in $cubo.MeasureGroups){&lt;/div&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #38761d;"&gt;#Obtengo el ID&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $mgid = $mg.id&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $mgname = $mg.name&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #38761d;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #Armo la cadena&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ($sql){&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $sql = "$sql UNION "&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $sql = "$sql &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT '$mgid' mg, '$mgname' mgname"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$svr.Disconnect()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #38761d;"&gt;## Establezco la conexion para guardar la info&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$conn = New-Object System.Data.SqlClient.SqlConnection("Data Source=$sqlServer;Initial Catalog=$dbName; Integrated Security=SSPI")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$conn.Open()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$cmd = $conn.CreateCommand()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #38761d;"&gt;# Borro lo anterior&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$cmd.CommandText = "TRUNCATE TABLE $tbl"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$null = $cmd.ExecuteNonQuery()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;echo "Table truncada"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #38761d;"&gt;# Agrego todos los registros nuevos&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$cmd.CommandText = "INSERT INTO $tbl SELECT * FROM ($sql) t"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$null = $cmd.ExecuteNonQuery()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;echo "Insercion finalizada"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$conn.Close()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-7674867670047952845?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/7674867670047952845/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/09/como-leer-desde-sql-los-measuregroups.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/7674867670047952845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/7674867670047952845'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/09/como-leer-desde-sql-los-measuregroups.html' title='Como leer desde SQL los MeasureGroups de AS'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-8714848887881200708</id><published>2011-08-24T12:07:00.001-03:00</published><updated>2011-10-04T15:22:07.900-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='restore'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='ChangeDataCapture'/><category scheme='http://www.blogger.com/atom/ns#' term='CDC'/><title type='text'>Restore de CDC en SQL 2008</title><content type='html'>&lt;div class="MsoNormal" style="color: #333399; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;El cdc es una feature muy buena del SQL2008 visto que de forma sencilla nos permite llevar un registro de los cambios en una tabla, tanto sea para cuestiones de auditoría, procesamientos parciales de información, etc.&lt;/span&gt;&lt;/div&gt;&lt;div style="color: #333399; text-align: justify;"&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;Así mismo, cuando se trabaja con cdc es normal que se deseen probar, testear, desarrollar procedimientos que utilicen esta información y naturalmente no queremos que accedan al ambiente productivo hasta estar testeadas. Aquí es cuando nos topamos que si hacemos un restore de una base con cdc en otra instancia no aparecen las tablas correspondientes. Para evitar esto debemos incluir la opción WITH KEEP_CDC al momento de hacer restore. No se si será poco usada, pero no se asusten si no es coloreada en el Managment Studio, funciona a la perfección. &lt;/span&gt;&lt;/div&gt;&lt;div style="color: #333399; text-align: justify;"&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;El código debería quedar algo así:&lt;/span&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;RESTORE DATABASE [AIELLO_DB]&lt;br /&gt;FROM DISK = N'D:\Backup\[AIELLO_DB][SQL2008].bak'&lt;br /&gt;WITH&lt;br /&gt;KEEP_CDC,&lt;br /&gt;FILE = 1,&lt;br /&gt;MOVE N'AIELLO_DB'&lt;br /&gt;TO N'D:\MSSQL10.MSSQLSERVER\MSSQL\DATA\AIELLO_DB.mdf',&lt;br /&gt;MOVE N'AIELLO_DB_log'&lt;br /&gt;TO N'D:\MSSQL10.MSSQLSERVER\MSSQL\DATA\AIELLO_DB_log.ldf',&lt;br /&gt;MOVE N'AIELLO_DB_cdc'&lt;br /&gt;TO N'D:\MSSQL10.MSSQLSERVER\MSSQL\DATA\AIELLO_DB_cdc.ndf',&lt;br /&gt;NOUNLOAD,&lt;br /&gt;REPLACE,&lt;br /&gt;STATS = 10&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;div class="MsoNormal" style="color: #333399; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;Con esto tendrán la información para poder explotarla, pero no se activará la captura de datos. Si desean que esto ocurra hay que incluir los jobs correspondientes con sys.sp_cdc_add_job aplicando tanto 'capture' como  'cleanup'.&lt;/span&gt;&lt;/div&gt;&lt;div style="color: #333399; text-align: justify;"&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;Saludos,&lt;/span&gt;&lt;/div&gt;&lt;div style="color: #333399; text-align: justify;"&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;Andrés &lt;/span&gt;&lt;/div&gt;&lt;div style="color: #333399; text-align: justify;"&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;Para mas información:&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span lang="ES-AR"&gt;&lt;span style="color: #333399;"&gt;RESTORE Arguments (Transact-SQL): &lt;/span&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms178615.aspx"&gt;http://msdn.microsoft.com/en-us/library/ms178615.aspx&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span style="color: #333399;"&gt;sys.sp_cdc_add_job (Transact-SQL):&lt;/span&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb510626.aspx"&gt; http://msdn.microsoft.com/en-us/library/bb510626.aspx&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-8714848887881200708?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/8714848887881200708/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/08/restore-de-cdc.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/8714848887881200708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/8714848887881200708'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/08/restore-de-cdc.html' title='Restore de CDC en SQL 2008'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-7873441387734540331</id><published>2011-08-11T12:28:00.005-03:00</published><updated>2011-10-04T16:24:12.666-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sys.partitions'/><category scheme='http://www.blogger.com/atom/ns#' term='DBCC PAGE'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Waitresource'/><title type='text'>SQL2008: Entendiendo el Waitresource</title><content type='html'>&lt;span style="font-size: 130%; font-weight: bold;"&gt;Introduccion&lt;/span&gt;&lt;br /&gt;&lt;span lang="ES-AR" style="color: #333399; font-family: arial;"&gt;Al ver los xml de bloqueos o deadlocks muchas veces aparecen números casi inentendibles, y uno de los importantes es el WAITRESOURCE. Este número codifica que objeto de la base de datos está participando en la pelea por el bloqueo. El recurso puede principalmente ser:&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: #333399; font-family: arial;"&gt;&lt;li&gt;&lt;span lang="ES-AR" style="font-family: Symbol;"&gt;&lt;span style="font: 7pt &amp;quot;Times New Roman&amp;quot;;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span lang="ES-AR" style="color: #333399; font-family: arial;"&gt;Una tabla&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span lang="ES-AR" style="font-family: Symbol;"&gt;&lt;span style="font: 7pt &amp;quot;Times New Roman&amp;quot;;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span lang="ES-AR"&gt;Una página&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span lang="ES-AR" style="font-family: Symbol;"&gt;&lt;span style="font: 7pt &amp;quot;Times New Roman&amp;quot;;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span lang="ES-AR"&gt;Una clave&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial;"&gt;&lt;span lang="ES-AR"&gt;Puede ser algunas cosas mas pero para simplificar el análisis nos enfocaremos en estos.&lt;/span&gt;&lt;/div&gt;&lt;span lang="ES-AR" style="font-family: arial; font-size: 130%; font-weight: bold;"&gt;Manos a la obra&lt;/span&gt;&lt;br /&gt;&lt;div class="MsoNormal" style="color: #333399;"&gt;&lt;span lang="ES-AR"&gt;Lo primero que debemos hacer es identificar cual de las tres cosas es, lo cual es fácil leyendo el texto de wait resourse que puede ser:&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;i&gt;“OBJECT: 19:1275867612:10”&lt;/i&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;i&gt;“PAGE: 12:1:79868773”&lt;/i&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0.0001pt;"&gt;&lt;i&gt;“KEY: 12:397371816017920 (760119e06bff)”&lt;/i&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;i&gt;&lt;/i&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;En el primer caso es cuando se trata de una tabla. Para este caso (y para los siguientes) lo primero que debemos hacer es analizar el primer número antes del separador (:) . Este número en todos los casos indica el id de la base de datos, por lo tanto debo hacer la siguiente consulta para obtenerla:&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;&lt;/span&gt;&lt;/div&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;SELECT * FROM sys.sysdatabases WHERE Dbid=19&lt;br /&gt;&lt;/pre&gt;&lt;div class="MsoNormal" style="color: #333399; line-height: normal; margin: 0cm 0cm 0.0001pt;"&gt;&lt;span lang="ES-AR"&gt;Lo cual me da por resultado Mibase. Recordemos esto porque es común a los tres casos.&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; line-height: normal; margin: 0cm 0cm 0.0001pt;"&gt;&lt;span lang="ES-AR"&gt;Ahora siguiendo con el análisis del primer caso la información brindada se debe analizar de la siguiente manera:&lt;/span&gt;&lt;/div&gt;&lt;span style="color: #333399;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR"&gt;OBJECT: dbId:ObjectId:IndexId&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;Con la salvedad de que indexId vale 0 cuando se trata del heap y 1 cuando se trata de un índice cluster. En otro caso figurará el número del índice.&lt;/span&gt;&lt;/div&gt;&lt;div style="color: #333399; font-family: arial; text-align: justify;"&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;Para obtener esta información en un formato útil debería hacer las siguientes consultas:&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0.0001pt;"&gt;&lt;span lang="ES-AR" style="color: blue; font-family: &amp;quot;;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;pre class="sql" name="code"&gt;-- Nota: debo estar situado en MiBase&lt;br /&gt;SELECT OBJECT_NAME(1275867612) &lt;br /&gt;-- O bien&lt;br /&gt;SELECT * FROM MiBase.sys.all_objects WHERE object_id = 1275867612&lt;br /&gt;-- Y para buscar el índice en caso de ser mayor que 1:&lt;br /&gt;SELECT * FROM MiBase.sys.indexes WHERE object_id=1275867612&lt;/pre&gt;&lt;span lang="ES-AR"&gt;De esta forma ya sabemos que table y que índice participaba en el bloqueo.&lt;/span&gt;&lt;br /&gt;&lt;div class="MsoNormal" style="color: #333399; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR" style="font-family: &amp;quot;;"&gt;Para el caso 2 (página) comenzaremos averiguando la base de la misma forma y la siguiente información nos viene como:&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR"&gt;PAGE: dbId:FileId:PageId&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR" style="font-family: &amp;quot;;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;Si no tenemos nuestra base con varios archivos sino todo en uno del primary el segundo campo siempre será 1.&lt;/span&gt;&lt;/div&gt;&lt;div style="color: #333399; font-family: arial; text-align: justify;"&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;Para analizar el último debemos obtener la información de la página (&lt;span style="text-transform: uppercase;"&gt;79868773 &lt;/span&gt;en el ejemplo). Para esto tenemos dos formas:&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt;"&gt;&lt;span lang="ES-AR"&gt; &lt;/span&gt;&lt;/div&gt;&lt;span style="color: #333399; font-family: arial;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;div class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0.0001pt;"&gt;&lt;span lang="ES-AR" style="color: blue; font-family: &amp;quot;;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR" style="color: blue;"&gt;DBCC&lt;/span&gt;&lt;span lang="ES-AR"&gt; TRACEON&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: grey;"&gt;(&lt;/span&gt; 3604 &lt;span style="color: grey;"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR" style="color: blue;"&gt;DBCC&lt;/span&gt;&lt;span lang="ES-AR"&gt; PAGE&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: grey;"&gt;(&lt;/span&gt;12&lt;span style="color: grey;"&gt;,&lt;/span&gt;1&lt;span style="color: grey;"&gt;,&lt;/span&gt;79868773&lt;span style="color: grey;"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR" style="color: grey;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR"&gt;o&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR" style="color: blue;"&gt;DBCC&lt;/span&gt;&lt;span lang="ES-AR"&gt; PAGE&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: grey;"&gt;(&lt;/span&gt;12 &lt;span style="color: grey;"&gt;,&lt;/span&gt; 1&lt;span style="color: grey;"&gt;,&lt;/span&gt; 79868773&lt;span style="color: grey;"&gt;)&lt;/span&gt; &lt;span style="color: blue;"&gt;WITH&lt;/span&gt; &lt;span style="color: blue;"&gt;TABLERESULTS&lt;/span&gt;&lt;span style="color: grey;"&gt;,&lt;/span&gt;&lt;span style="color: blue;"&gt;NO_INFOMSGS&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR" style="font-family: &amp;quot;;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;En el primer caso es necesario el traceon porque sino no podemos ver la salida, la cual saldrá en modo texto. En el segundo no es necesario visto que la salida la veremos en modo tabla.&lt;/span&gt;&lt;/div&gt;&lt;div style="color: #333399; font-family: arial; text-align: justify;"&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;Sea cual fuera el caso que elegimos debemos buscar el renglon (o registro) que tenga la siguiente información:&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt;"&gt;&lt;span lang="ES-AR"&gt; &lt;/span&gt;&lt;/div&gt;&lt;span style="color: #333399; font-family: arial;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;div align="left" class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: left;"&gt;&lt;span style="font-family: &amp;quot;;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div align="left" class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-align: left; text-autospace: none;"&gt;m_objId&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: grey;"&gt;(&lt;/span&gt;AllocUnitId&lt;span style="color: grey;"&gt;.&lt;/span&gt;idObj&lt;span style="color: grey;"&gt;)&lt;/span&gt; &lt;span style="color: grey;"&gt;=&lt;/span&gt; 1051306955                                  m_indexId&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: grey;"&gt;(&lt;/span&gt;AllocUnitId&lt;span style="color: grey;"&gt;.&lt;/span&gt;idInd&lt;span style="color: grey;"&gt;)&lt;/span&gt; &lt;span style="color: grey;"&gt;=&lt;/span&gt; 7&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR" style="font-family: &amp;quot;;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;y con esto obtengo el ObjectId para poder continuar mi análisis como en el caso anterior.&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt;"&gt;&lt;span lang="ES-AR"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt;"&gt;&lt;span lang="ES-AR"&gt;Por último nos queda el caso del índice (&lt;span style="text-transform: uppercase;"&gt;KEY: 12:397371816017920 (760119e06bff)&lt;/span&gt;). En este caso debemos leerlo como:&lt;/span&gt;&lt;/div&gt;&lt;span style="color: #333399; font-family: arial;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;div class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0.0001pt;"&gt;&lt;span lang="ES-AR" style="font-family: &amp;quot;;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR"&gt;KEY: dbId:hObjecto (hash)&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;span lang="ES-AR"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;El hash puede ser ignorado, visto que no tenemos función para transformarlo (es la gracia de los hash!), así que nos quedaremos con el hObj. Este número se encuentra almacenado en la msdb así que lo podemos utilizar para calcular el objetcId:&lt;/span&gt;&lt;br /&gt;&lt;span lang="ES-AR"&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;SELECT * FROM MiBase.sys.partitions&lt;br /&gt;WHERE hobt_id = 397371816017920&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin: 0cm; mso-layout-grid-align: none; text-autospace: none;"&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR" style="font-family: &amp;quot;;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="color: #333399; font-family: arial; line-height: normal; margin: 0cm 0cm 0.0001pt; text-align: justify;"&gt;&lt;span lang="ES-AR"&gt;De esta consulta obtenemos el object_id y podemos hacer nuestro análisis de siempre.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-7873441387734540331?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/7873441387734540331/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/08/entendiendo-el-waitresource.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/7873441387734540331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/7873441387734540331'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/08/entendiendo-el-waitresource.html' title='SQL2008: Entendiendo el Waitresource'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-3889723546488050838</id><published>2011-07-26T13:02:00.005-03:00</published><updated>2011-10-04T15:34:45.070-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='job name'/><category scheme='http://www.blogger.com/atom/ns#' term='UNIQUEIDENTIFIER'/><category scheme='http://www.blogger.com/atom/ns#' term='sp_who'/><category scheme='http://www.blogger.com/atom/ns#' term='sp_who2'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='job_id'/><title type='text'>Traduciendo jobs names de SQL</title><content type='html'>&lt;div style="color: #333399; text-align: justify;"&gt;&lt;span style="font-family: arial;"&gt;Muchas veces estamos monitoreando en tiempo real nuestro SQL y hay cosas interesantes para observar. Este pequeño articulo es la puerta de entrada al de la semana que viene donde profundizaremos este tema.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: arial;"&gt;Por ahora lo que quiero mencionar es simplemente un pequeño y usual problema . La forma mas simple es mediante el sp_who2, el cual en la columna BlkBy nos indicará si un proceso se encuentra proqueado y en la columna ProgramName podremos obtener que programa es la pobre víctima. Es muy importante que si este proceso fue lanzado por un job no veremos el nombre sino una secuencia extraña de números que debemos traducir, por ejemplo:&lt;/span&gt;&lt;/div&gt;&lt;span style="font-family: courier new;"&gt;SQLAgent - TSQL JobStep (Job 0xF64F718235C7154DB6F21B5935D7218A : Step 1)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #333399; font-family: arial;"&gt;Para traducir esto debemos tomar la parte "numerica" del mensaje y copiarla en la siguiente consulta:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="sql"&gt;&lt;br /&gt;SELECT name&lt;br /&gt;FROM msdb.dbo.sysjobs&lt;br /&gt;WHERE job_id = CAST( 0xF64F718235C7154DB6F21B5935D7218A AS UNIQUEIDENTIFIER)&lt;br /&gt;&lt;/pre&gt;&lt;span style="color: #333399; font-family: arial;"&gt;así obtendremos el nombre del job en cuestión. &lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333399; font-family: arial;"&gt;Con esta info ahora solo nos resta cruazarla con las tablas del sistema para saber si un spid en particular está molestando o no, pero como dije eso lo veremos la semana siguiente.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333399; font-family: arial;"&gt;Saludos,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333399; font-family: arial;"&gt;Andrés&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-3889723546488050838?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/3889723546488050838/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/07/traduciendo-jobs-names.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/3889723546488050838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/3889723546488050838'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/07/traduciendo-jobs-names.html' title='Traduciendo jobs names de SQL'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-7011779707039685862</id><published>2011-07-18T11:34:00.000-03:00</published><updated>2011-07-18T11:40:47.981-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Cluster'/><category scheme='http://www.blogger.com/atom/ns#' term='PowerShell'/><title type='text'>Cluster desde powershell</title><content type='html'>&lt;div align="justify"&gt;&lt;br /&gt;&lt;span style="font-family:arial;color:#333399;"&gt;Cuando se trabaja con SQL en entornos de alta disponibilidad es muy comun trabajar con windows en cluster y tener que lidiar con varias tareas que involucran tanto sea al sql como al cluster.&lt;br /&gt;La forma tradicional de como hacer esto es con el comando Cluster.exe, pero para esto deberíamos habilitar el cmd shell lo cual nunca es recomendable.&lt;br /&gt;Por suerte desde 2008 tenemos de forma nativa en los jobs incorporar rutinas de powershell, pero hasta ese entonces la única salida era seguir acudiendo al cluster.exe.&lt;br /&gt;Esto ha cambiado con la salida de Windows Server 2008 R2 (no confundir con SQL Server 2008 R2!!!), donde se ha incorporado un modulo de cluster al powershell que hace muy comoda su adminstración.&lt;br /&gt;Para utilizar este modulo primero debemos entrar a nuestra consola de powershell y ejecutar el siguiente comando:&lt;br /&gt;&lt;br /&gt;Import-Module FailoverClusters&lt;br /&gt;&lt;br /&gt;Con esto se incorporarán las funciones de cluster y podremos utilizarlas. En mi caso me ha servido porque en conjunto con SQL 2008 puedo llamarlas desde un job de sql configurandolo con rutina powershell y&lt;br /&gt;&lt;br /&gt;esto es flexible y seguro.&lt;br /&gt;&lt;br /&gt;Les adjunto un link de como pasar las tareas de Cluster.exe a powershell:&lt;br /&gt;&lt;br /&gt;Como usarlo: &lt;a href="http://technet.microsoft.com/en-us/library/ee619751%28WS.10%29.aspx"&gt;http://technet.microsoft.com/en-us/library/ee619751%28WS.10%29.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Mapeo: &lt;a href="http://technet.microsoft.com/en-us/library/ee619744%28WS.10%29.aspx"&gt;http://technet.microsoft.com/en-us/library/ee619744%28WS.10%29.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;====================================================================&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div align="justify"&gt;&lt;span style="font-family:arial;color:#333399;"&gt;When working with SQL in high availability is very common to work over windows cluster and dealing with various tasks involving both sql server and the windows cluster.&lt;br /&gt;The traditional way of how to do this is with the command Cluster.exe, but for this should enable the cmd shell it is never recommended.&lt;br /&gt;Luckily since 2008 We have powershell natively in jobs routines, but the only way out was to keep going to the cluster.exe.&lt;br /&gt;This has changed with the release of Windows Server 2008 R2 (not to be confused with SQL Server 2008 R2!!!), which has a powershell module of the cluster that makes it very comfortable its management.&lt;br /&gt;To use this module must first enter our powershell console and run the following command:&lt;br /&gt;&lt;br /&gt;Import-Module FailoverClusters&lt;br /&gt;&lt;br /&gt;This will incorporate the functions of cluster and we use them. In my case I have served it in conjunction with SQL 2008 I can call them from a sql job of setting it powershell with routine and that is&lt;br /&gt;&lt;br /&gt;flexible and secure.&lt;br /&gt;&lt;br /&gt;I attached a link of how to change tasks Cluster.exe to powershell:&lt;br /&gt;&lt;br /&gt;How to use: &lt;a href="http://technet.microsoft.com/en-us/library/ee619751%28WS.10%29.aspx"&gt;http://technet.microsoft.com/en-us/library/ee619751%28WS.10%29.aspx&lt;/a&gt;&lt;br /&gt;Mapping: &lt;a href="http://technet.microsoft.com/en-us/library/ee619744%28WS.10%29.aspx"&gt;http://technet.microsoft.com/en-us/library/ee619744%28WS.10%29.aspx&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-7011779707039685862?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/7011779707039685862/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/07/cluster-desde-powershell.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/7011779707039685862'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/7011779707039685862'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/07/cluster-desde-powershell.html' title='Cluster desde powershell'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-5490380461885072125</id><published>2011-07-07T16:13:00.000-03:00</published><updated>2011-10-04T15:42:44.992-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='restore'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='FILESTREAM'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>Restore de FILESTREAM</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;span style="color: #333399;"&gt;El filestream es una funcionalidad nueva del SQL2008 que a veces es discutida pero a mi ver es muy buena en muchos casos. En esta oportunidad me gustaría hablar sobre un caso interesante y es como hacer para restorear una base que tiene campos filestream pero que no ha sido diseñado pensando en esto. ¿A que me refiero? Uno puede diseñar la base desde un principio alojando las tablas que contienen archivos en filegroups diferentes para asegurarse que en un restore parcial no afecten, pero no siempre las cosas nacen en este orden, muchas veces las aplicaciones vienen de hace tiempo y "llegan" al sql 2008 y en la tabla que se encuentra el binario tambien se encuentra otra información indispensable para el funcionamiento del sisetema. En estos casos no restorear el filegroup en cuestión es lo mismo que no restorear nada. Para estos casos el filestream es una buena solución visto que en cierto modo puedo hacer un filegroup "vertical".&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333399;"&gt;Supongamos una tabla "cliente" que tenga los campos id, nombre, apellido, Documento, siendo el último un VARBINARY(MAX). Si esta tabla la pongo en un filegroup diferente y hago un restore del resto obtendría error al realizar la siguiente consulta:&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;SELECT id, nombre, apellido FROM Cliente&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #333399; font-weight: bold;"&gt;Restore con PARTIAL&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="color: #000099;"&gt;Ahora supongamos que mi campo base tiene definido FILESTREAM y el campo Documento se encuentra albergado de esa forma. En este caso ante un problema por el cual deseo recuperar mi base podría hacer lo siguiente:&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;RESTORE DATABASE [AIELLO_DBA]&lt;br /&gt;FROM DISK = N'D:\Prueba_fs.bak'&lt;br /&gt;WITH REPLACE, PARTIAL, RECOVERY&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #333399; text-align: justify;"&gt;Y ahora la consulta antes mencionada funcionaría sin problemas, solamente obtendría un error si intento acceder al campo documento, como sería con la siguiente consulta:&lt;/div&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;SELECT id, nombre, apellido, Documento FROM Cliente&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-family: courier new;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="color: red; font-family: georgia;"&gt;Msg 670, Level 16, State 1, Line 2&lt;/span&gt;&lt;br /&gt;&lt;span style="color: red; font-family: georgia;"&gt;Large object (LOB) data for table "dbo.Cliente&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;span style="color: red; font-family: georgia;"&gt;" resides on an offline filegroup ("AIELLO_DBA_FS") that cannot be accessed.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333399;"&gt;&lt;br /&gt;Lo que logré es poner mi base en linea en un tiempo mucho menor. Pero lamentablemente para recuperar todo debo volver a hacer el restore full en otro momento.&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="color: #333399;"&gt;&lt;br /&gt;&lt;span style="color: #333399; font-weight: bold;"&gt;Restore operativo por partes&lt;/span&gt;&lt;br /&gt;No todo está perdido!! como dice el dicho, hecha la ley hecha la trampa, entonces lo que hice es lo siguiente.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333399;"&gt;En mi backup nocturno hago lo siguiente:&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;-- =============================================&lt;br /&gt;-- Author: Andrés Aiello&lt;br /&gt;-- Create date: 07/07/2011&lt;br /&gt;-- Backup full poniendo readonly el filestream&lt;br /&gt;-- =============================================&lt;br /&gt;&lt;br /&gt;ALTER DATABASE [AIELLO_DBA] MODIFY FILEGROUP [AIELLO_DBA_FS] READONLY&lt;br /&gt;BACKUP DATABASE [AIELLO_DBA]&lt;br /&gt;TO DISK = N'D:\Prueba_fs_readonly.bak'&lt;br /&gt;WITH NOFORMAT, NOINIT, NAME = N'PRUEBA FS', SKIP, NOREWIND, NOUNLOAD, STATS = 10&lt;br /&gt;ALTER DATABASE [AIELLO_DBA] MODIFY FILEGROUP [AIELLO_DBA_FS] READWRITE&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #333399; text-align: justify;"&gt;Por lo tanto el filegroup de los documentos es guardado como readonly. Al momento de hacer restore lo puedo hacer de dos formas:&lt;/div&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;--============== MODO 1 - Full&lt;br /&gt;-- 7:38 min&lt;br /&gt;&lt;br /&gt;RESTORE DATABASE [AIELLO_DBA]&lt;br /&gt;FROM DISK = N'D:\Prueba_fs_readonly.bak'&lt;br /&gt;WITH REPLACE, RECOVERY&lt;br /&gt;ALTER DATABASE [AIELLO_DBA] MODIFY FILEGROUP [AIELLO_DBA_FS] READWRITE&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="color: #333399;"&gt;Esta forma hace un restore completo de la forma tradicional, dejando el servicio bajo el tiempo que dure el restore (en una base donde el mayor porcentaje del espacio son archivos esto puede crecer mucho).&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333399;"&gt;Y el plan b...&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333399;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre class="sql" name="code"&gt;&lt;br /&gt;-- =============================================&lt;br /&gt;-- Author: Andrés Aiello&lt;br /&gt;-- Create date: 07/07/2011&lt;br /&gt;-- Restore inteligente&lt;br /&gt;-- =============================================&lt;br /&gt;--============== MODO 2 - Sin los binarios&lt;br /&gt;-- 0:46 &lt;br /&gt;RESTORE DATABASE [AIELLO_DBA]&lt;br /&gt;FROM DISK = N'D:\Prueba_fs_readonly.bak'&lt;br /&gt;WITH REPLACE, PARTIAL, RECOVERY&lt;br /&gt;ALTER DATABASE [AIELLO_DBA] SET RECOVERY FULL WITH NO_WAIT&lt;br /&gt;-- Base online sin los binarios!!!&lt;br /&gt;-- Recuperar todo...&lt;br /&gt;-- 8:30&lt;br /&gt;RESTORE DATABASE [AIELLO_DBA]&lt;br /&gt;FILEGROUP='AIELLO_DBA_FS'&lt;br /&gt;FROM DISK = N'D:\Prueba_fs_readonly.bak'&lt;br /&gt;WITH REPLACE, RECOVERY&lt;br /&gt;ALTER DATABASE [AIELLO_DBA] MODIFY FILEGROUP [AIELLO_DBA_FS] READWRITE&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="color: #333399;"&gt;De esta forma la base en solo 45 segundos se encuentra operativa!!! y mientras se va utilizando se va recuperando en background los documentos del otro filegroup. Para evitar inconsistencias mientras se recupera esa parte el filegroup se mantiene en readonly.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333399;"&gt;Andrés&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-5490380461885072125?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/5490380461885072125/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/07/restore-de-filestream.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/5490380461885072125'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/5490380461885072125'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/07/restore-de-filestream.html' title='Restore de FILESTREAM'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-150308489818745784</id><published>2011-04-08T11:33:00.000-03:00</published><updated>2011-09-15T12:39:43.479-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='CREATE USER'/><category scheme='http://www.blogger.com/atom/ns#' term='LOGIN'/><category scheme='http://www.blogger.com/atom/ns#' term='EXECUTE AS'/><category scheme='http://www.blogger.com/atom/ns#' term='WITHOUT LOGIN'/><category scheme='http://www.blogger.com/atom/ns#' term='sp_change_users_login'/><category scheme='http://www.blogger.com/atom/ns#' term='CREATE USER WITHOUT LOGIN'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>CREATE USER WITHOUT LOGIN</title><content type='html'>&lt;div style="color: #333399; text-align: justify;"&gt;Una instrucción no muy utilizada es la de create user without login. ¿En que consiste? tal como su nombre lo indica lo que hace es crear un usuario sin asociarlo a un login en el servidor, ahora veamos porque querríamos utilizar esto.&lt;br /&gt;Antes que nada vayamos a la sintaxis&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;CREATE USER user_name&lt;br /&gt;WITHOUT LOGIN&lt;br /&gt;WITH DEFAULT_SCHEMA = [dbo]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #3333ff; text-align: justify;"&gt;&lt;span style="color: #333399;"&gt;Este usuario podrá recibir permisos, ser incluido en roles y todo lo que considere necesario, pero nadie podrá loguearse con dicho usuario. Un posible uso (aunque a mi ver no recomendado) es cuando aún no se el nombre del login que tendrá y quiero dejarlo listo para una vez definido todo modificar el login asociado y ya tengo todo andando. Esto lo podré hacer con la sentencia:&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;EXEC sp_change_users_login 'update_one', @username, @loginname&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #333399; text-align: justify;"&gt;¿Porque digo que no recomiendo esto? porque en estos casos una mejor práctica es asignar los permisos a un role, y una vez definido y creado el usuario simlemente se lo agrega al role. Es mucho mas comoda la administración de permisos si uno utiliza roles.&lt;/div&gt;&lt;br /&gt;&lt;span style="color: #000099; font-weight: bold;"&gt;EXECUTE AS&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #333399; text-align: justify;"&gt;El uso mas interesante viene de la mano de la opción EXECUTE AS. Esta opción me permite hacer que un procedimiento, función o trigger se ejecute con los permisos de otro usuario que no sea necesariamente el que lo invocó. De esta forma podría por ejemplo hacer un procedimiento que muestre información que de otra forma el usuario no hubiera podido ver. Al no estar este usuario asociado a ningún login no se corre peligro de que alguien se loguee con dicho usuario y escale permisos.&lt;br /&gt;La forma de hacer esto es, por ejemplo:&lt;/div&gt;&lt;pre style="font-family: courier new;"&gt;CREATE PROCEDURE dbo.procedimiento&lt;br /&gt;WITH EXECUTE AS 'UsuarioSinLogin'&lt;br /&gt;AS&lt;br /&gt;TRUNCATE TABLE ...&lt;br /&gt;GO&lt;/pre&gt;&lt;div style="color: #333399; text-align: justify;"&gt;En este ejemplo un usuario con permisos de datareader y ejecución sobre el stored puede tener una forma comoda y segura de limpiar una tabla en particular.&lt;/div&gt;&lt;br /&gt;&lt;span style="color: #333399; font-weight: bold;"&gt;Huerfanos&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #333399; text-align: justify;"&gt;Hay un caso muy particular en el cual mucha gente se topa con la sentencia WITHOUT LOGIN sin desearlo, y a veces sin entender porque. Supongamos que tenemos el usuario1 y login1 en la base de datos1 en el servidor1. Mediante backup y restore movemos la base al servidor2. El usuario, como muchos ya saben, queda huerfano de su login, y es necesario utilizar la función nombrada en la primer parte para volver a asociarlo (esto se debe a los ids internos de los usuarios). Si deseamos hacer un script completo de la base nos vamos a encontrar que los logins van a aparecer como WITHOUT LOGIN y esto se debe a que al no coincidir el id interno el motor asume que no tiene login. Es importante considerar esto antes de ponerse a buscar como loco que procedimiento hace un EXECUTE AS o algo similar. En la página de microsoft se puede encontrar un script muy simple para corregir estos casos cuando el usuario y el login tienen el mismo nombre.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #333399;"&gt;Para mas información: &lt;/span&gt;&lt;br /&gt;http://msdn.microsoft.com/en-us/library/ms173463.aspx&lt;br /&gt;http://msdn.microsoft.com/es-es/library/ms174378.aspx&lt;br /&gt;http://msdn.microsoft.com/en-us/library/ms188354.aspx&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-150308489818745784?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/150308489818745784/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/04/create-user-without-login.html#comment-form' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/150308489818745784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/150308489818745784'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/04/create-user-without-login.html' title='CREATE USER WITHOUT LOGIN'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-1936807811857618460</id><published>2011-03-16T12:13:00.000-03:00</published><updated>2011-03-16T13:34:55.321-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linked servers'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 11'/><category scheme='http://www.blogger.com/atom/ns#' term='Contained Databases'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Denali'/><title type='text'>Contained Databases SQL Denali (2011)</title><content type='html'>&lt;div style="text-align: justify; color: rgb(51, 51, 153);"&gt;Una de las novedades, a mi ver, mas interesantes del SQL 2011 son las bases autocontenidas (&lt;a class="LW_CollapsibleArea_TitleAhref" title="Collapse" id="5417b0c9-55ec-4daf-a67a-219b68bfc6af"&gt;&lt;span class="LW_CollapsibleArea_Title"&gt;Contained Databases&lt;/span&gt;&lt;/a&gt;). En las versiones actuales hay cierta información que se guarda en la base, y otra que se guarda en la instancia, como por ejemplos los logins o los jobs. Todo esto seguirá existiendo pero ahora habrá una nueva forma de guardar las cosas y es dentro de la misma base. Esto va a significar una mejora muy importante cuando uno realiza un movimiento de una base de un servidor a otro, permitiendo que toda la lógica de negocio correspondiente a la base viaje con esta, disminuyendo de esta forma las probabilidades de olvidar algo.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Logins&lt;/span&gt;&lt;br /&gt;Una de las caractecterísticas mas importantes son los logins. Las bases contenidas permiten que el login lo maneje la misma base y no la instancia. Comunmente cuando uno realiza una migración los usuarios de la base se encuentran asociados a un login de la instancia (tanto sea uno de seguridad integrada o un login sql), y al momento de migrar esta relación se pierde dejando al usuario huerfano. Para solucionar esto es necesario al momento de restorear ejecutar un script que se encargue de mapear nuevamente el usuario con el login correspondiente. Esto no sería necesario en una base contenida visto que toda la información de login se encuentra almacenada en si misma. Es muy importante resaltar que para que esto funcione al momento de establecer la conexion a la base hay que indicar como base default dicha base y no la master como suele venir por defecto.&lt;br /&gt;NOTA: No tuve tiempo de probar cuando es seguridad integrada como se comporta al mover de un servidor a otro y mas allá de que el usuario se mantiene relacionado con el login, ver si el login se encuentra bien definido o requiere algo extra.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Linked servers&lt;/span&gt;&lt;br /&gt;Los linked servers también pueden ser almacenados en la base de este nuevo modelo. Es sumamente util esto cuando son utilizados por la aplicación dueña de la base. Los beneficios son notables al momento de puesta en producción inicial, movimientos de base, y para tener mas aislados los elementos de cada base/aplicación. Es una función que me parece va a volverse un MUST en el diseño de bases de datos.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Jobs&lt;/span&gt;&lt;br /&gt;Otro elemento que puede pertenecer a la base. En este caso creo que el mayor beneficio es el aislar la lógica de la aplicación. ¿Todos mis jobs van a pertenecer a alguna base ahora? la respuesta es NO. Los jobs de mantenimiento, por ejemplo, va a seguir siendo mejor mantenerlos en la instancia. Ejemplo si tengo un job para hacer backup de mis bases todos los días a las 11PM ese job está bien que se mantenga como un job de la instancia. Lo mismo los de reindexado, actualización de indices etc. En cambio si tengo un job que hace algo propio de la aplicación (ejemplo todas las noches actualiza el estado de los usuarios) ese si debe ir en la base.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Manos a la obra!&lt;/span&gt;&lt;br /&gt;El primer paso es habilitar nuestra instancia para utilizar Conteined Databases. El código es el siguiente:&lt;br /&gt;&lt;/div&gt;&lt;pre class="csharpcode"&gt;sp_configure &lt;span class="str"&gt;'show advanced'&lt;/span&gt;, 1;&lt;br /&gt;&lt;span class="kwrd"&gt;RECONFIGURE&lt;/span&gt; &lt;span class="kwrd"&gt;WITH&lt;/span&gt; OVERRIDE;&lt;br /&gt;&lt;span class="kwrd"&gt;go&lt;/span&gt;&lt;br /&gt;sp_configure &lt;span class="str"&gt;'contained database authentication'&lt;/span&gt;, 1;&lt;br /&gt;&lt;span class="kwrd"&gt;RECONFIGURE&lt;/span&gt; &lt;span class="kwrd"&gt;WITH&lt;/span&gt; OVERRIDE;&lt;br /&gt;&lt;span class="kwrd"&gt;go&lt;/span&gt;&lt;/pre&gt;&lt;span style="color: rgb(51, 51, 153);"&gt;Y luego crear la base, indicando que será una base contenida:&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; MiBase CONTAINMENT = &lt;span class="kwrd"&gt;PARTIAL&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;go&lt;/span&gt;&lt;/pre&gt;&lt;span style="color: rgb(51, 51, 153);"&gt;Con esto ya tenemos nuestra base lista!!!&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 153);"&gt;Saludos y espero que les sirva. Para mas información: http://msdn.microsoft.com/en-us/library/ff929071%28v=SQL.110%29.aspx .&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 153);"&gt;Andrés&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-1936807811857618460?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/1936807811857618460/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/03/contained-databases-sql-denali-2011.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/1936807811857618460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/1936807811857618460'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/03/contained-databases-sql-denali-2011.html' title='Contained Databases SQL Denali (2011)'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-700140522618550762</id><published>2011-01-25T08:19:00.000-03:00</published><updated>2011-01-25T08:52:00.922-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sp_who'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='sp_who2'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>Sp_who en Oracle</title><content type='html'>&lt;span style="color: rgb(0, 0, 153);"&gt;En el tiempo que llevo trabajando con SQL Server creo que el comando que mas veces ejecuté es el &lt;span style="font-style: italic;"&gt;sp_who&lt;/span&gt; o su versión extendida &lt;span style="font-style: italic;"&gt;sp_who2&lt;/span&gt;. Este comando cuando se está administrando una base es muy comodo por su sencillez y nos da un buen resumen de que está ocurriendo en el servidor. Claramente cuando hay alguna situación fuera de lo normal esto es solo la puerta de entrada para despues controlar las DMVs, los contadores del sistema operativo, etc, pero siempre es un buen comienzo. Muchas personas les pasa que acostumbradas a ambientes SQL Server se sientan frente a un sistema Oracle y buscan algo equivalente y no lo encuentran, así que veamos como sería una consulta equivalente en Oracle.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;No contamos con un stored procedure prearmado que nos brinde la información, pero al igual que en SQL Server, esta información se nutre de las sesiones, así que consultaremos la &lt;span style="font-style: italic;"&gt;V_$SESSION&lt;/span&gt; al igual que el &lt;span style="font-style: italic;"&gt;sp_who&lt;/span&gt; original.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;En este caso para que les sea mas comodo acomodé los campos para que queden igual que en la versión original.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    SELECT sid, status, Username,  terminal, blocking_session_status,  schemaname, a.name Command_Action,  logon_time, program&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    FROM SYS.V_$SESSION s&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    INNER JOIN AUDIT_ACTIONS a ON s.command=a.action;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Como podrán ver aparte de consultar la vista de sesiones hice un join con la tabla &lt;span style="font-style: italic;"&gt;AUDIT_ACTIONS&lt;/span&gt; que es la que contiene las descripciones de cada evento para que sepamos que está haciendo la session.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Lo que recomiendo es guardar esta consulta en un script a mano y poco a poco irse internalizando mas con la &lt;span style="font-style: italic;"&gt;SYS.V_$SESSION&lt;/span&gt; visto que tiene mucho para darnos. Quien no esté acostumbrado se va a sorprender al encontrar muchos mas campos que en su equivalente de SQL Server.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Pueden encontrar mas detalles en:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;http://download.oracle.com/docs/cd/B19306_01/server.102/b14237/dynviews_2088.htm&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Por último si lo que se desea es hacer algo mas semejante al sp_who2 y no tienen ganas de internalizarse en los demas campos, puede hacerse una función que nos retorne los resultados de la consulta. Esta función sería:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;-- Creacion de funcion que retorna como resultado una tabla&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;CREATE OR REPLACE  function sp_who2 return sp_who2_tab PIPELINED&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;IS   &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;CURSOR cur0 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;IS&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    SELECT sid, status, Username,  terminal, blocking_session_status,  schemaname, a.name Command_Action,  logon_time, program&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    FROM SYS.V_$SESSION s&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    INNER JOIN AUDIT_ACTIONS a ON s.command=a.action;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;out_rec sp_who2_rec := sp_who2_rec(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    OPEN cur0; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    LOOP&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    FETCH cur0 INTO out_rec.sid, out_rec.status, out_rec.Username, &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         out_rec.terminal, out_rec.blocking_session_status,  out_rec.schemaname, out_rec.Command_Action,  out_rec.logon_time, out_rec.program;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    EXIT WHEN cur0%NOTFOUND;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        PIPE ROW (out_rec);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    END LOOP;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    CLOSE cur0;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;RETURN;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;END;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Y como sucede con las funciones que retornan tablas en Oracle, la forma de utilizarla sería:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;SELECT * FROM TABLE(sp_who2);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Claramente a esto hay que sumarle la creación de los objetos necesarios (record y table).&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Espero que les haya servido!&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-700140522618550762?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/700140522618550762/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/01/spwho-en-oracle.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/700140522618550762'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/700140522618550762'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/01/spwho-en-oracle.html' title='Sp_who en Oracle'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-2180534640700702160</id><published>2011-01-17T09:51:00.001-03:00</published><updated>2011-01-17T10:05:05.718-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eliminar tabla temporal'/><category scheme='http://www.blogger.com/atom/ns#' term='CREATE TABLE'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='drop and create'/><category scheme='http://www.blogger.com/atom/ns#' term='Eliminar tabla temporaria'/><title type='text'>Drop and Create</title><content type='html'>&lt;span style="color: rgb(0, 0, 153);"&gt;Muchas veces al armar los scripts figuran creación de objetos, y obviamente es deseable que nuestro script no falle por mas que dicho objeto ya se encuentre creado. En el caso de los stored procedures, en Oracle, tenemos la opción de CREATE OR REPLACE, pero cuando nos manejamos con tablas esta opción, lamentablemente, no existe ni en Oracle ni en SQL Server.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Para eliminar y crear una tabla desde cero en SQL Server es bastante conocido el método (de echo en la versión 2008 en adelante ya lo tenemos a un click del managment). El código es:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;-- Prueba 1: Controlo si existe la tabla, si es necesario la elimino y la vuelvo a crear&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.prueba_creacion') AND type in (N'U'))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;DROP TABLE dbo.prueba_creacion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;CREATE TABLE prueba_creacion(clave INT);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;De esta forma controlamos si la tabla existe, y en caso afirmativo la eliminamos. Luego podemos proceder a crearla sin problema.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Otra es la historia cuando la tabla es una tabla temporaria. Lo intuitivo sería ahcer lo mismo con el nombre de la tabla temporaria, pero esto arrojaría error. ¿porqué? porque la tabla temporaria se encuentra alojada en la tempdb. El código para poder realizar lo mismo con tablas temporarias sería:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;-- Prueba 2: Controlo si existe la tabla temporaria, si es necesario la elimino y la vuelvo a crear&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;IF NOT OBJECT_ID('tempdb.dbo.#prueba_creacion_temp') IS NULL&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;DROP TABLE dbo.#prueba_creacion_temp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;CREATE TABLE #prueba_creacion_temp(clave INT);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Pueden ver que se código no importa cuantas veces se ejecute nunca arrojará error.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Por último es interesante resaltar que en oracle no podemos realizar ninguno de estos controles debido a que el parser arrojará error la primera vez al hacer un DROP TABLE de una tabla que aún no existe. Por este motivo la forma de realizar lo mismo en Oracle sería:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;-- Prueba 3: Controlo si existe la tabla en oracle, si es necesario la elimino y la vuelvo a crear&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;BEGIN  &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  EXECUTE IMMEDIATE 'DROP TABLE prueba_creacion';&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  EXCEPTION WHEN OTHERS THEN NULL;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;END;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;CREATE TABLE prueba_creacion(clave INT);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;De esta forma se ejecutará siempre el DROP TABLE y arrojará error de sintaxis cuando no exista la tabla, pero el error será en el sql dinámico y no en todo el script, y estará capturado por el WHEN OTHERS, haciendo que sea transparente para el resto de la ejecución.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-2180534640700702160?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/2180534640700702160/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/01/drop-and-create.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2180534640700702160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2180534640700702160'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/01/drop-and-create.html' title='Drop and Create'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-5573320110282217394</id><published>2011-01-06T12:13:00.000-03:00</published><updated>2011-01-06T19:12:57.178-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL 11'/><category scheme='http://www.blogger.com/atom/ns#' term='NEXT VALUE FOR'/><category scheme='http://www.blogger.com/atom/ns#' term='IDENTITY'/><category scheme='http://www.blogger.com/atom/ns#' term='Sequence'/><category scheme='http://www.blogger.com/atom/ns#' term='secuencia'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='NEXTVAL'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Denali'/><title type='text'>SQL Server Denali - Sequence</title><content type='html'>Estuve probando el SQL 11 y una de las cosas que mas contento me puso es la incorporación de las SECUENCIAS tal como lo maneja Oracle. ¿Qué es esto? básicamente es un objeto en el motor que podemos crear y nos arroja números de forma ordenada según el criterio que hayamos definido. El principal objetivo es no depender de claves de tipo IDENTITY.&lt;br /&gt;En este artículo hablaré de 3 cosas:&lt;br /&gt;1) Como se utilizan las secuencias (sequence)&lt;br /&gt;2) Comparar con Oracle el manejo de secuencias&lt;br /&gt;3) Stress test comparando secuencias con campos identity&lt;br /&gt;&lt;br /&gt;Un ejemplo de como utilizar este nuevo objeto sería el siguiente:&lt;br /&gt;&lt;br /&gt;USE SQLDENA&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- La forma tradicional de hacer un "autonumerico" es&lt;br /&gt;IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[PruebaSecuencia]') AND type in (N'U'))&lt;br /&gt;DROP TABLE [dbo].PruebaSecuencia&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;CREATE TABLE PruebaSecuencia(&lt;br /&gt;id    INT PRIMARY KEY IDENTITY,&lt;br /&gt;dato1 VARCHAR(100)&lt;br /&gt;)&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- Pero ahora con las secuencias lo podemos hacer de la siguiente forma&lt;br /&gt;IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[PruebaSecuencia]') AND type in (N'U'))&lt;br /&gt;DROP TABLE [dbo].PruebaSecuencia&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- Creamos la tabla que SIN campo identity&lt;br /&gt;CREATE TABLE PruebaSecuencia(&lt;br /&gt;id    INT PRIMARY KEY,&lt;br /&gt;dato1 VARCHAR(100)&lt;br /&gt;)&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- Creo la secuencia, se puede definir como se incrementa, etc&lt;br /&gt;-- Como se puede ver son muy flexibles permitiendo configurar como se van a comportar&lt;br /&gt;CREATE SEQUENCE dbo.NuevaSec&lt;br /&gt;   AS INT&lt;br /&gt;   START WITH 1&lt;br /&gt;   INCREMENT BY 1&lt;br /&gt;   MINVALUE 1&lt;br /&gt;   MAXVALUE 999999&lt;br /&gt;   CACHE 20&lt;br /&gt;;&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- Obtengo unos valores de ejemplo&lt;br /&gt;SELECT NEXT VALUE FOR dbo.NuevaSec&lt;br /&gt;GO 4&lt;br /&gt;&lt;br /&gt;-- Reinicio la secuencia para el ejemplo&lt;br /&gt;ALTER SEQUENCE dbo.NuevaSec RESTART&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- Ejemplo de como la usaria&lt;br /&gt;INSERT INTO PruebaSecuencia&lt;br /&gt;select next value for dbo.NuevaSec as nro,  'Valor1' as dato1&lt;br /&gt;&lt;br /&gt;-- O tambien...&lt;br /&gt;INSERT INTO PruebaSecuencia (id, dato1)&lt;br /&gt;VALUES (next value for dbo.NuevaSec,  'Valor1')&lt;br /&gt;&lt;br /&gt;-- Que valor ingrese ultimo?&lt;br /&gt;select current_value from sys.sequences where name = 'NuevaSec'&lt;br /&gt;&lt;br /&gt;-- Esto me permite pasarle el valor a otra rutina que tenga que insertar en base a lo ingresado&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;-- La forma de realizar esto mismo en ORACLE hubiera sido:&lt;br /&gt;/* PRUEBA ORACLE */&lt;br /&gt;CREATE TABLE PruebaSecuencia(&lt;br /&gt;id    INT PRIMARY KEY,&lt;br /&gt;dato1 VARCHAR2(100)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;CREATE SEQUENCE NuevaSec&lt;br /&gt;   START WITH 1&lt;br /&gt;   INCREMENT BY 1&lt;br /&gt;   MINVALUE 1&lt;br /&gt;   MAXVALUE 999999&lt;br /&gt;   CACHE 20;&lt;br /&gt;&lt;br /&gt;-- Obtengo unos valores de ejemplo&lt;br /&gt;SELECT NuevaSec.NEXTVAL FROM DUAL&lt;br /&gt;&lt;br /&gt;-- Ejemplo de como la usaria&lt;br /&gt;INSERT INTO PruebaSecuencia&lt;br /&gt;select NuevaSec.NEXTVAL as nro,  'Valor1' as dato1 FROM DUAL&lt;br /&gt;&lt;br /&gt;-- O tambien...&lt;br /&gt;INSERT INTO PruebaSecuencia (id, dato1)&lt;br /&gt;VALUES (NuevaSec.NEXTVAL,  'Valor1')&lt;br /&gt;&lt;br /&gt;-- Que valor ingrese ultimo?&lt;br /&gt;select NuevaSec.CURRVAL FROM DUAL&lt;br /&gt;&lt;br /&gt;/* FIN PRUEBA ORACLE */&lt;br /&gt;&lt;br /&gt;Comparando ambas formas creo que por suerte mantuvieron una sintaxis muy similar en lo que corresponde a la creación del objeto, y como oracle no tiene su hermoso CREATE OR REPLACE para las secuencias entonces es totalmente consistente. En lo que respecta a su uso diario, me parece mucho mas comoda y agradable la sintaxis de Oracle, principalmente la forma de ver el valor actual que es algo que no entiendo como no incorporaron. Por otra parte en Oracle es muy incomodo reiniciar una secuencia (es necesario restarle el valor actual) , mientras que SQL ha simplificado esta tarea para evitarnos dolores de cabeza.&lt;br /&gt;&lt;br /&gt;Volviendo al SQL Server, realice un stress test con ambas tablas, una con identity y otra sin, utilizando las siguientes instrucciones&lt;br /&gt;-- test1&lt;br /&gt;INSERT INTO PruebaSecuencia (dato1)&lt;br /&gt;VALUES ('Valor1')&lt;br /&gt;GO 50000&lt;br /&gt;&lt;br /&gt;-- test2&lt;br /&gt;INSERT INTO PruebaSecuencia (id, dato1)&lt;br /&gt;VALUES (next value for dbo.NuevaSec,  'Valor1')&lt;br /&gt;GO 50000&lt;br /&gt;&lt;br /&gt;Los resultados fueron parejos tardando un poco menos el ejemplo con la secuencia pero no de forma significativa. Es importante notar que la prueba no la realicé en un gran servidor sino en una pc virtual, y según varios test esta diferencia suele ser mayor.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-5573320110282217394?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/5573320110282217394/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/01/sql-server-denali-sequence.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/5573320110282217394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/5573320110282217394'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/01/sql-server-denali-sequence.html' title='SQL Server Denali - Sequence'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-4730036309360627263</id><published>2011-01-03T08:32:00.001-03:00</published><updated>2011-01-03T08:39:53.426-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simulacion'/><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='stress test'/><category scheme='http://www.blogger.com/atom/ns#' term='RML'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='test'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='microsoft'/><title type='text'>RML para SQL 2008 - Parte 1</title><content type='html'>&lt;span style="color:#000099;"&gt;&lt;b&gt;A quien no le ha pasado de tener un sistema de base de datos, hacer unos cambios y no estar seguro si dichos cambios realmente mejoran la performance del proceso que se deseaba atacar? Este problema es muy común y por suerte contamos con unas series de herramientas que nos permiten solucionarlo. Este pack se llama RML y consta de varias herramientas, comentaré las mas importantes a mi parecer:&lt;br /&gt;ReadTrace, OStress, y ORCA.&lt;br /&gt;El ReadTrace nos permite hacer un análisis te las trazas de SQL y pasarlas a lo que se llaman archivos RML. Estos archivos a diferencia de la traza, se encuentran organizados por proceso, de esta forma se hace posible el simulacro.&lt;br /&gt;El OStress toma los archivos RML y los lanza al SQL simulando el comportamiento original, pudiendo configurarle si lo debe lanzar una sola vez o muchas, cada que intervalo, y muchas cosas mas.&lt;br /&gt;&lt;br /&gt;En esté primer artículo les dejo un overview de las pruebas realizadas.&lt;br /&gt;Las  herramientas son muy configurables y de un uso muy simple e intuitivo, y  al ser por linea de comando es facil de documentar los pasos a seguir.&lt;br /&gt;El readtrace viene con 3 archivos de ejemplo para una carga full, media o  liviana. La herramienta esta pensada para hacer reportes y para  trabajar con el Ostress, pero la verdad es que ninguno de estos tres  archivos de configuración es adecuado para el OS. El archivo full  consume muchisimo espacio, y el mediano no posee varios eventos que son  requeridos por el OS.&lt;br /&gt;El Ostress es un poco caprichoso con los eventos que requiere y las  columnas que se deben haber capturado. Algunas (a mi ver) están de mas  pero bue... sus mensajes no son del todo intuitivos visto que algunas  veces les va a decir "falta tal evento y tal otro" y en realidad falta  uno solo de los dos, pero se debe a que usa el mismo mensaje para  determinado grupo de eventos (ejemplo los started y completed, si falta  uno de los dos le va a decir que faltan los dos).&lt;br /&gt;Me armé una traza personalizada que tiene menos eventos que la full pero  los suficientes para que funcione el OStress, intentando minimizar las  columnas tambien (hay algunos warnings que me da pero alcanza para que  ejecute). Probé en un sistema con carga moderada y tardó un varias horas  en llegar al giga de traza, pero en sistemas con mucho movimiento en  menos de una hora ya rozaba el giga... Es una herramienta que hay que  tener cuidado como se la usa visto la gran demanda de recursos  (principalmente disco, compare los contadores y no hubo diferencias  significativas en la performance del sistema al realizar la traza) así  que me parece que lo adecuado es definir una franja horaria crítica o  modelo y utilizarla sobre dicha franja. Claramente no es una traza para  dejar corriendo durante toda la jornada.&lt;br /&gt;&lt;br /&gt;Pro: Es muy facil una vez capturado hacer un simulacro para poder  comparar la performance de un sistema antes y despues de hacer un cambio&lt;br /&gt;&lt;br /&gt;Contra:  Pese a poder configurar el paralelismo y los delay entre conexion, se  dificulta hacer simulaciones de una ventana de tiempo prolongada o hacer  la captura sin saber cuando será el momento crítico.&lt;br /&gt;&lt;br /&gt;Les dejo el link para bajarlo: &lt;a href="http://support.microsoft.com/kb/944837" target="_blank"&gt;http://support.microsoft.com/&lt;wbr&gt;kb/944837&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-4730036309360627263?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/4730036309360627263/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2011/01/rml-para-sql-2008-parte-1.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4730036309360627263'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4730036309360627263'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2011/01/rml-para-sql-2008-parte-1.html' title='RML para SQL 2008 - Parte 1'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-1971772426891862338</id><published>2010-11-12T11:33:00.000-03:00</published><updated>2010-11-16T16:51:16.179-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Analisys Services'/><category scheme='http://www.blogger.com/atom/ns#' term='$system.discover'/><category scheme='http://www.blogger.com/atom/ns#' term='sp_who'/><title type='text'>Controlando el AS</title><content type='html'>&lt;span style=";font-family:&amp;quot;;font-size:10pt;"  lang="EN-US" &gt;&lt;/span&gt;Miles de veces ejecutamos el bendito sp_who o sp_who2 entre otros, pero hablando con varias personas me encontré que desconocían como hacer lo mismo en Analisys Services.&lt;br /&gt;Si queremos hacer un monitoreo del AS contamos con tablas parecidas a las DMV del SQL.&lt;br /&gt;Para acceder a estas debemos conectarnos y generar una nueva consulta MDX, una vez ahí podemos escribir:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;select * from $system.discover_commands&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Y esto nos retorna la información equivalente al sp_who. Desde ahí podemos obtener el inputbuffer de cada comando que se encuentra en ejecución.&lt;br /&gt;Esta es la que mas utilizo pero no es la única.&lt;br /&gt;Para saber las conexiones existentes podemos utilizar:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;select * from $system.discover_connections&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Luego para analisis mas profundos contamos con otras como:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;select * from $system.discover_memoryusage&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;select * from $system.discover_object_memory_usage&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;select * from $system.discover_object_activity where object_reads &gt; 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;select * from $system.discover_partition_stat&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Podemos obtener un listado completo de las tablas del sistema con la sentencia&lt;br /&gt;&lt;span style="font-style: italic;"&gt;SELECT TABLE_NAME&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;  FROM $system.dbschema_tables&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt; WHERE TABLE_SCHEMA = '$SYSTEM'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt; ORDER BY table_name"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ahí podremos ver que se encuentran divididas en 4 categorias:&lt;br /&gt;DBSCHEMA_: Brinda información de la base&lt;br /&gt;DISCOVER_: Brinda información para administración&lt;br /&gt;DMSCHEMA_: Brinda información de datamining&lt;br /&gt;MDSCHEMA_: Brinda información de la estructura de los cubos&lt;br /&gt;&lt;br /&gt;En lo personal el que mas utilizo es el "discover", pero depende la tarea de cada uno esto puede variar.&lt;br /&gt;&lt;br /&gt;Saludos!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-1971772426891862338?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/1971772426891862338/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2010/11/controlando-el-as.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/1971772426891862338'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/1971772426891862338'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2010/11/controlando-el-as.html' title='Controlando el AS'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-6117992366017077655</id><published>2010-10-05T17:49:00.000-03:00</published><updated>2010-10-05T17:57:47.455-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='sp_cdc_disable_db'/><category scheme='http://www.blogger.com/atom/ns#' term='CDC'/><title type='text'>Socorro! no puedo frenar del CDC!!!</title><content type='html'>El CDC de SQL 2008 es en muchos aspectos una bendición, pero en algunos casos se puede volver una pesadilla si lo deseamos apagar. Una catarata de errores nos pueden ocurrir al intentar desactivar el CDC de una base o de una tabla, principalmente si no dejamos todo intacto como cuando lo creamos (ejemplo renombramos la tabla que tenia CDC).&lt;br /&gt;En este caso vamos a ver que si borramos la tabla pasamos a estar peor, porque ahora no solo que no nos deja desactivar el CDC de la base sino que aparecerán algunos errores, así que lo que debemos hacer es erradicar todo rastro.&lt;br /&gt;Primero debemos eliminar "dbo.systranschemas" y luego todas las referencias en el schema CDC.&lt;br /&gt;Con una consulta nos alcanza para encontrarlas:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;select * from sys.objects where schema_id=schema_id('cdc')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Esto nos devolvera cuales son las tablas, procedures y functions que se crearon. Debemos eliminar todos estos, con especial cuidado en las funciones que algunas tienen nombres raros como "fn_cdc_get_net_changes_ ..." y si no la ponen entre corchetes no se podrán eliminar.&lt;br /&gt;Una vez borradas todas estas tablas ejecutamos el comando:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;EXECUTE sys.sp_cdc_disable_db&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;y dejamos que el SQL se encargue del resto. Les recuerdo que esto es un último recurso, no deben hacerlo salvo que sea extremadamente necesario, nunca es recomentable borrar la información propia del SQL.&lt;br /&gt;Saludos!&lt;br /&gt;Andrés&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-6117992366017077655?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/6117992366017077655/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2010/10/socorro-no-puedo-frenar-del-cdc.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/6117992366017077655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/6117992366017077655'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2010/10/socorro-no-puedo-frenar-del-cdc.html' title='Socorro! no puedo frenar del CDC!!!'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-2084797293822792645</id><published>2010-09-16T13:25:00.000-03:00</published><updated>2010-09-16T13:44:08.371-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grant'/><category scheme='http://www.blogger.com/atom/ns#' term='roles'/><category scheme='http://www.blogger.com/atom/ns#' term='execute'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>Role de ejecución para todos los stored procedures</title><content type='html'>Una situación bastante común es querer que un usuario (o grupo de usuarios) tenga permiso de ejecución para todos los stored procedures de una base. El SQL Server nos brinda los roles db_datareader, db_datawriter u otros, pero ninguno da solamente esos permisos. Para poder hacer esto con roles es necesario asignarlo al role db_owner, lo cual da muchos mas permisos de los deseados.&lt;br /&gt;La única forma es dar los permisos de cada stored de forma individual, lo cual si tenemos muchos puede ser realmente molesto.&lt;br /&gt;La solución que planteo es hacer un grupo al cual llamé db_executeall. Armé un script que recorre todas las bases y en todas crea dicho role.&lt;br /&gt;El segundo paso es crear un cursor que recorra todos los stored procedures y asigne los permisos al role. El código estaría estructurado de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Cursor que recorre bases&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;         Crear role db_executeall si no existe&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;         Cursor que recorre procedures&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;         begin&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;                  Asignar permiso de ejecución al role&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;         end&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Esto nos dejaría en cada base un role nuevo que tiene todos los permisos de ejecución así solamente debemos asignarlo ahí al usuario. Una idea extra es agregar este script en un job diario, o por hora, para asegurarnos que nuestro role siempre esté actualizado con todos los permisos.&lt;br /&gt;Si alguién necesita el código puede escribirme.&lt;br /&gt;Saludos!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-2084797293822792645?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/2084797293822792645/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2010/09/role-de-ejecucion-para-todos-los-stored.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2084797293822792645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2084797293822792645'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2010/09/role-de-ejecucion-para-todos-los-stored.html' title='Role de ejecución para todos los stored procedures'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-1805855022368209453</id><published>2010-09-07T10:35:00.001-03:00</published><updated>2010-09-07T10:55:39.310-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grant'/><category scheme='http://www.blogger.com/atom/ns#' term='roles'/><category scheme='http://www.blogger.com/atom/ns#' term='dm_exec_sessions'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>Defaul role como en Oracle</title><content type='html'>Una cosa que mucha gente que trabaja con SQL Server extraña de Oracle es lo conocidos como &lt;span style="font-style: italic;"&gt;Default Roles&lt;/span&gt;.&lt;br /&gt;¿En que consiste esto? Consiste en tener un conjunto de permisos al comenzar la sesion y en tiempo de ejecución poder acceder a otros permisos de forma explicita. Un ejemplo util sería darle a un usuario permisos de DATAREADER con la opción de ascender a DATAWRITER. De esta forma si la mayoria de sus tareas consisten en solo leer datos no podría modificar cosas por error salvo que explicitamente suba sus permisos.&lt;br /&gt;Para implementar esto haremos lo siguiente. Para empezar crearemos en la master (o en alguna base de DBA) una tabla que tenga la siguiente estructura:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;T_Permisos(Usuario SYSNAME, Role SYSNAME, Defualt TINYINT)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Con esta tabla indicaremos los roles que tiene permitidos un usuario. La primer columna sera el nombre del LOGIN, la segunda el role y la última si este role lo tiene desde el comienzo o lo debe explicitar.&lt;br /&gt;El segundo paso es generar un logon trigger. Este trigger lo que hará será leer la tabla con un filtro en el where de &lt;span style="font-style: italic;"&gt;Default=1 y Usuario=ORIGINAL_LOGIN()&lt;/span&gt; y hacer con SQL Dinamico una asignación de permisos a los roles indicados y quitandole cualquier otro que pudiera tener.&lt;br /&gt;Con esto ya tenemos garantizado que al momento de conectarse tendrá un subconjunto de permisos.&lt;br /&gt;El último paso es permitir la escalada de permisos, lo cual lo haremos mediante un stored procedure. El stored &lt;span style="font-style: italic;"&gt;GrantRoles(Role SYSNAME)&lt;/span&gt; deberán tener permiso de ejecución todos los miembros de public. Este stored lo que hará es un select para controlar si el usuario logueado tiene en la tabla registrado el rol que solicita, en caso negativo no se hace nada y en caso afirmativo se asigna de forma dinámica el role. Es importante que este stored utilice la sentencia EXECUTE AS SELF por ejemplo y se haya creado con un usuario administrador. La idea es que el no tenga los permisos pero el stored si, y con la lógica adecuada se los asigne.&lt;br /&gt;Una vez terminada su tarea, cuando se desconecte mantendrá los permisos, pero al establecer una nueva conexion los perderá.&lt;br /&gt;Es interesante el tema de conexiones simultaneas, ahí se pueden analizar varias variantes como controlar en la &lt;span style="font-style: italic;"&gt;sys.dm_exec_sessions&lt;/span&gt; para ver de solo sacar los permisos si no hay otra conexion viva del mismo usuario.&lt;br /&gt;Saludos!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-1805855022368209453?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/1805855022368209453/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2010/09/defaul-role-como-en-oracle.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/1805855022368209453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/1805855022368209453'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2010/09/defaul-role-como-en-oracle.html' title='Defaul role como en Oracle'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-562589839866330523</id><published>2010-08-26T09:42:00.000-03:00</published><updated>2010-08-26T10:06:19.183-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='restore'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><title type='text'>Restore</title><content type='html'>Este artículo es corto pero muchas veces me lo preguntaron y yo mismo lo he necesitado asi que me parece un buen dato para tener siempre a mano. Cuantas veces uno tiene que hacer un restore de una base de varios gigas y no tiene idea de cuanto va a tardar, y del otro lado del teléfono tenemos al usuario reclamando que quiere su base online hace una hora (aunque el pedido se haya realizado hace 15 minutos, siempre es así el usuario). Para esto podemos utilizar una vista del sistema, DM_EXEC_REQUESTS (http://msdn.microsoft.com/es-es/library/ms177648.aspx). Una consulta sencilla que me permitirá saber el tiempo que resta para un restore es la siguiente:&lt;br /&gt;&lt;br /&gt;SELECT CONVERT(NVARCHAR(3), CAST(percent_complete AS INTEGER)) + '%' Porcentaje&lt;br /&gt;   , r.estimated_completion_time/(1000*60) MinutosRestantes&lt;br /&gt;FROM SYS.DM_EXEC_REQUESTS r&lt;br /&gt;WHERE percent_complete &gt; 0&lt;br /&gt;&lt;br /&gt;Esta consulta nso dirá el tiempo esperado para finalizar el restore pero tiene un problema, en caso de estar realizando varios restore al mismo tiempo no nos indica que a que base corresponde cada tiempo estimado. Esta información la podemos enriquecer haciendo un join con la información obtenida en el SP_WHO2 y así tener una consulta mucho mas completa que nos muestre también cual es la base sobre la cual operamos.&lt;br /&gt;&lt;br /&gt;CREATE TABLE #sp_who2&lt;br /&gt;   (SPID INT,&lt;br /&gt;   Status VARCHAR(1000) NULL,&lt;br /&gt;   Login SYSNAME NULL,&lt;br /&gt;   HostName SYSNAME NULL,&lt;br /&gt;   BlkBy SYSNAME NULL,&lt;br /&gt;   DBName SYSNAME NULL,&lt;br /&gt;   Command VARCHAR(1000) NULL,&lt;br /&gt;   CPUTime INT NULL,&lt;br /&gt;   DiskIO INT NULL,&lt;br /&gt;   LastBatch VARCHAR(1000) NULL,&lt;br /&gt;   ProgramName VARCHAR(1000) NULL,&lt;br /&gt;   SPID2 INT,&lt;br /&gt;   REQUESTID INT)&lt;br /&gt;&lt;br /&gt;INSERT INTO #sp_who2&lt;br /&gt;EXEC sp_who2&lt;br /&gt;&lt;br /&gt;SELECT w.DBName&lt;br /&gt;   , CONVERT(NVARCHAR(3), CAST(percent_complete AS INTEGER)) + '%' Porcentaje&lt;br /&gt;   , r.estimated_completion_time/(1000*60) MinutosRestantes&lt;br /&gt;FROM #sp_who2 w, SYS.DM_EXEC_REQUESTS r&lt;br /&gt;WHERE r.SESSION_ID = w.SPID&lt;br /&gt;AND w.Command IN ('RESTORE DATABASE')&lt;br /&gt;AND r.percent_complete&gt;0&lt;br /&gt;AND w.DBName&lt;&gt;'master'&lt;br /&gt;ORDER BY 1&lt;br /&gt;&lt;br /&gt;DROP TABLE #sp_who2&lt;br /&gt;&lt;br /&gt;Saludos!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-562589839866330523?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/562589839866330523/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2010/08/restore.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/562589839866330523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/562589839866330523'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2010/08/restore.html' title='Restore'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-2031838291796885232</id><published>2010-08-13T10:56:00.000-03:00</published><updated>2010-08-13T11:16:23.943-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='policys'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='seguridad'/><category scheme='http://www.blogger.com/atom/ns#' term='logins'/><category scheme='http://www.blogger.com/atom/ns#' term='Auditoria'/><title type='text'>Todo sobre logins (parte 2)</title><content type='html'>Ya hablamos de como mantener bien nuestros logins, ahora lo que falta es controlar que todo funcione como queremos. La auditoria es una de las partes mas importantes a la hora de administrar la seguridad.&lt;br /&gt;Hay varias cosas que podemos auditar pero principalmente quisiera hacer foco en dos:&lt;br /&gt;1) Auditoria SQL&lt;br /&gt;2) Logon triggers&lt;br /&gt;&lt;br /&gt;En la auditoria podemos definir los eventos que queremos que se controlen. Esto en la versión 2008 se ha echo muy sencillo, con solo un par de clicks podemos hacerlo. Si en cambio nuestra base es SQL 2005 deberemos trabajar un poco mas y habilitar el service broker (ENABLE_BROKER) y tenemos varios eventos que esta bueno monitorear y loguear en una tabla:&lt;br /&gt;AUDIT_LOGIN_CHANGE_PROPERTY_EVENT&lt;br /&gt;AUDIT_LOGIN_FAILED&lt;br /&gt;AUDIT_ADD_LOGIN_TO_SERVER_ROLE_EVENT&lt;br /&gt;AUDIT_ADDLOGIN_EVENT&lt;br /&gt;&lt;br /&gt;Estos eventos nos permitiran monitorear si se han creado nuevos logins o se le asignaron permisos a los ya existentes. Seguro se estarán preguntando "y no voy a auditar si se borraron loggins?" el evento cuando se borra un login es "AUDIT_ADDLOGIN_EVENT" pero en el xml del evento el subclass es 2 en lugar de 1.&lt;br /&gt;&lt;br /&gt;Lo otro que podemos hacer interesante es definir logon tringgers y aquí podemos dejar volar nuestra imaginación. Entre las ideas que se pueden implementar estaría:&lt;br /&gt;- Definir que un login pueda conectarse solamente desde un host en particular&lt;br /&gt;- Definir que un login pueda tener N ocurrencias en el día o simultaneas&lt;br /&gt;- Guardar en una tabla los horarios de login del usuario&lt;br /&gt;- No permitir que dos usuarios se conecten de forma simultanea&lt;br /&gt;&lt;br /&gt;y esas son solo algunas ideas, cada uno puede adaptarlas según las necesidades de su empresa&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-2031838291796885232?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/2031838291796885232/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2010/08/todo-sobre-logins-parte-2.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2031838291796885232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2031838291796885232'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2010/08/todo-sobre-logins-parte-2.html' title='Todo sobre logins (parte 2)'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-3163059872831199842</id><published>2010-08-04T18:38:00.001-03:00</published><updated>2010-08-04T19:21:16.212-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='policys'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='certificate'/><category scheme='http://www.blogger.com/atom/ns#' term='seguridad'/><category scheme='http://www.blogger.com/atom/ns#' term='logins'/><category scheme='http://www.blogger.com/atom/ns#' term='certificado'/><title type='text'>Todo sobre logins (parte 1)</title><content type='html'>&lt;div style="text-align: justify;"&gt;Uno de los temas mas importantes en las bases de datos es la seguridad, y obviamente ésto viene de la mano de los logins.&lt;br /&gt;En este articulo intentaré transmitir lo que para mi son las buenas prácticas al respecto, tanto sea para administradores principiantes como no.&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;Seguridad integrada&lt;/span&gt;&lt;br /&gt;Para empezar recordemos que en SQL contamos con dos tipos de autentificación: integrada con windows o manejada por SQL. Aquí ya tenemos una de las primeras buenas prácticas, cuando sea posible es bueno definir los logins para utilizar seguridad integrada, esto permite que nuestra seguridad sea manejada de forma aislada. Nuestro segundo paso para asegurar la base sería que nuestros logins no sean usuarios de windows, sino usuarios de red, de forma deseable manejados desde AD. De esta forma si queremos denegar el acceso a un usuario de todas nuestras instancias, podemos hacerlo simplemente denegando el acceso desde AD. El tercer y último paso en esta linea de pensamiento es no definir al usuario de AD como login de nuestro SQL, sino definir un grupo de AD y en el SQL definir como login a dicho grupo. La administración de dar o quitar permisos ahora pasa simplemente a ser agregar o quitar una persona al grupo de AD.&lt;br /&gt;Este modelo es muy seguro y tiene varios puntos fuertes:&lt;br /&gt;1) Puedo dar o quitar permisos a un usuario en varias instancias SQL de forma inmediata.&lt;br /&gt;2) Si otra persona debe tener los mismos permisos, no requiere ningún esfuerzo. Nota: es común que varias personas cumplan el mismo rol y por ende tengan los mismos permisos.&lt;br /&gt;3) Es facil garantizar que todos los usuarios cumplan los mismos requisitos de seguridad de contraseñas (caducidad, complejidad, etc).&lt;br /&gt;Este a mi ver es el mejor que se puede plantear, pero como siempre hay detalles a tener en cuenta. Tal es el caso si tengo varias instancias SQL y un grupo con permisos sobre diferentes bases en estos. Supongamos que ingresa una nueva persona que debe tener todos los mismos permisos SALVO que no debe poder acceder a una tabla que el resto si. Una opción poco práctica sería definir un nuevo grupo y replicar todos los permisos, pero es dificil de mantener visto que si agrego un nuevo permiso debo recordar agregarlo en ambos grupos. Otra opción, a mi ver mucho mas práctica, sería definir en mi base no solo al grupo sino también al login particular, y a éste &lt;span style="font-weight: bold;"&gt;denegarle &lt;/span&gt;el permiso a dicha tabla. De esta forma heredará los permisos del grupo pero le será denegado el acceso a la tabla.&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;Seguridad SQL&lt;br /&gt;&lt;/span&gt;El esquema visto anteriormente es el ideal, pero es un echo que no siempre puedo adaptarme a éste modelo y a veces no hay mas remedio que utilizar seguridad SQL. En estos casos es una buena práctica que los logins deban cumplir con cierta complejidad de contraseña, así como también definir la caducidad. Recuerden tener esto en cuenta porque son dos clicks al dar de alta y nos dejará dormir mucho mas tranquilos. Pero es una tarea humana realizar esta alta en general, y como tal puede fallar. Por eso es importante corroborar que fehacientemente los logins cumplan con nuestros criterios de seguridad establecidos. En SQL 2008 podemos utilizar policys (http://msdn.microsoft.com/en-us/library/bb510667.aspx) que nos permiten hacer dos cosas en este contexto:&lt;br /&gt;- Tener un listado periodico de todos los logins que no cumplan con determinados criterios&lt;br /&gt;- Prohibir la creación de un login si no cumple los criterios&lt;br /&gt;Esto es muy comodo porque nos evita los errores humanos, aunque en algunos contextos puede ser demasiado restrictivo.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Certificados&lt;br /&gt;&lt;/span&gt;Por último una buena forma de tener acotados los permisos que les damos a los usuarios es ponerles una fecha de caducidad si sabemos que la tarea que van a realizar es solamente por un tiempo acotado. En estos casos podemos definir un certificado en la master que tenga un &lt;span style="font-style: italic;"&gt;expiration date &lt;/span&gt;y asociar el login a dicho certificado. De ésta forma una vez vencido el certificado el usuario no podrá loguearse al sistema.&lt;br /&gt;&lt;br /&gt;Saludos!&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-3163059872831199842?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/3163059872831199842/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2010/08/todo-sobre-logins-parte-1.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/3163059872831199842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/3163059872831199842'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2010/08/todo-sobre-logins-parte-1.html' title='Todo sobre logins (parte 1)'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-2588976984531469525</id><published>2010-07-26T14:03:00.000-03:00</published><updated>2010-07-27T12:10:01.664-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='colgado'/><category scheme='http://www.blogger.com/atom/ns#' term='xp_sqlagent_enum_jobs'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='jobs'/><category scheme='http://www.blogger.com/atom/ns#' term='sysjobhistory'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>Jobs Matusalén (Procesos colgados)</title><content type='html'>&lt;div style="text-align: justify;"&gt;Un tema interesante que se me presentó hace unos meses fue encontrar un job que llevaba corriendo una semana y como ningún usuario reclamó nada pasó desapercibido. Ahí fue que decidí tomar una acción preventiva para estos casos. Cuando configuramos nuestras tareas de mantenimiento o control lo mas normal es que utilicemos jobs. Los jobs si ejecutan de forma correcta podemos configurar que nos mande un mail, o lo que es mas habitual, podemos configurar que nos envíe mail cuando falla (a nosotros o cualquier operador del SQL). El problema es que pasa cuando el proceso queda colgado, por lo tanto no recibimos ni mail de ok, ni mensaje de error y es muy probable que no nos demos cuenta.&lt;br /&gt;Con la intención de alertar esta situación generé un job que se ejecute cada 15 minutos y controle todos los jobs que se encuentran vivos hace cuanto tiempo lo están. La forma de implementarlo fue hacer un procedimiento que para cada job que se encuentra corriendo hace mucho genere una excepción, y en caso contrario no haga nada, de esta forma puedo en mi job de control programar la alerta de mail y que la reciban todos los administradores.&lt;br /&gt;Para obtener los jobs vivos utilicé "xp_sqlagent_enum_jobs", que es medio tramposa así que tengan en cuenta que deben pasarle como primer parámetro 0 y el segundo parametro no interesa pero debe ser algún texto (no importa cual). Esto se debe a que el primer parámetro hace que se ignore el segundo pero igual lo exije.&lt;br /&gt;El resultado de esa consulta nos retorna jobs_id así que deberemos cruzarla con "msdb.dbo.sysjobs" y "msdb.dbo.sysjobactivity" para transoformala en algo humanamente entendible.&lt;br /&gt;La pregunta interesante es la siguiente: cuando consideramos que un job está tardando? La mejor solución asumí que es basarnos en el historial. Por suerte contamos con la tabla msdb.dbo.sysjobhistory. Un error común podría ser querer promediar el tiempo que ahí se encuentra y generar una alerta cada vez que el job tarda mas que ese promedio. ERROR. ¿por que es esto incorrecto? porque si un job a veces tarda 58min y a veces 1hs 2min, no suena razonable que pasada una hora alerte que ocurrió un error, sino la mitad de las veces recibiría el mail, y bien sabemos que un mail que llega seguido termina siendo ignorado con las posibles consecuencías que esto trae. Por eso es necesario basarnos en la matemática y averiguar el desvio estandar de nuestra muestra, y calcular cual es el tiempo esperado tal que un 90% de los casos alcanza a terminar, asumiendo que el tiempo esperado suele ser de la forma valor esperado + error, teniendo el error una distrinución Gaussiana.&lt;br /&gt;En la impementación me pareció bueno meter esto en otra tabla y actualizarla períodicamente con otro job que se encargue de calcular los tiempos (una vez por semana por ejemplo) y el job de control consulte estos tiempos. Una de las partes mas molestas de implementar esto es que la job_history no tiene un formato muy amigable para los tiempos, les recomiendo que lo calculen con una función y la tengan a mano porque sirve para muchas cosas y es muy molesta de rehacer.&lt;br /&gt;Espero haber sido claro, si alguién desea el código puede enviarme un mensaje privado.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-2588976984531469525?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/2588976984531469525/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2010/07/jobs-matusalen-procesos-colgados.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2588976984531469525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/2588976984531469525'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2010/07/jobs-matusalen-procesos-colgados.html' title='Jobs Matusalén (Procesos colgados)'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3525590579238673765.post-4988227296775977494</id><published>2010-07-22T09:02:00.000-03:00</published><updated>2010-07-22T12:49:37.247-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AD'/><category scheme='http://www.blogger.com/atom/ns#' term='LDAP'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='PowerShell'/><category scheme='http://www.blogger.com/atom/ns#' term='MERGE'/><category scheme='http://www.blogger.com/atom/ns#' term='ChangeDataCapture'/><category scheme='http://www.blogger.com/atom/ns#' term='Auditoria'/><category scheme='http://www.blogger.com/atom/ns#' term='CDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Active Directory'/><title type='text'>Auditoria de Active Directory con SQL 2008</title><content type='html'>&lt;div style="text-align: justify;"&gt;Hace poco se me presentó un problema que luego de buscarlo por varias páginas sin resultados buenos decidí implementar una solución desde cero. El equipo de seguridad informática necesitaba un producto para llevar una auditoría de cambios de AD y controlar que usuarios han sido modificados o se les han asignado nuevos permisos.&lt;br /&gt;El primero intento (y el que abunda en la red) de llevar esto a &lt;span style="font-weight: bold;"&gt;SQL 2008&lt;/span&gt; tiene sus problemas. Si la empresa está compuesta por pocos usuarios no hay inconveniente, se hace un open query de SQL a AD utilizando LDAP y se controla de a un usuario por vez si cambio algo. El problema es que el SQL no permite traer TODOS los usuarios si estos son muchos, así que hay que buscar otra solución.&lt;br /&gt;La respuesta que plantee consiste de combinar varias tecnologías. Para poder hacer la auditoría primero cargaremos todos los datos de AD en un conjunto de tablas intermedias en SQL. La forma de hacer esto será mediante &lt;span style="font-weight: bold;"&gt;Power Shell&lt;/span&gt;. El Power Shell puede conectarse sin problemas al AD y cada resultado obtenido en el iterador lo volcaremos en la tabla SQL. Hay que tener cuidado con la normalización de las tablas visto que algunos de los campos de AD son multivaluados y debemos guardarlos como tablas independientes (el ejemplo mas importante es Member o MemberOf).&lt;br /&gt;Una vez cargados los datos en las tablas intermedia SQL lo volcamos en la tabla final. Este paso intermedio lo hacemos para poder saber que cosas han cambiado sin tener que volcar una gran lógica en el Power Shell. En lugar de hacer complejas consultas actualizaremos la tabla final (&lt;span style="font-style: italic;"&gt;Ej. T_AD_USERS&lt;/span&gt;) con la tabla intermedia (&lt;span style="font-style: italic;"&gt;Ej. T_AD_USERS_TEMP&lt;/span&gt;). La forma mas rápida podría ser hacer un truncate y volcar todo el contenido, pero cambiaremos solamente lo que sea realmente necesario y ya veremos por que. El SQL 2008 nos brinda para esto el comando &lt;span style="font-weight: bold;"&gt;MERGE &lt;/span&gt;(http://technet.microsoft.com/en-us/library/bb510625.aspx) que nos permite de forma rápida incorporar los registros faltantes, modificar los existentes y borrar los dados de baja.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_d9XJskvVskk/TEg-fPAqYnI/AAAAAAAAAfA/HnlNXPKZbWE/s1600/modeload.JPG"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 78px;" src="http://1.bp.blogspot.com/_d9XJskvVskk/TEg-fPAqYnI/AAAAAAAAAfA/HnlNXPKZbWE/s320/modeload.JPG" alt="" id="BLOGGER_PHOTO_ID_5496712051531866738" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Con esto ya tenemos una tabla con la información de AD actualizada cuando querramos (podría ser un job que ejecute cada una hora). Lo que nos falta es llevar la auditoría en si misma, y para eso activaremos el &lt;span style="font-weight: bold;"&gt;CDC (change dat&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;a capture)&lt;/span&gt; sobre la tabla en cuestión. Como nos encargamos de no borrar todo cada vez sino solamente actualizar según los cambios, el CDC llevará un registro de todos los usuarios que hayan sido actualizados. La única salvedad es que nuestra auditoría así como está planteada mostrará las altas, las bajas, y por cada vez que se ejecute el job todos los campos figurarán como actualizado, así que debemos hacer dos MERGE, uno de altas y bajas (WHEN NOT MATCHED BY TARGET y WHEN NOT MATCHED BY SOURCE) y otro para actualizar que contenga en el join que coincida la PK y alguno de los campos haya cambiado.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Con esto ya tendrémos una tabla de auditoría de AD (&lt;span style="font-style: italic;"&gt;cdc.dbo_T_AD_USERS_CT&lt;/span&gt;), ahora lo único que nos falta es darle a la gente de seguridad informática una interfaz amigable para acceder a ésta. Recordemos que el CDC trabaja con marcas de agua y esto no es muy amigable para la gente de otras áreas, así que lo que recomiendo como mínimo es hacer un stored procedure que tome como parametros dos DATETIME (desde, hasta) y retorne todas las entradas del CDC que se encuentren en dicho período pero cambiando la marca de agua por su fecha correspondiente y mostrar esto desde reporting services u otra interfaz amigable.&lt;br /&gt;Si alguien quiere el código de todo esto implementado no dude en ponerse en contacto conmigo.&lt;br /&gt;Saludos!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3525590579238673765-4988227296775977494?l=aiellodba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aiellodba.blogspot.com/feeds/4988227296775977494/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://aiellodba.blogspot.com/2010/07/auditoria-de-active-directory-con-sql.html#comment-form' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4988227296775977494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3525590579238673765/posts/default/4988227296775977494'/><link rel='alternate' type='text/html' href='http://aiellodba.blogspot.com/2010/07/auditoria-de-active-directory-con-sql.html' title='Auditoria de Active Directory con SQL 2008'/><author><name>Andres Aiello</name><uri>http://www.blogger.com/profile/08215199243421676040</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-wytZO1Kdv18/TiWrCKZaZQI/AAAAAAAAAjo/rnpQ9nOBtrg/s220/aaiello.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_d9XJskvVskk/TEg-fPAqYnI/AAAAAAAAAfA/HnlNXPKZbWE/s72-c/modeload.JPG' height='72' width='72'/><thr:total>3</thr:total></entry></feed>
