T-SQL - Gráfica de los distintos tipos de Joins

Yo pienso que esta imagen nos da la respuesta clara y exacta de como funciona cada uno de los joins disponibles en T-S
( click en la imagen para agrandarla)

















Hugo Román Bernachea
Mail de contacto: SQLServer777@gmail.com

Microsoft Certified DBA
Microsoft Certified Trainer
Twitter: @bernachea

Read More...

XQuery - Obtener default namespace de un campo o variable XML

Después de dar unas cuantas vueltas, apremiado para resolver un store procedure que tenía que procesar un campo xml (usando sp_preparedocument y OpenXML) que podía tener distintos namespaces en distintos registros, es que me puse a buscar la forma de recuperar el namespace predeterminado de un xml y encontré que la forma es la siguiente.

Select CampoXML.value('namespace-uri(/*[1])','VARCHAR(100)')
u obviamente
Select @variableXML.value('namespace-uri(/*[1])','VARCHAR(100)')
Esto por ejemplo puede regresar:
urn:proyecto-version-numero-1.1
Otro ejemplo:
SELECT CampoXML.value('local-name(/*[1])', 'varchar(100)'), CampoXML.value('namespace-uri(/*[1])','VARCHAR(100)') from tabla
Donde tenemos que:
local-name devuelve el nombre del elemento raiz
y
namespace-uri devuelve el namespace predeterminado.

Hugo Román Bernachea
Mail de contacto: SQLServer777@gmail.com

Microsoft Certified DBA
Microsoft Certified Trainer
Twitter: @bernachea

Read More...

Traza predeterminada en SQL Server 2005

La traza predeterminada esalgo completamente nuevo que Microsoft implementó para auditar ciertos eventos en el sistema, de los cuales se pueden hacer reportes via Management Reports.

Para verificar que la traza predetermina (default trace) está ejecutándose, ejecute el siguiente query:

select * from sys.configurations where configuration_id = 1568

Si quiere chequear si hay trazas activas corriendo ejecute el siguiente script:

select * from ::fn_trace_getinfo(0)

También puede utilizar fn_trace_getinfo y sp_trace_create para realizar tareas adicionales relativas a trazas.

Si usted no quiere tener corriendo dichas trazas, las puede deshabilitar ejecutando:

sp_configure 'default trace enabled', 0

Debiera deshabilitarlas? Antes de deshabilitarlas por favor observe que eventos están siendo capturados por la traza predeterminada. Si usted abre la traza en el profiler podrá ver exactamente que cosa es capturada.

Aquí tenemos una lista de los eventos capturados por la traza predeterminada:

Database

* Data file auto grow
* Data file auto shrink
* Database mirroring status change
* Log file auto grow
* Log file auto shrink

Errors and Warnings

* Errorlog
* Hash warning
* Missing Column Statistics
* Missing Join Predicate
* Sort Warning

Full-Text

* FT Crawl Aborted
* FT Crawl Started
* FT Crawl Stopped


Objects

* Object Altered
* Object Created
* Object Deleted

Security Audit

* Audit Add DB user event
* Audit Add login to server role event
* Audit Add Member to DB role event
* Audit Add Role event
* Audit Add login event
* Audit Backup/Restore event
* Audit Change Database owner
* Audit DBCC event
* Audit Database Scope GDR event (Grant, Deny, Revoke)
* Audit Login Change Property event
* Audit Login Failed
* Audit Login GDR event
* Audit Schema Object GDR event
* Audit Schema Object Take Ownership
* Audit Server Starts and Stops

Server

* Server Memory Change

Estas trazas parecieran no generar demasiada sobrecarga extra al sistema y proveen de info al administrador en caso de que un incidente ocurriera. Adicionalmente si se deshabilitan las trazas tampoco van a tener disponibles la opción para debugear los stored procedures desde el Management Studio 2005.

Consejo, salvo un requerimiento específico, deje las trazas predeterminadas tal como están.

Hugo Román Bernachea
Mail de contacto: SQLServer777@gmail.com

Microsoft Certified DBA
Microsoft Certified Trainer
Twitter: @bernachea

Read More...

Mejoras en T-SQL de SQL Server 2008 - El type Table para ser usado como parámetro de un Stored Procedure

Siempre existió la necesidad de pasar información en forma batch, esto es, pasar múltiples registros de información a SQL como parámetro de un Stored Procedure, lo cual tendría un rendimiento superior al pasar de una sola vez una gran cantidad de información y no pasar la información con múltiples invocaciones.
En SQL Server 2000 el parche que se usaba para lograr este efecto era pasar un parámetro con datos XML en una variable varchar(8000) para luego leerlo desde el Stored Procedure con OpenXML.
En SQL Server 2005 se incorporó el tipo de datos xml que facilitó este manejo, ya que por un lado permitía enviar mayor cantidad de información a los 8000 bytes y por el otro habilitaba el manejo de xquery además del OpenXML para leer el parámetro de tipo XML nativo.
Pero en SQL Server 2008 esto todavía se logra de una manera todavía mas sencilla utilizando parámetros de tipo Table.

Un ejemplo vale mas que mil palabras y para empezar a demostrar la nueva característica vamos a crear una base de datos de ejemplo:
CREATE DATABASE [Ejemplo]

Ahora vamos a crear un tabla llamada Clientes que utilizaremos para este ejemplo.
use Ejemplo
go
CREATE TABLE [Clientes]
(
[ID] [int] NOT NULL PRIMARY KEY IDENTITY,
[Nombre] [varchar](100)NOT NULL,
[Apellido] [varchar](100)NOT NULL,
[Email] [varchar](200) NOT NULL
)
GO
--ingresamos algunos registros en la tabla Clientes
INSERT INTO [Clientes] (nombre, apellido, Email)
VALUES('aaa','XYZ', 'aaa@ejemplo.com')
INSERT INTO [Clientes] (nombre, apellido, Email)
VALUES('bbb','XYZ', 'bbb@ejemplo.com')
INSERT INTO [Clientes] (nombre, apellido, Email)
VALUES('ccc','XYZ', 'ccc@ejemplo.com')
GO

podemos probar los datos ingresados con:
SELECT * FROM Clientes

y debieran aparecer los tres registros previamente cargados.

Ahora creamos el tipo de datos (type) de tipo Table:
CREATE TYPE [ClientesUDT] AS TABLE
(
nombre varchar(100) NOT NULL,
apellido varchar(100) NOT NULL,
Email varchar(200) NOT NULL
)
GO
Con cualquiera de las dos sentencias siguientes pueden verificar la creación del tipo:
SELECT name, system_type_id, user_type_id, is_assembly_type, is_table_type
FROM SYS.TYPES WHERE is_table_type = 1
SELECT name, system_type_id, user_type_id, is_assembly_type, is_table_type
FROM SYS.TABLE_TYPES

Obviamente también pueden usar el Management Studio para verificar en forma visual la existencia del nuevo type.

Hecho todo lo anterior, ahora vamos directamente al punto clave de toda esta innovación y vamos a crear un Stored Procedure utilizando un parámetro de tipo Table:
use Ejemplo
GO
CREATE PROCEDURE dbo.AgregaClientes
@ClientesTVP ClientesUDT READONLY --observese que tiene que ser readonly
AS
BEGIN
INSERT INTO dbo.Clientes
SELECT * FROM @ClientesTVP
END
GO

Ahora vamos a probar si todo funciona ok:
/*
** defino una variable de tipo el udf de tipo table previamente creado
*/
DECLARE @ColeccionClientes ClientesUDT
--ingreso algunos datos
INSERT INTO @ColeccionClientes (nombre, apellido, Email)
VALUES('ddd','XYZ', 'ddd@ejemplos.com')
INSERT INTO @ColeccionClientes (nombre, apellido, Email)
VALUES('eee','XYZ', 'eee@ejemplos.com')
INSERT INTO @ColeccionClientes (nombre, apellido, Email)
VALUES('fff','XYZ', 'fff@ejemplos.com')

EXEC AgregaClientes @ColeccionClientes
select * from clientes
GO

Y de esta manera hemos pasado en un solo parámetro varios registros de una sola vez, con todo lo que eso implica a nivel rendimiento y sencillez.

Invocando el Stored Procedure desde .NET 3.5
En la siguiente página se indica detalladamente como invocar el Stored Procedure de este artículo desde un aplicativo .NET 3.5
http://logicanet.blogspot.com/2009/08/usando-el-nuevo-tipo.html

Hugo Román Bernachea
Mail de contacto: SQLServer777@gmail.com

Microsoft Certified DBA
Microsoft Certified Trainer
Twitter: @bernachea


Read More...

SQL Server 2008 - Buscando Stored Procedures que no están en el caché

Con el query que se publica a continuación se puede obtener una lista de Stored Procedures que no están en el cache, lo cual podría posibilitar investigar luego si esos S.P. que no están en el cache son realmente utilizados o no.

Atención, nunca borre o elimine un stored procedure basandose en este query, ya que este query indica solamente si el sp está en el cache, lo cual no significa necesariamente que no se utiliza, por caso si un S.P. tiene las sentencias RECOMPILE, nunca jamás aparecerá en el cache a pesar de ser plenamente utilizado.

Y recuerde que en vez de eliminar un S.P. debería renombrarlo con algún prefijo que identifique claramente a los SPs a investigar en el entorno de testing y luego hacer las pruebas correspondientes en entornos de testing y de pruebas para ver si ese S.P. es usado o no. Y obviamente, luego de todas esas pruebas y como medida de seguridad adicional, antes de borrar un S.P. en producción se debe guardar un script con toda la lógica.

Dicho lo anterior, veamos los scripts:
-- Obtengo una lista de SPs en la base de datos (SQL 2005 and 2008)
  SELECT p.name AS 'SP Name', p.create_date, p.modify_date      
  FROM sys.procedures AS p
  WHERE p.is_ms_shipped = 0
  ORDER BY p.name;


  -- Obtener una lista de SPs posiblemente no usados (SQL 2008 solamente)
  SELECT p.name AS 'SP Name'        
  FROM sys.procedures AS p
  WHERE p.is_ms_shipped = 0

  EXCEPT

  SELECT p.name AS 'SP Name'        -- Lista de SPs en la base actual
  FROM sys.procedures AS p          -- que están en el procedure cache
  INNER JOIN sys.dm_exec_procedure_stats AS qs
  ON p.object_id = qs.object_id
  WHERE p.is_ms_shipped = 0;
Adicionalmente usted puede usar el siguiente query (solamente SQL Server 2008)
para determinar las dependencias de un objeto.
SELECT referencing_schema_name, referencing_entity_name
FROM sys.dm_sql_referencing_entities (‘Person.Address’, 'OBJECT');


Estos consejos son dados "AS IS" "TAL COMO ESTÁN", no doy ni concedo explicita o implicitamente
garantía alguna acerca de estos scripts, queries y consejos, ni de su funcionalidad ni utilidad
y su uso queda bajo la exclusiva responsabilidad de un Administrador de Bases de Datos competente
y experimentado, toda responsabilidad por daños alguno o el mal uso de los mismos queda bajo la
responsabilidad exclusiva de dicho administrador y se da por entendido que las bases de Datos
SQL Server deben ser administradas por profesionales expertos en dicha tecnología.
No me hago cargo de modo alguno por daños en datos, sistemas y servidores o 
similes por el uso de este o cualquier otro artículo de este blog.

Hugo Román Bernachea
Mail de contacto: SQLServer777@gmail.com

Microsoft Certified DBA
Microsoft Certified Trainer
Twitter: @bernachea

Read More...

Intersect, Except, Union, All and Any - David Poole

David Poole en SQLServerCentral hace una revisión de algunos nuevos comandos en SQL Server 2008, por caso:

INTERSECT
EXCEPT
ALL
ANY
ALL y ANY no son nuevos, pero INTERSECT y EXCEPT son nuevos.

INTERSECT, EXCEPT and UNION

Para experimentar con esos comandos David decidió ver dos conjuntos de valores para CustomerID.

Customers (Clientes) en sales territory 10 (United Kingdom)
(pedidos) Sales orders de July 2004, el cual es el último mes de pedidos en Adventureworks
La mejor manera de ver que hacen estos dos comandos es comparar los datos en los diagramas.
redicate Illustration Description
EXCEPT Customers (clientes) de UK que no compraron en Julio 2004
INTERSECT Customers (clientes) de UK
AND (y) que compraron algo en Julio 2004
UNION Customers (clientes) de UK
OR (o) que hicieron una compra en Julio 2004

Diferentes formas de escribir un query con EXCEPT.

Si bien nunca usé EXCEPT antes yo he obtenido los mismos resultados por métodos tradicionales, hay muchas formas de hacer lo mismo, por ejemplo:
LEFT JOIN
Este query trae los resultados requeridos.
SELECT C.CustomerID
   FROM Sales.Customer AS C
    LEFT JOIN Sales.SalesOrderHeader AS OH
    ON C.CustomerID = OH.CustomerID
    AND OrderDate>='2004-07-01'
   WHERE OH.CustomerID IS NULL
   AND C.TerritoryID=10
WHERE CustomerID NOT IN(…)
Buscando la eficiencia, otra forma de hacer lo mismo.

SELECT CustomerID
   FROM Sales.Customer
   WHERE TerritoryID=10
   AND CustomerID NOT IN(
    SELECT customerid
    FROM  Sales.SalesOrderHeader
    WHERE OrderDate>='2004-07-01'
   )

EXCEPT

Finalmente usando el nuevo comando Except.
SELECT CustomerID
   FROM Sales.Customer
   WHERE TerritoryID=10
    EXCEPT
   SELECT customerid
   FROM Sales.SalesOrderHeader
   WHERE OrderDate>='2004-07-01'

Diferentes maneras de escribir un query tipo INTERSECT

Tres ejemplos:
INNER JOIN
Como un cliente puede tener mas de un pedido tengo que hacer una lista con distinct para los valores del customerid, veamos dos enfoques para lo mismo.

As any customer can have more than one order I am going to have to make a distinct list of CustomerID values. I decided to try a couple of approaches.
SELECT DISTINCT C.CustomerID
   FROM Sales.Customer AS C
    INNER JOIN Sales.SalesOrderHeader AS OH
    ON C.CustomerID = OH.CustomerID
   WHERE
    C.TerritoryID=10
    AND OH.OrderDate>='2004-07-01'

SELECT C.CustomerID
   FROM Sales.Customer AS C
    INNER JOIN (SELECT DISTINCT CustomerID FROM Sales.SalesOrderHeader WHERE OrderDate>='2004-07-01'
   )AS OH
    ON C.CustomerID = OH.CustomerID
   WHERE C.TerritoryID=10
WHERE CustomerID IN(…)
SELECT CustomerID
   FROM Sales.Customer
   WHERE TerritoryID=10
   AND CustomerID IN(
    SELECT customerid
    FROM  Sales.SalesOrderHeader
    WHERE OrderDate>='2004-07-01'
   )
INTERSECT
Finalmente un intersect.
SELECT CustomerID
   FROM Sales.Customer
   WHERE TerritoryID=10
    INTERSECT
   SELECT customerid
   FROM Sales.SalesOrderHeader
   WHERE OrderDate>='2004-07-01'
The ANY and ALL Predicate
ANY and ALL are predicates I have never needed to use.

ANY

Los dos queries nos ofrecen los mismos resultados y el mismo plan de ejecución:
SELECT *
   FROM Sales.SalesPerson
   WHERE TerritoryID = ANY(
    SELECT TerritoryID FROM Sales.SalesTerritory WHERE CountryRegionCode='US'
   )

SELECT *
   FROM Sales.SalesPerson
   WHERE TerritoryID IN(
    SELECT TerritoryID FROM Sales.SalesTerritory WHERE CountryRegionCode='US'
   )
   
ALL
All permite una comparación contra todos los valores en una lista de un select, por caso estos dos queries son idénticos:

SELECT *
   FROM Sales.SalesOrderHeader
   WHERE TotalDue > ALL(SELECT TotalDue FROM Sales.TopSales)
   ORDER BY Sales.TotalDue DESC 

SELECT *
   FROM Sales.SalesOrderHeader
   WHERE TotalDue > (SELECT MAX(TotalDue) FROM Sales.TopSales)
   ORDER BY Sales.TotalDue DESC 
La página original se encuentra en:

http://www.sqlservercentral.com/articles/T-SQL/67545/


Hugo Román Bernachea
Mail de contacto: SQLServer777@gmail.com

Microsoft Certified DBA
Microsoft Certified Trainer
Twitter: @bernachea

Read More...

Algunos Scripts para monitorear SQL Server

Para monitorear el estado de los jobs que fallaron en su última ejecución:

SELECT name FROM msdb.dbo.sysjobs A, msdb.dbo.sysjobservers B
                           WHERE A.job_id = B.job_id AND B.last_run_outcome = 0
Espacio en cada disco para la instancia SQL:

EXEC master..xp_fixeddrives
Para ver un listado de Jobs Deshabilitados:
SELECT name FROM msdb.dbo.sysjobs
           WHERE enabled = 0 ORDER BY name
Para ver un listado de los jobs que están actualmente en ejecución:

msdb.dbo.sp_get_composite_job_info
          NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, NULL
Para ver logines que son miembros de los roles de servidor:
SELECT 'ServerRole' = A.name, 'MemberName' =  B.name
      FROM master.dbo.spt_values A, master.dbo.sysxlogins B
              WHERE A.low = 0 AND A.type = 'SRV' AND B.srvid IS NULL
Para ver la última vez que las bases de datos fueron backupeadas:

SELECT  B.name as Database_Name, ISNULL(STR(ABS(DATEDIFF(day, GetDate(),
MAX(Backup_finish_date)))),
'NEVER') as DaysSinceLastBackup,
ISNULL(Convert(char(10), MAX(backup_finish_date), 101), 'NEVER')
as LastBackupDate
FROM master.dbo.sysdatabases B
LEFT OUTER JOIN msdb.dbo.backupset A
ON A.database_name = B.name AND A.type = 'D'
GROUP BY B.Name
ORDER BY B.name

Para leer las ultimas entradas del archivo de log (NO el transaction log):

CREATE TABLE #Errors (vchMessage varchar(255), ID int)
CREATE INDEX idx_msg ON #Errors(ID, vchMessage)
INSERT #Errors EXEC xp_readerrorlog
SELECT vchMessage
FROM #Errors
WHERE vchMessage
NOT LIKE '%Log backed up%' AND vchMessage
NOT LIKE '%.TRN%' AND vchMessage
NOT LIKE '%Database backed up%' AND vchMessage
NOT LIKE '%.BAK%' AND vchMessage
NOT LIKE '%Run the RECONFIGURE%' AND
vchMessage NOT LIKE '%Copyright (c)%'
ORDER BY ID

DROP TABLE #Errors


Espero sus comentarios, sugerencias, correcciones, etc y espero además
que estos scripts les sean de utilidad.

Hugo Román Bernachea
Mail de contacto: SQLServer777@gmail.com

Microsoft Certified DBA
Microsoft Certified Trainer
Twitter: @bernachea









Read More...

Como obtener todos los campos de una tabla en SQL 2000 y en 2005

--como obtener todos los campos de una tabla
Una vez determinado el object id, en este caso el 146230095 que corresponde a la tabla store de adventureworks, podremos ejecutar una de las siguientes consultas dependiendo de si estamos en 2000 o en 2005 (y 2008)

--sql server 2000
select syscolumns.name [name], systypes.name [type],
syscolumns.length as 'length',
syscolumns.isnullable as 'isnullable'
from syscolumns inner join systypes
on syscolumns.xtype = systypes.xtype and
syscolumns.xusertype = systypes.xusertype
where syscolumns.id = 14623095"
and systypes.name <> 'sysname'
order by syscolumns.colid

--sql server 2005 & 2008

with ctabla
as
(select s.name + '.' + t.name tabla, t.object_id oid from sys.tables t
inner join sys.schemas s on t.schema_id = s.schema_id)

select c.name [name],
(select top 1name from sys.systypes where xtype = c.system_type_id) [type],
c.max_length [length], c.is_nullable [isnullable] from sys.columns c
inner join ctabla t on c.object_id = t.oid
where t.oid = 14623095
order by c.name

Hugo Román Bernachea
Mail de contacto: SQLServer777@gmail.com

Microsoft Certified DBA
Microsoft Certified Trainer
Twitter: @bernachea

Read More...

Como obtener todas las tablas de una base de datos en SQL Server 2000 y en 2005

--Todas las tablas de una base de datos
-- en sql 2000

select name, Id from sysobjects
where type='U' and name <> 'dtproperties'
order by name

-- en sql 2005
with ctabla
as
(select s.name + '.' + t.name tabla, t.object_id oid from sys.tables t
inner join sys.schemas s on t.schema_id = s.schema_id)
select t.tabla, name from sys.columns c
inner join ctabla t on c.object_id = t.oid

Hugo Román Bernachea
Mail de contacto: SQLServer777@gmail.com

Microsoft Certified DBA
Microsoft Certified Trainer
Twitter: @bernachea

Read More...