Video con conceptos básicos

Posted by Miguel Egea | Posted in Basicos Newsgroup, Relacional | Posted on 18-05-2013

0

De mi charla en Gusenet hace un mes.. espero que os guste.
https://drive.google.com/folderview?id=0B4jb4DhnTRGRRm1NZzd1aUtNcmM&usp=sharing

 

Trigger Sencillo

Posted by Miguel Egea | Posted in Relacional | Posted on 07-05-2013

0

Hace unos dias me mandaban este correo.

 

Hago una consulta a esta tabla

select * from Saldos

 

La cual me arroja los siguientes resultados

T015_idComercio T015_saldo
201735 0.00
201735 0.00
201735 0.00
201735 0.00
201758 0.00
201758 0.00
201758 0.00

 

Cree una tabla con la siguiente estructura

create table Activaciones(Cid int, BloqueoB bit, BloqueoV bit, Bloqueo bit)

Realizar un Trigger que se ejecute cada vez que se inserte un nuevo T015_idComercio

De la tabla Saldos , que ese T015_idComercio se inserte mediante el Trigger en la tabla Activaciones del campo Cid

Y aquí está la solución.

create table saldos (T015_idComercio int, saldo numeric(18,2))
go
create table Activaciones(Cid int, BloqueoB bit, BloqueoV bit, Bloqueo bit)
go
create trigger tr_saldos on saldos for insert,update 
as begin
 merge into Activaciones as target
   using (select distinct t015_idcomercio from inserted) as source on target.cid=source.t015_idcomercio
   when not matched then
    insert values (source.t015_idcomercio,0,0,0);
 
end
go
 
insert into saldos values (201735	,0.00),
(201735	,0.00),
(201735	,0.00),
(201735	,0.00),
(201758	,0.00),
(201758	,0.00),
(201758	,0.00)
go
select * from saldos
select * from Activaciones

Recorriendo árboles

Posted by admin | Posted in Relacional | Posted on 02-05-2013

0

Ayer un amigo me preguntaba por como recorrer un árbol en orden, particularmente cuando puedes hacer movimientos de hojas completas, y le mandé este ejemplo

create table arbol (ID INT IDENTITY NOT NULL primary key,
NAME NVARCHAR(50) NOT NULl,
PARENT_ID INT NULL
);

Creada la tabla le insertamos algunos valores a modo de ejemplo

insert into arbol values ('nodo padre',null),('nodo hijo A',1),('nodo hijo B',1),('nodo hijo A-A',2),('nodo hijo A-B',2),('nodo hijo A-C',2);

Y ahora la función Recursiva que lo recorre. La primera de las partes indica la condición de entrada (where parent_id is null), tras el union all hacemos referencia a nosotros mismos entrando en modo recursivo, hasta que se acaben los elementos, es decir hasta llegar a las hojas.
El único truco está que que añadimos la ruta que vamos recorrriendo, concatenando el identificador en cada uno de esos pasos recursivos

with ObtenerArbol(ID,NAME,PARENT_ID, ruta)   as
(select folders.ID,folders.NAME,folders.PARENT_ID, cast(cast(id as varchar)+ '->' as varchar(5000)) ruta  From arbol folders 
 where PARENT_ID is null   
 union ALL 
   select f.ID,f.NAME,f.PARENT_ID,  cast(ruta + cast(f.id as varchar) + '->' as varchar(5000)) from arbol f   
 inner join ObtenerArbol mc on f.PARENT_ID=mc.ID )
 select * from ObtenerArbol ORDER BY ruta

Ahora movemos un nodo de posición

update arbol set PARENT_ID=3 where id=2

Y volvemos a sacar el árbol

SSMS para manejar Extended events

Posted by Miguel Egea | Posted in Noticias, Relacional | Posted on 04-07-2012

0

Esta mañana navegando para contestar una pregunta en el foro de noticias de microsoft, me encontré con esta explicación , y me parece muy interesante. Se trata de una explicción escrita por el MVP Devon Musgrave en donde cuenta como desde SSMS se puede hacer algo parecido a profiler pero con eventos extendidos, este es el link y si os gusta el tema en este otro artículo de mi compañero Enrique Catalá encontrareis información muy interesante

Reindexar una base de datos Express por linea de comandos

Posted by Miguel Egea | Posted in Basicos Newsgroup, Relacional | Posted on 03-12-2011

0

graba el contenido del código T-SQL en un fichero que se llame reindexa.SQL  El código está sacado de los libros en pantalla de la ayuda del producto.

Una vez que tengas ese fichero (llamado en mi caso c:\reindexa.sql ejecuta desde la linea de comandos esta línea

c:\>sqlcmd -S localhost -E -d tubasededatos -i c:\reindex.sql

con esto se ejecutará el script que en principio debe reindexar toda tu base de datos. recuerda cambiar en la ejecutcion de arriba donde pone tubasededatos por el nombre de tu base de datos.

 

SET NOCOUNT ON;
DECLARE @objectid int;
DECLARE @indexid int;
DECLARE @partitioncount bigint;
DECLARE @schemaname nvarchar(130); 
DECLARE @objectname nvarchar(130); 
DECLARE @indexname nvarchar(130); 
DECLARE @partitionnum bigint;
DECLARE @partitions bigint;
DECLARE @frag float;
DECLARE @command nvarchar(4000); 
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function 
-- and convert object and index IDs to names.
SELECT
    object_id AS objectid,
    index_id AS indexid,
    partition_number AS partitionnum,
    avg_fragmentation_in_percent AS frag
INTO #work_to_do
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED')
WHERE avg_fragmentation_in_percent > 10.0 AND index_id > 0;
 
-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR FOR SELECT * FROM #work_to_do;
 
-- Open the cursor.
OPEN partitions;
 
-- Loop through the partitions.
WHILE (1=1)
    BEGIN;
        FETCH NEXT
           FROM partitions
           INTO @objectid, @indexid, @partitionnum, @frag;
        IF @@FETCH_STATUS < 0 BREAK;
        SELECT @objectname = QUOTENAME(o.name), @schemaname = QUOTENAME(s.name)
        FROM sys.objects AS o
        JOIN sys.schemas as s ON s.schema_id = o.schema_id
        WHERE o.object_id = @objectid;
        SELECT @indexname = QUOTENAME(name)
        FROM sys.indexes
        WHERE  object_id = @objectid AND index_id = @indexid;
        SELECT @partitioncount = count (*)
        FROM sys.partitions
        WHERE object_id = @objectid AND index_id = @indexid;
 
-- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
        IF @frag < 30.0
            SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE';
        IF @frag >= 30.0
            SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD';
        IF @partitioncount > 1
            SET @command = @command + N' PARTITION=' + CAST(@partitionnum AS nvarchar(10));
        EXEC (@command);
        PRINT N'Executed: ' + @command;
    END;
 
-- Close and deallocate the cursor.
CLOSE partitions;
DEALLOCATE partitions;
 
-- Drop the temporary table.
DROP TABLE #work_to_do;
print "reindexación completada"
GO

 

 

Luis Franco hablando de CROSS APPLY

Posted by Miguel Egea | Posted in Noticias, Relacional | Posted on 26-09-2011

0

Cross Apply y las funciones escalares, una comparativa con el uso de funciones y como cazar lo que están haciendo realmente. Adicionalmente a lo que dice Luis, las funciones escalares no solamente pueden degradar el rendimiento cuando esas funciones a su vez llaman a tablas (en ese caso la degradacion es espectacular), sino que también lo es cuando sin ese acceso se usan como herramientas matemáticas por ejemplo (una multiplicación, operaciones con fechas o cosas así )

El motivo es que se ejecutan para cada fila, sin posibilidad de optimización y acaban sobrecargando la cpu de la máquina, y dando un mal rendimiento. Así pues.. usad la forma que dice Luis.

Por cierto, si alguno me visteis dar una charla en el developer day de ¿2009? con Fernando G. Guerrero , esto de lo que habla Luis, fué la demo que hice :) .

SQL Denali. Objeto Sequence

Posted by Miguel Egea | Posted in Relacional | Posted on 18-09-2011

2

En los grupos de noticias en castellano de SQL Server un amigo preguntaba sobre como hacer un autoincremental sobre un campo texto. lo cierto es que los campos texto no tienen autoincrementales, pero su objetivo era poder generar números muchísimo más grandes que los 18 mil millones de millones que tiene un bigint. La verdad es que todos le dijimos que si tienes en una tabla por estrecha que sea, más de 18 mil millones de millones de filas, el menor de tus problemas es el autoincremental,.. pero en cualquier caso si que me dió una idea para hablar sobre las secuencias.

Las secuencias son un objeto nuevo en SQL Server Denali, que van a ayudar a que podamos tener “más de un autonumérico” por cada una de las tablas. Este artículo será una versión corta de como se pueden solucionar este tipo de problemas. De momento, lo que se me ocurrió fué lo siguiente:

1.- Crear dos campos bigint, que sean la clave primaria de la tabla

2.- Crear un campo calculado de tipo texto que sea la concatenación de ceros y el valor del campo 1 en los 18 dígitos menos significativos y la misma operación para el campo 2

3.- Comprobar cuando el campo menos significativo supera el rango de los bigint, es decir, cuando vuelve a cero.

4.- En ese caso incrementar en uno el campo más significativo.

Creo que con esta técnica el campo calculado responde a la pregunta de nuestro amigo, aunque realmente no tenga más que una utilidad educativa y no práctica (en mi humilde opinión)

Como quiera que  un trozo de código vale más que mil palabras, aquí está la solución que propongo.

 

create sequence SecuenciaA as bigint start with 1 increment by 1 no maxvalue cycle;
create sequence Secuenciab as bigint start with 0 increment by 1 no maxvalue;
go
create table t (id1 bigint not null ,id2 bigint not null, datotest varchar(10),
campotexto as right('000000000000000000'+ cast( id2 as varchar(19)),19)+
right('000000000000000000'+ cast( id1 as varchar(19)),19) , constraint pk_t primary key (id1,id2))
go
create procedure insertaent @datotest varchar(10)
as
begin
  declare @valor1 bigint
  declare @valor2 bigint
  select @valor1=NEXT VALUE FOR SecuenciaA;
  if @valor1=0 
    select @valor2=NEXT VALUE FOR secuenciaB;
  else
   select @valor2=cast(current_value as bigint) FROM sys.sequences where name='SecuenciaB';
  insert into dbo.t values (@valor1,@valor2,@datotest);
end;
go
exec insertaent 'hola'
go
SELECT * FROM DBO.t
go
drop procedure insertaent;
drop table t;
drop sequence secuenciaA;
drop sequence secuenciaB;

SQL DMO y sus utilidades

Posted by Miguel Egea | Posted in Relacional | Posted on 13-09-2011

0

Es muy común que para desarrolladores de base de datos, incluso los más instruidos, no necesiten nunca o casi nunca usar el sistema de automatización que proveen todos los productos de microsoft. Generalmente todas las herramientas (SQL Server Management Studio es un ejemplo), no son más que interfaces que usan esa funcionalidad, que por otra parte está disponible para cualquier desarrollador con un poquito de inquietud y una necesidad de emular esos comportamientos.

Lo que os dejo hoy son dos links, uno más general sobre como usar estas funcionalidades desde scripts de windows, y un segundo enlace que va orientado a aquellos desarrolladores que quieren usar estas funcionalidades desde dentro de TSQL, no es que sea una practica a hacer en todos los casos, pero es posible que nos saque de un apuro alguna vez y eso siempre se agradece. Así que si quereis podeis seguir este enlace . En el vereis como conseguir la generación de un script de una tabla (por ejemplo) desde TSQL.

 

Heaps (montones) y tablas con índices Clustered

Posted by Miguel Egea | Posted in Noticias, Relacional | Posted on 12-09-2011

0

A veces hay que leer no solo lo que la gente usa como buenas prácticas, sino también lo que se usa como malas prácticas. En este caso Luis nos cuenta algun caso que seguramente se habrá encontrado por ahí, y su analisis sobre la fragmentación de los heaps y como alguna gente intenta evitarla, sin demasiado éxito y consumiendo recursos.

Totalmente recomendable como lectura

Artículo de BI Corner, Mitos y leyendas, defragmentacion de heaps

Administrador multiserver con SQL Server Management Studio

Posted by Miguel Egea | Posted in Relacional | Posted on 25-08-2011

4

Hace uno dias, en los foros de noticias uno de los compañeros preguntaba por herramientas de administración multiservidor. Me explico, una herramienta que cuando ejecutes un script, no solo lo ejecute en un server, sino que se encargue de que tu comando (tanto si es de manipulación de datos -DML es decir insert,update…- , como si es de definición de datos -DDL, es decir create table, etc- se ejecute en un conjunto de servidores.
Me sorprendió ver como muy poca gente conocía que esta funcionalidad la tiene SQL Server Management Studio, es cierto que no es probablemente una funcionalidad para un gran porcentaje de usuarios, pasará desapercibido, no tendrá utilidad. Sin embargo veo algunos escenarios de mucha utilidad:
  • Para aquellos que administren siquiera dos servidores pueden beneficiarse de comprobaciones de fragmentación, de índices, de seguimiento de bloqueos, y de muchas tareas administrativas.
  • Para aquellos que mantengan bases de datos idénticas en distintos servers, y que quieran asegurarse que realmente son idénticas.
Seguro que hay otro montón de escenarios útiles, pero creo que con estos dos, el lector interesado sabrá de que estoy hablando, y si no esta en estos, el que lo necesite, seguramente sea capaz de inferir que esta funcionalidad puede ser útil, también para él.
Voy a hacer la demostración y la captura de pantallas con el SQL Server Management Studio de la CTP3 de Denali, pero esto ya funciona, desde versiones anteriores (desde SQL 2008).
Lo primero que haremos será, tras abrir nuestro SQL Server Management Studio, ir al menú de Ver, y ahí elegir servidores registrados, notad como hay una carpeta llamada Central Management Servers, como puede observarse en la siguiente figura. Disculpad aquellos que no utiliceis las versiones en inglés, entiendo que para un hispano hablante, quizá debiera usar esas versiones, pero por mi trabajo, me veo muy a menudo obligado a usarlo en inglés y prefiero no hacerme un lio con las traducciones. Mis disculpas al que le moleste.
Pulsando con el botón derecho sobre Central Management Servers nos aparecerá un  menú contextual con leyenda “Register Central Management Server”, este será el servidor que nos valga como nodo principal, por decirlo de una forma poco ortodoxa, pero bastante comprensible.  En el asistente nos permite especificar tanto una descripción como una forma de conectarse, en mi caso, lo haré con mi usuario Administrador y con seguridad integrada. Cabe destacar que para no almacenar contraseñas que además lo serían de usuarios con muchos privilegios, solamente está permitida la seguridad integrada, según se detalla en este artículo http://msdn.microsoft.com/en-us/library/bb934126(v=SQL.100).aspx Aquí simplemente hemos de conectarnos con los suficientes privilegios. (Son privilegios obviamente de administración de los servidores es decir, unos privilegios bastante elevados)
Tras comprobar que nos conectamos de forma adecuada, pulsaremos save, a partir de este momento hemos de añadir los servidores que serán administrados desde éste.  No es necesario añadirlo dentro de la subcarpeta Central Management Servers, es más podemos crear grupos de servidores que se comporten como tales. Por ejemplo, podemos crear un grupo Desarrollo, de forma que script aplicados a server de desarrollo se apliquen a tantos servidores de desarrollo como tengamos registrados.
Veamos un ejemplo de como hacerlo. Sobre “Local Server Groups” pulsamos botón derecho y “New SQL Server Group”, esto hace que creemos una carpeta común bajo la que ubicar servers. dentro de esa carpeta, botón derecho de nuevo y registraremos nuestros servers, como puede verse en la siguiente figura.
En el caso del ejemplo tenemos registrados dos servidores, en realidad son las instancias SQL 2008 R2 y SQL 2005 que tengo instaladas en mi equipo.
Si sobre el grupo Desarrollo, presionamos botón derecho new query, nos aparecerá una ventanita, en la que, podremos comprobar como la barra de estado, no es amarilla ni gris, sino de un color rosado, También nos dice cuantos servidores hay contectados. Cualquier query ejecutado ahí, se ejecutará en ambos servers. Ojo, con el tipo de queries que hacemos, puesto que pueden fallar. Suelo decir que cuando alguien ejecuta un SELECT * , Dios mata un gatito, es una broma que me gusta hacer y que en este caso cobra especial relevancia, en mi caso por ejemplo, si hago esto saldrá este mensaje.
.\SQK2K8R2(WIN-P3PS5OB2GSJ\Administrator): (15 row(s) affected)
.\SQL2K5(WIN-P3PS5OB2GSJ\Administrator): An error occurred while executing batch. Error message is: The result set could not be merged because the result schema did not match the schema from the first responding server.
.\SQL2K5(WIN-P3PS5OB2GSJ\Administrator): (8 row(s) affected)
Esto es básicamente porque lo que hace SQL Server Management Studio es ejecutar el mismo comando en ambos servers y unir el resultado como si de un UNION ALL se tratara. En mi caso, entre la versión SQL 2005 y la versión SQL 2008 R2, la tabla sys.sysdatabases tiene estructuras distintas, así pues.. no puede unir el resultado. Cambiaré ese * y así podré ver como si que funciona. La sentencia que ejecutaré y el resultado podeis verlo en la siguiente captura de pantalla. Notad como aparece una columna que yo no he solicitado ([Server Name]) que indica a que server pertenecen esos objetos.
Si os fijais ha aparecido esa columna que mencionabamos además de aparecer la barra de estado en color rosa.
Esta opción es una opción del propio SQL Server Management Studio,  tanto que mezcle los resultados ( lo que hablabamos antes y que tiene problemas con servidores con distintas versiones) tanto que añada el nombre del servidor o incluso el nombre de login. Si vamos al menú Tools (herramientas) a la opcion “Options” (Opciones), bajo Query Results, SQL Server veremos un apartado Multiserver Results  en el que controlar ese comportamiento. Obviamente podremos cambiarlo hasta que se adecúe lo mejor posible a nuestro propio entorno. Como puede verse en la siguiente figura.
Conclusion: SQL Server Management Studio, es una herramienta realmente potente, con un gran número de opciones y funcionalidades, algunas que permanecen ocultas para muchos, merece la pena bucear un poquito en su funcionamiento para realmente sacarle el máximo provecho.  En este caso, para la administración multi servidor.