quarta-feira, 16 de dezembro de 2009
Data por extenso alterando o language
*** No exemplo eu uso por padrão o us_english no banco de dados. Verifique antes qual o default language do seu banco para alterar a última linha do código:
Declare @Data DateTime
set language brazilian
Declare @Retorno VarChar(200)
If @Data is Null
Begin
Set @Data = getdate()
End
Select DATENAME(weekday, @Data) + ', ' + convert(varchar(02),DatePart(day,@Data)) + ' De ' + DateName(Month,@Data) + ' de ' + convert(varchar(04),DatePart(YEar,@Data)) + '.'
SET LANGUAGE us_english
Importar e Exportar imagem do banco.
Independente da discussão, aqui vai um exemplo de como colocar uma imagem no banco e depois recuperá-la.
Primeiro passo: Criar a tabela.
If Exists(Select 0 from Sys.Objects Where name = 'tbCachimbos')
Begin
Drop Table dbo.tbCachimbos
End
GO
Create Table dbo.tbCachimbos(
idCachimbo int Identity(1,1) NOT NULL,
dsCachimbo VarChar(1000) Not Null,
dsimage Image NULL,
Constraint PK_Cachimbos Primary Key Clustered (idCachimbo ASC))
* Notem o campo dsimage do tipo Image.
Segundo passo: Fazer o insert de um registro e depois colocar a imagem.
Insert Into dbo.tbCachimbos (dsCachimbo) Values ('Brebbia First Rocciata Double Silver Band')
Update dbo.tbCachimbos
Set dsimage = (Select * From OpenRowset (Bulk 'd:\Projetos\Brebbia.jpg', Single_Blob) as a )
Where idCachimbo = @@Identity
* Faça um select da tabela tbCachimbos e veja como está o campo dsimage.
Terceiro passo: Recuperar a imagem.
Para recuperar a imagem, é preciso utilizar o BCP para gravar um arquivo. O problema de gravar um arquivo imagem a partir do campo de uma tabela é conseguir recuperar a tipagem correta da coluna e gravar em um arquivo sem nenhuma alteração de conteudo.
Entre alguns exemplos que consegui, acabei optando por usar um arquivo FMT como padrão de saida.
O arquivo FMT fica assim:
9.0
1
1 SQLIMAGE 0 0 "" 1 dsimage ""
E para recuperar a imagem:
Declare @SQLcommand NVarChar(4000)
Set @SQLcommand = 'bcp "SELECT dsimage FROM BancoTeste.dbo.tbCachimbos" queryout "d:\Projetos\Brebbia_Recuperado.jpg" -T -fd:\Projetos\Imagens.fmt'
Exec xp_cmdshell @SQLcommand, no_output
terça-feira, 17 de novembro de 2009
Diminuir o tamanho do banco TempDB
Método 1:
Diminui para um tamanho especifico:
USE TEMPDB
GO
DBCC SHRINKFILE (tempdev, 50)
--* O comando acima diminui o tamanho do arquivo de dados do tempdb para 50MB.
DBCC SHRINKFILE (templog, 5)
--* O comando acima diminui o tamanho do arquivo de log do tempdb para 5MB.
Método 2:
Diminuir para um percentual do tamanho atual
DBCC SHRINKDATABASE (tempdb, 10)
--* O comando acima diminui o tamanho do banco tempdb para 10% do atual.
Os dois métodos acima podem não funcionar caso o banco de dados TempDB ainda possua dados, nesse caso o único método que funcionará é o 3o.
Método 3:
Esse método é o mais simples:
Reinicie o serviço do SQLServer:
Clique com o botão direito do mouse em "SQL Server" no SQL Server Configuration Manager e clique em Restart ou Reiniciar.
Para saber o resultado em qualquer dos métodos acima
SP_HELPDB TEMPDB
Como iniciar o SQLServer em modo single-user
(Essas alterações podem tambem ser feitas pelo Services do Windows no serviço "SQL Server (MSSQLSERVER)")
Clique em Parâmetros de inicialização para visualizar as seguintes entradas:
A opção "-c" reduz o tempo de inicialização ao iniciar SQL Server no prompt de comando. Normalmente, o Mecanismo de Banco de Dados do SQL Server inicia como um serviço chamando o Gerenciador de Controle de Serviços. Porque o Mecanismo de Banco de Dados do SQL Server não inicia como um serviço quando inicia do prompt de comando.
A opção "-m" indica que quando você inicia uma instância de SQL Server em modo de usuário único, só um único usuário pode conectar.
A opção "-T3608" indica que uma instância de SQL Server deveria ser iniciada com um sinalizador de rastreamento especificado (trace#) em efeito. São usados sinalizadores de rastreamento para iniciar o servidor com comportamento sem padrão. O sinalizador de rastreamento 3608 evita que o SQL Server recupere qualquer banco de dados, exceto o banco de dados mestre.
O parametro de inicialização fica por exemplo:
-dD:\MSSQL\DATA\master.mdf;-eD:\MSSQL\LOG\ERRORLOG;-lC:\MSSQL\LOGS\mastlog.ldf; -m -c -T3608
Após alterado, pare o serviço e inicie novamente.
Para voltar ao modo normal, retire as opções -m -c -T3608 e reinicie o serviço.
Mover os arquivos do banco de dados Msdb
O sinalizador de rastreamento 3608 evita que o SQL Server recupere na inicialização qualquer banco de dados, exceto o banco de dados Master.
Após adicionar a opção -c, a opção -m e o sinalizador de rastreamento 3608, execute as seguintes etapas:
. Interrompa e reinicie o SQL Server.
. Certifique-se de que o serviço SQL Server Agent não está sendo executado no momento.
. Desanexe o banco de dados msdb como segue:
use master
go
sp_detach_db 'msdb'
go
. Mova os arquivos Msdbdata.mdf e Msdblog.ldf do local atual (D:\Mssql8\Data) para o novo local (E:\Mssql8\Data).
. Remova -c -m -T3608 da caixa de parâmetros de inicialização no Enterprise Manager.
. Interrompa e reinicie o SQL Server.
Observação: Se tentar anexar novamente o banco de dados msdb iniciando o SQL Server junto com a opção -c, a opção -m e o sinalizador de rastreamento 3608, talvez você a seguinte mensagem de erro seja exibida:
Servidor: Msg 615, Nível 21, Estado 1, Linha 1
Não foi possível encontrar a tabela de banco de dados ID 3, nome 'Model'.
.Anexe novamente o banco de dados msdb conforme a seguir:
use master
go
sp_attach_db 'msdb','E:\Mssql8\Data\msdbdata.mdf','E:\Mssql8\Data\msdblog.ldf'
go
Observação: Se usar este procedimento e mover o banco de dados Model, estará tentando desanexar o banco de dados msdb enquanto desanexa o banco de dados Model.
Ao fazer isto, será necessário anexar novamente o banco de dados Model primeiro e anexar novamente o banco de dados msdb.
Se anexar novamente o banco de dados msdb primeiro, a seguinte mensagem de erro será exibida ao tentar anexar novamente o banco de dados Model:
Msg 0, Nível 11, Estado 0, Linha 0
Erro grave no comando atual. Os resultados, se houver, devem ser descartados.
Neste caso, é necessário desanexar o banco de dados msdb, anexar novamente o banco de dados Model e anexar novamente o banco de dados msdb.
Após mover o banco de dados msdb, talvez a seguinte mensagem de erro seja exibida:
Erro 229: Permissão EXECUTE negada no objeto'ObjectName', banco de dados 'mestre', proprietário 'dbo'.
Esse problema ocorre porque a corrente de propriedade foi quebrada.
Os proprietários do banco de dados msdb e do banco de dados mestre não são os mesmos.
Neste caso, o proprietário do banco de dados msdb foi alterado. Como solução alternativa, execute as seguintes declarações Transact-SQL.
É possível fazer isso usando a linha de comando Osql.exe ou a linha de comando Sqlcmd.exe:
USE MSDB
Go
EXEC sp_changedbowner 'sa'
Go
Mover os arquivos do banco de dados Master
Observação: Aqui também é possível alterar o local do log de erro.
. Clique com o botão direito do mouse em "SQL Server" no SQL Server Configuration Manager e clique em Propriedades.
(Essas alterações podem tambem ser feitas pelo Services do Windows no serviço "SQL Server (MSSQLSERVER)")
. Clique em Parâmetros de inicialização para visualizar as seguintes entradas:
-dC:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\DATA\master.mdf -eC:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\LOG\ERRORLOG -lC:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\DATA\mastlog.ldf
-d é o caminho totalmente qualificado para o arquivo de dados do banco de dados mestre.
-e é o caminho totalmente qualificado para o arquivo de log de erro.
-l é o caminho totalmente qualificado para o arquivo de log do banco de dados mestre.
. Altere os caminhos dos arquivos para o lugar desejado. No exemplo abaixo os arquivos serão passados para a Pasta D:\BD\SQLDATA e o Log para D:\BD\Log
-dD:\BD\SQLDATA\master.mdf -eD:\BD\Log -lD:\BD\SQLDATA\mastlog.ldf
. Pare o serviço "SQL Server".
. Copie os arquivos Master.mdf e Mastlog.ldf para o novo local (D:\BD\SQLDATA\).
. Inicie o serviço "SQL Server".
quarta-feira, 11 de novembro de 2009
Primeiras letras em maiúsculas sem Loop. (Camel Case)
Declare @Texto VarChar(8000)
Set @Texto = 'CamelCase é a denominação em inglês para a prática de escrever palavras compostas ou frases, onde cada palavra é iniciada com Maiúsculas e unidas sem espaços. É um padrão largamente utilizado em diversas linguagens de programação, como Java, Ruby e Python, principalmente nas definições de Classes e Objetos. Pela sua associação com tecnologia, o marketing se apropriou dessa maneira de escrever, injetando certo ar de "tecnologia" nos produtos assim nomeados: iPod, GameCube, OpenOffice.org, StarCraft, dentre outros.'
;With tbCamelCase as (
Select upper( substring( @Texto, 1, 1 )) AS cc,
1 as Seq
Union All
select Case When substring(@Texto, n.Seq, 1) = ' '
Then upper(substring( @Texto, n.Seq + 1, 1 ))
Else substring( @Texto, n.Seq + 1, 1)
End AS cc,
n.Seq + 1 as Seq
From tbCamelCase n
Where n.Seq + 1 <= Len(@Texto))
Select Replace((Select cc AS [text()] from tbCamelCase for xml path( '' )), ' ', ' ')
option(maxrecursion 30000)
Números randomicos dentro de um período.
DECLARE @Random INT;
DECLARE @Upper INT;
DECLARE @Lower INT
SET @Lower = 800 --Limite inferior do periodo
SET @Upper = 999 --Limite superior do periodo
SELECT @Random = ROUND(((@Upper - @Lower -1) * RAND(CAST(NEWID() AS varbinary )) + @Lower), 0)
SELECT @Random
Um exemplo dessa aplicação é gerar números aleatórios de telefones:
DECLARE @Random VarChar(9)
DECLARE @Upper Decimal(9,0)
DECLARE @Lower Decimal(9,0)
SET @Lower = 30000000 --Limite inferior do periodo
SET @Upper = 99999999 --Limite superior do periodo
Select @Random = Stuff(Convert(VarChar(9), Convert(Decimal(9,0), ROUND(((99999999 - @Lower -1) * RAND(CAST(NEWID() AS varbinary)) + @Lower), 0))), 5, 0, '-')
SELECT @Random
Gerar CNPJ Válido
Declare @n Int, @n1 Int, @n2 Int, @n3 Int, @n4 Int, @n5 Int, @n6 Int, @n7 Int, @n8 Int, @n9 Int, @n10 Int, @n11 Int, @n12 Int
Declare @d1 Int, @d2 Int
Set @n = 9
Set @n1 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n2 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n3 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n4 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n5 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n6 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n7 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n8 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n9 = 0
Set @n10 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n11 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n12 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @d1 = @n12*2+@n11*3+@n10*4+@n9*5+@n8*6+@n7*7+@n6*8+@n5*9+@n4*2+@n3*3+@n2*4+@n1*5
Set @d1 = 11 - (@d1%11)
if (@d1>=10)
Set @d1 = 0
Set @d2 = @d1*2+@n12*3+@n11*4+@n10*5+@n9*6+@n8*7+@n7*8+@n6*9+@n5*2+@n4*3+@n3*4+@n2*5+@n1*6
Set @d2 = 11 - (@d2%11)
if (@d2>=10)
Set @d2 = 0
Select
Cast(@n1 as VarChar)+
Cast(@n2 as VarChar)+'.'+
Cast(@n3 as VarChar)+
Cast(@n4 as VarChar)+
Cast(@n5 as VarChar)+'.' +
Cast(@n6 as VarChar)+
Cast(@n7 as VarChar)+
Cast(@n8 as VarChar)+'/'+
Cast(@n9 as VarChar)+
Cast(@n10 as VarChar)+
Cast(@n11 as VarChar)+
Cast(@n12 as VarChar)+'-'+
Cast(@d1 as VarChar)+
Cast(@d2 as VarChar)
Gerar CPF Válido
Declare @n Int, @n1 Int, @n2 Int, @n3 Int, @n4 Int, @n5 Int, @n6 Int, @n7 Int, @n8 Int, @n9 Int
Declare @d1 Int, @d2 Int
Declare @NumeroCPFs Int
Create Table #TabelaCPF (sCPF VarChar(14))
Set @NumeroCPFs = 1000
While @NumeroCPFs > 0
Begin
Set @n = 9;
Set @n1 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n2 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n3 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n4 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n5 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n6 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n7 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n8 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @n9 = Cast((@n + 1) * RAND(CAST(NEWID() AS varbinary )) as int)
Set @d1 = @n9*2+@n8*3+@n7*4+@n6*5+@n5*6+@n4*7+@n3*8+@n2*9+@n1*10;
Set @d1 = 11 - (@d1%11);
if (@d1>=10)
Set @d1 = 0
Set @d2 = @d1*2+@n9*3+@n8*4+@n7*5+@n6*6+@n5*7+@n4*8+@n3*9+@n2*10+@n1*11;
Set @d2 = 11 - ( @d2%11 );
if (@d2>=10)
Set @d2 = 0;
Insert Into #TabelaCPF Values (
Cast(@n1 as VarChar)+
Cast(@n2 as VarChar)+
Cast(@n3 as VarChar)+'.'+
Cast(@n4 as VarChar)+
Cast(@n5 as VarChar)+
Cast(@n6 as VarChar)+'.'+
Cast(@n7 as VarChar)+
Cast(@n8 as VarChar)+
Cast(@n9 as VarChar)+'-'+
Cast(@d1 as VarChar)+
Cast(@d2 as VarChar))
Set @NumeroCPFs = @NumeroCPFs - 1
End
Select * from #TabelaCPF
Drop Table #TabelaCPF
Recuperar banco em Suspect
Basicamente, se não houver problemas muito mais sérios, a receita é:
EXEC sp_resetstatus 'Nome_BancoDados';
ALTER DATABASE Nome_BancoDados SET EMERGENCY
DBCC checkdb('Nome_BancoDados')
ALTER DATABASE Nome_BancoDados SET SINGLE_USER WITH ROLLBACK IMMEDIATE
DBCC CheckDB ('Nome_BancoDados', REPAIR_ALLOW_DATA_LOSS)
ALTER DATABASE Nome_BancoDados SET MULTI_USER
sexta-feira, 6 de novembro de 2009
Renomear os arquivos e nome lógico dos arquivos de um banco.
from BDDesenvOld.Sys.Database_files
Name Physical_Name
------------------- ----------------------------------
BDDesenv_Temp E:\DataSQL\BDDesenv.mdf
BDDesenv_Temp_log E:\DataSQL\BDDesenv_log.ldf
USE master
GO
ALTER DATABASE BDDesenvOld SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE
GO
ALTER DATABASE BDDesenvOld
MODIFY FILE (NAME = BDDesenv_Temp, NEWNAME = BDDesenvOld, FILENAME = 'E:\DataSQL\BDDesenvOld.mdf')
GO
ALTER DATABASE BDDesenvOld
MODIFY FILE (NAME = BDDesenv_Temp_log, NEWNAME = BDDesenvOld_log, FILENAME = 'E:\DataSQL\BDDesenvOld_log.ldf')
GO
alter database BDDesenvOld set offline
GO
/*
Agora tem que renomear o arquivo na mão pelo SO
*/
alter database BDDesenvOld set Online
GO
ALTER DATABASE BDDesenvOld SET multi_user
Select Name, Physical_Name
from BDDesenvOld.Sys.Database_files
Name Physical_Name
--------------------- -------------------------------------
BDDesenvOld E:\DataSQL\BDDesenvOld.mdf
BDDesenvOld_log E:\DataSQL\BDDesenvOld_log.ldf
Renomear um database.
Este procedimento não renomeia o nome fisico do arquivo, somente o nome do banco no SQLServer.
USE [master]
GO
ALTER DATABASE DBDesenv SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE
GO
ALTER DATABASE DBDesenv MODIFY NAME = DBDesenvOld
GO
ALTER DATABASE DBDesenvOld SET multi_user
Como mover um banco de dados
Isso é facilmente resolvido por um detach / atach.
use BDDesenvolvimento
--Para saber exatamente onde o arquivo está.
sp_helpfile
name fileid filename filegroup size maxsize growth usage
---------------------- ------ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- ------------------ ------------------ ------------------ ---------
BDDesenvolvimento 1 C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\DATA\BDDesenvolvimento.mdf PRIMARY 13312 KB Unlimited 10240 KB data only
BDDesenvolvimento_log 2 C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\DATA\BDDesenvolvimento_log.ldf NULL 5696 KB 2147483648 KB 10% log only
use master
go
--Desvincule o banco de dados do servidor:
sp_detach_db 'BDDesenvolvimento'
go
/*Depois, copie os arquivos de dados e de log do local atual (D:\Mssql7\Data) para um novo local (E:\Sqldata). */
use master
go
--Vincule novamente o banco de dados.
sp_attach_db 'BDDesenvolvimento','e:\DataSQL\BDDesenvolvimento.mdf','e:\LogsSQL\BDDesenvolvimento_log.ldf'
go
use BDDesenvolvimento
GO
--Verifique o novo caminho do banco.
sp_helpfile
name fileid filename filegroup size maxsize growth usage
--------------------- ------ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- ------------------ ------------------ ------------------ ---------
BDDesenvolvimento 1 e:\DataSQL\BDDesenvolvimento.mdf PRIMARY 13312 KB Unlimited 10240 KB data only
BDDesenvolvimento_log 2 e:\LogsSQL\BDDesenvolvimento_log.ldf NULL 5696 KB 2147483648 KB 10% log only
Listar as instancias de SQLServer do dominio.
Lembrando que para utilizar o cmdshell, talvez você precise liberar o acesso no seu servidor.
Declare @SQL as Varchar(100)
If Object_ID('tempdb..#InstanciasSQL') is Not Null
Begin
Drop Table #InstanciasSQL
End
CREATE TABLE #InstanciasSQL ([FName] NVARCHAR(1000))
SET @SQL = 'EXEC XP_CMDSHELL "OSQL -L"'
Insert Into #InstanciasSQL
Exec(@SQL)
Select LTrim(RTrim(FName))
from #InstanciasSQL
Where LTrim(RTrim(FName)) Not in ('Servers:')
And FName is not null
Log de execução do Maintenance Plan
With UltimaExecucao as (
Select A.Plan_Id, Max(A.Start_Time) as DataExec
from msdb..sysmaintplan_log A
Inner Join msdb..sysmaintplan_plans B On A.Plan_Id = B.id
Where B.name = 'OrgDiario' --Aqui vai o nome do seu MP
Group by A.Plan_Id)
Select C.Name,
C.Owner,
Case when D.succeeded = 1 then 'True' else 'False' End as Succeeded,
D.line1,
D.line2,
D.line3,
D.line4,
D.line5,
D.start_time,
D.end_time,
D.error_number,
D.error_message
From UltimaExecucao A
Inner Join msdb..sysmaintplan_log B On A.Plan_Id = B.Plan_Id
And A.DataExec = B.start_time
Inner Join msdb..sysmaintplan_plans C On C.id = A.Plan_Id
Inner Join msdb..sysmaintplan_logdetail D On D.task_detail_id = B.task_detail_id
Script para saber quais Backups foram executados e quando
B.backup_finish_date,
B.database_name as source_database_name,
C.physical_device_name as backup_file_used_for_restore
From msdb..backupset B
INNER JOIN msdb..backupmediafamily C ON B.media_set_id = C.media_set_id
Order by B.backup_start_date DESC
Script para saber quais Restores foram executados e quando
A.restore_date,
B.backup_start_date,
B.backup_finish_date,
B.database_name as source_database_name,
C.physical_device_name as backup_file_used_for_restore
From msdb..restorehistory A
INNER JOIN msdb..backupset B ON A.backup_set_id = B.backup_set_id
INNER JOIN msdb..backupmediafamily C ON B.media_set_id = C.media_set_id
Order by A.restore_date DESC
Cálculo de Feriados Móveis
Declare @ano int
Set @ano = 2009
DECLARE
@seculo INT,
@G INT,
@K INT,
@I INT,
@H INT,
@J INT,
@L INT,
@MesDePascoa INT,
@DiaDePascoa INT,
@pascoa smalldatetime
SET @seculo = @ano / 100
SET @G = @ano % 19
SET @K = ( @seculo - 17 ) / 25
SET @I = ( @seculo - CAST(@seculo / 4 AS int) - CAST(( @seculo - @K ) / 3 AS int) + 19 * @G + 15 ) % 30
SET @H = @I - CAST(@I / 28 AS int) * ( 1 * -CAST(@I / 28 AS int) * CAST(29 / ( @I + 1 ) AS int) ) * CAST(( ( 21 - @G ) / 11 ) AS int)
SET @J = ( @ano + CAST(@ano / 4 AS int) + @H + 2 - @seculo + CAST(@seculo / 4 AS int) ) % 7
SET @L = @H - @J
SET @MesDePascoa = 3 + CAST(( @L + 40 ) / 44 AS int)
SET @DiaDePascoa = @L + 28 - 31 * CAST(( @MesDePascoa / 4 ) AS int)
SET @pascoa = CAST(@MesDePascoa AS varchar(2)) + '-' + CAST(@DiaDePascoa AS varchar(2)) + '-' + CAST(@ano AS varchar(4))
Select @pascoa as 'Pascoa',
DateAdd(dd, -3, @pascoa) as 'Sexta-Feira Paixao',
DateAdd(dd, -47, @pascoa) as 'Quarta Carnaval',
DateAdd(dd, 60, @pascoa) as 'CORPUS CHRISTI'
Miudezas Parte 4: Caminho do arquivo fisico do bd.
Select * from sys.database_files
Select * from sys.Master_Files
Select * from Sys.Databases
*/
Select A.Database_id,
A.Type_Desc as 'Tipo',
B.Name as 'Banco',
A.Name as 'Nome Arquivo',
A.Physical_Name as 'Caminho Arquivo'
from Sys.Master_Files A
Inner Join Sys.Databases B On A.Database_Id = B.Database_Id
Order by B.Name, Tipo DESC
Métodos Hexadecimal em SQLServer
Representação String to Hex
*/
DECLARE @HEXB AS varbinary(1000) ,
@HEXV AS varchar(1000)
-- Convert hexstring value in a variable to varbinary:
DECLARE @hexstring varchar(max) ;
SET @hexstring = 'abcedf012439' ;
SELECT @HEXB =
CAST('' AS xml).value('xs:hexBinary( substring(sql:variable("@hexstring"), sql:column("t.pos")) )' , 'varbinary(max)')
FROM
( SELECT
CASE substring(@hexstring , 1 , 2)
WHEN '0x' THEN 3
ELSE 0
END ) AS t ( pos )
Select @HEXB,
SQL_VARIANT_PROPERTY(@HEXB,'BaseType') AS '@HEXB Base Type'
GO
/*
Hex p/ representação em string - Function não documentada
*/
select master.dbo.fn_varbintohexstr(@HEXB) as String
--OU
DECLARE @hexbin varbinary(max)
SET @hexbin = 0xabcedf012439
Set @HEXV = '0x' + CAST('' AS xml).value('xs:hexBinary(sql:variable("@hexbin") )' , 'varchar(max)')
Select @HEXV,
SQL_VARIANT_PROPERTY(@HEXV,'BaseType') AS '@HEXV Base Type'
GO
/*
Valor correspondente em string/int
*/
DECLARE @HEXB AS varbinary(1000),
@charvalue as VarChar(1000)
Set @HEXB = 0x46617573746F
declare @vc varchar(8)
declare @vi Int
declare @vb varbinary(8)
set @vb = @HEXB
set @vc = CONVERT(varchar(8),@vb,2)
SELECT @vb, @vc
set @vb = 0x000000C1
set @vc = CONVERT(Int,@vb,2)
SELECT @vb, @vc
/*
Hex p/ representação em string
*/
DECLARE @HEXB AS varbinary(1000),
@charvalue as VarChar(1000)
Set @HEXB = 0x193
Set @charvalue = '0x' + cast('' as xml).value('xs:hexBinary(sql:variable("@HEXB") )', 'varchar(max)');
SELECT SQL_VARIANT_PROPERTY(@charvalue,'BaseType') AS '@charvalue Base Type',
SQL_VARIANT_PROPERTY(@charvalue,'Precision') AS '@charvalue Precision',
SQL_VARIANT_PROPERTY(@charvalue,'Scale') AS '@charvalue Scale',
SQL_VARIANT_PROPERTY(@charvalue,'MaxLength') AS '@charvalue MaxLength',
@charvalue as '@charvalue Valor'
SELECT
/*
Conversão de String / Int p/ HEX
*/
declare @hexstring varchar(max);
set @hexstring = '193';
select CONVERT(varbinary(max), @hexstring, 1);
set @hexstring = '193';
select CONVERT(varbinary(max), @hexstring, 2);
declare @hexInt Int;
set @hexInt = '193';
select CONVERT(varbinary(max), @hexInt, 2);
quinta-feira, 27 de agosto de 2009
Combinação de valores Base-2.
Combinação de valores Base 2 é bastante utilizado em "campos" onde precisamos guardar uma combinação de "possibilidades" ou opções em um único campo. Por exemplo em campos de status ou pendencias.
O valor resultante desta combinação único, nenhuma outra combinação resulta no mesmo valor, então com uma lógica simples é possivel achar essa combinação.
Um exemplo disso são os campos Status e Status2 da tabela sys.databases ( http://msdn.microsoft.com/pt-br/library/ms179900.aspx )
Select Name, Status, Status2 from Master.dbo.sysdatabases
Name Status Status2
---------- ----------- -----------
master 65544 1090520064
O Status 65544 é a combinação de 65536 e 8
O Status2 1090520064 é a combinação de 1073741824, 16777216 e 1024
De qualquer forma, a sequencia é sempre número anterior * 2, ou em base-2: 2^n.
2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, etc, etc, etc.....
Seguindo o exemplo de "pendências", para facilitar vamos imagina um caso onde um cliente fez um cadastro em uma loja para contratar um financiamento, e está "devendo" alguns documentos para terminar o processo do financiamento:
Código Valor Descrição
1 2 Falta RG
2 4 Falta CPF
3 8 Falta Certidão de Nascimento
4 16 Falta Certidão de Casamento
5 32 Falta Certidão Negativa
6 64 Falta Comprovante de Renda
7 128 Falta Comprovante de Residencia
8 256 Falta Reservista
9 512 Falta Passaporte
10 1024 Falta Comprovante de Votação
Combinando os valores 3 (8), 5 (32), 7 (128), 8 (256) e 10 (1024) = 1448
Ainda faltam para o cliente:
- Falta Certidão de Nascimento
- Falta Certidão Negativa
- Falta Comprovante de Residencia
- Falta Reservista
- Falta Comprovante de Votação
Uma forma simples de se fazer isso é, sabendo que a soma dos números anteriores nunca é maior ou igual à atual, fazer um loop decrescente "easy cake" diminuindo do resultado final +/- assim:
/************************************************************************************************/
Declare @Numero float, @LimiteSuperior float, @iLimiteSuperior Int
Set @Numero = 1448
Set @LimiteSuperior = 562949953421312 -- 49 opções se precisar mais que isso é só calcular.
Set @iLimiteSuperior = 49
Declare @Resultados table (Base int, Valor float)
While @Numero > 0
Begin
If @LimiteSuperior < = @Numero Begin
Insert Into @Resultados Values (@iLimiteSuperior, @LimiteSuperior)
Set @Numero = @Numero - @LimiteSuperior
End
Set @LimiteSuperior = @LimiteSuperior / 2 --Acha o valor anterior
Set @iLimiteSuperior = @iLimiteSuperior - 1
End
Select * from @Resultados
/************************************************************************************************/
Outra forma, que eu acho mais interessante, tambem é um loop decrescente, porem trabalhamos com Log Base-2 que conseguimos com a divisão: LOG(Numero)/LOG(2).
/************************************************************************************************/
Declare @Numero float, @Expoente float
Declare @Resultados table (Base int, Valor float)
Set @Numero = 1448
While @Numero > 0
Begin
Set @Expoente = FLOOR(LOG(@Numero)/LOG(2))
Insert Into @Resultados Values (@Expoente, POWER(cast(2 as float), @Expoente))
set @Numero = @Numero - POWER(cast(2 as float), @Expoente)
End
Select * from @Resultados
Gerar Senhas Randomicas parte 2.
Como parametro de entrada da function eu passava os itens abaixo e recebia lista de senhas como Table.
@GrupoBitMinuscula
@GrupoBitNumericos
@GrupoBitEspeciais
@GrupoBitDiferenci
@GrupoCharDiferenci
@QuantidadeSenha
@TamanhoSenha
Declare @GrupoCharMaiuscula VarChar(26),
@GrupoCharMinuscula VarChar(26),
@GrupoCharNumericos VarChar(10),
@GrupoCharEspeciais VarChar(26),
@GrupoCharDiferenci VarChar(Max)
Declare @GrupoBitMaiuscula Bit,
@GrupoBitMinuscula Bit,
@GrupoBitNumericos Bit,
@GrupoBitEspeciais Bit,
@GrupoBitDiferenci Bit
Declare @GrupoCharTotal VarChar(Max),
Declare @TextoSenha Table (dsSenha VarChar(Max))
Declare @tmpTextoSenha VarChar(Max)
Declare @TamanhoSenha Int,
@QuantidadeSenha Int
Set @QuantidadeSenha = 10 --Quantidade de senhas para serem geradas
Set @GrupoCharMaiuscula = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
Set @GrupoCharMinuscula = 'abcdefghijklmnopqrstuvwxyz'
Set @GrupoCharNumericos = '1234567890'
Set @GrupoCharEspeciais = '!#%&()*+,-./:;<=>@[]^_{}~'
Set @GrupoCharDiferenci = ''
Set @GrupoBitMaiuscula = 1
Set @GrupoBitMinuscula = 1
Set @GrupoBitNumericos = 1
Set @GrupoBitEspeciais = 1
Set @GrupoBitDiferenci = 0
Set @GrupoCharTotal = Case when @GrupoBitMaiuscula = 1 Then @GrupoCharMaiuscula Else '' End +
Case when @GrupoBitMinuscula = 1 Then @GrupoCharMinuscula Else '' End +
Case when @GrupoBitNumericos = 1 Then @GrupoCharNumericos Else '' End +
Case when @GrupoBitEspeciais = 1 Then @GrupoCharEspeciais Else '' End +
Case when @GrupoBitDiferenci = 1 Then @GrupoCharDiferenci Else '' End
While @QuantidadeSenha > 0
Begin
set @tmpTextoSenha = ''
Set @TamanhoSenha = 15 --Tamanho da senha em Caracteres
While @TamanhoSenha > 0
Begin
Select @tmpTextoSenha = @tmpTextoSenha + SUBSTRING(@GrupoCharTotal , Cast((Len(@GrupoCharTotal) - 2) * RAND(CAST(NEWID() AS varbinary )) + 1 as int) , 1)
Set @TamanhoSenha = @TamanhoSenha - 1
End
Insert Into @TextoSenha Values (@tmpTextoSenha)
Set @QuantidadeSenha = @QuantidadeSenha - 1
End
Select * from @TextoSenha
Random no SQLServer
Mas dá para contornar isso usando alguns artificios.
Exemplo, execute algumas vezes repetidas esta linha:
SELECT RAND(), RAND(3);
Os resultados não mudam.
Idem Aqui:
SELECT RAND(159784);
SELECT RAND(159784);
SELECT RAND(159784);
Aqui vou apresentar 2 meios (Existem vários) de fazer com que o Rand realmente seja um Rand, utilizando seu parametro de seed.
1) Usando uma Data:
SELECT RAND( (DATEPART(mm, GETDATE()) * 100000 )
+ (DATEPART(ss, GETDATE()) * 1000 )
+ DATEPART(ms, GETDATE()) );
2) Usando o o NewID:
SELECT RAND(CAST( NEWID() AS varbinary ));
Com isso em mãos, é possivel então estabelecer limites Mínimos e Máximos para o Random:
DECLARE @Upper INT;
DECLARE @Lower INT
SET @Lower = 1 ---- The lowest random number
SET @Upper = 999 ---- The highest random number
--Para gerar Randomicamente os números em float:
SELECT Cast((@Upper - @Lower -1) * RAND(CAST(NEWID() AS varbinary)) + @Lower as Float)
--Para gerar Randomicamente os números em Int:
SELECT Cast((@Upper - @Lower -1) * RAND(CAST( NEWID() AS varbinary )) + @Lower as Int)
Gerar Senhas Randomicas parte 1.
declare @password varchar(15) -- Aqui o 15 é a quantidade de caracteres
set @password=''
select @password=@password+char(n) from
(
Select Top 15 Number as N -- Aqui o 15 é a quantidade de caracteres
From master..spt_values
Where type='p'
And number between 48 and 122
Order by newid()
) as t
select @password
quarta-feira, 26 de agosto de 2009
Retornar os valores afetados nos Inserts, Updates ou Deletes.
Ela contém os valores Deleted e Inserted de todas as colunas do update, independente da quantidade de linhas que o Insert, Update ou Delete afetaram:
create table #permanent(id int, d float, comment varchar(15))
go
insert into #permanent values(1, 10., 'Original Row')
insert into #permanent values(2, 10., 'Original Row')
insert into #permanent values(3, 10., 'Original Row')
go
create table #staging(id int, d float)
go
insert into #staging values(2, 15.)
insert into #staging values(3, 15.)
insert into #staging values(4, 15.)
go
declare @updated_ids table(id int, d float, commentAnt varchar(15), commentNew varChar(15))
update #permanent
set d = s.d, comment = 'Modified Row'
output inserted.id, inserted.d, deleted.comment, inserted.comment into @updated_ids
from #permanent p, #staging s
where p.id=s.id
Select *
From @updated_ids
Drop Table #staging
Drop Table #permanent
Split parte 3
Create Table #tmpLista (idLinha Int, xCol VarChar(max))
Insert Into #tmpLista Values (1, 'Linha A1;Linha B1;Linha C1;Linha D1;Linha E1;Linha F1')
Insert Into #tmpLista Values (2, 'Linha A2;Linha B2;Linha C2;Linha D2;Linha E2;Linha F2')
Insert Into #tmpLista Values (3, 'Linha A3;Linha B3;Linha C3;Linha D3;Linha E3;Linha F3')
Insert Into #tmpLista Values (4, 'Linha A4;Linha B4;Linha C4;Linha D4;Linha E4;Linha F4')
Insert Into #tmpLista Values (5, 'Linha A5;Linha B5;Linha C5;Linha D5;Linha E5;Linha F5')
Insert Into #tmpLista Values (6, 'Linha A6;Linha B6;Linha C6;Linha D6;Linha E6;Linha F6')
Insert Into #tmpLista Values (7, 'Linha A7;Linha B7;Linha C7;Linha D7;Linha E7;Linha F7')
Insert Into #tmpLista Values (8, 'Linha A8;Linha B8;Linha C8;Linha D8;Linha E8;Linha F8')
Insert Into #tmpLista Values (9, 'Linha A9;Linha B9;Linha C9;Linha D9;Linha E9;Linha F9')
Insert Into #tmpLista Values (10, 'Linha A10;Linha B10;Linha C10;Linha D10;Linha E10;Linha F10')
DECLARE @delimiter NVARCHAR(5)
Set @delimiter = ';'
;with tbLista as (
SELECT CAST ( '
From #tmpLista
Where idLinha Between 1 and 5
)
SELECT T.split.value('.', 'nvarchar(max)') AS data, idLinha
FROM tbLista CROSS APPLY xCol.nodes('/d') T (split)
Drop Table #tmpLista
Update em Tabela e em variavel ao mesmo tempo.
Achei meio sem sentido, talvez só para economizar um select, mas de qualquer jeito posto aqui:
Create Table #Tabela1 (id Int, Nome Varchar(50))
Insert Into #Tabela1 Values (1, 'AAA')
Insert Into #Tabela1 Values (2, 'BBB')
Insert Into #Tabela1 Values (3, 'CCC')
Insert Into #Tabela1 Values (4, 'DDD')
Insert Into #Tabela1 Values (5, 'EEE')
Declare @Nome VarChar(50)
Update #Tabela1
Set @Nome = Nome,
Nome = 'AAA1'
Where id = 1
Select @Nome as 'Antigo'
Select * from #Tabela1 Where id = 1
Drop Table #Tabela1
terça-feira, 25 de agosto de 2009
Join Array - Concatenar registros parte 2
DECLARE @Procedures varchar(MAX)
Select @Procedures = COALESCE(@Procedures + ', ', '') + name
From sysobjects
Where name like 'sp_%'
Select @Procedures
Join Array - Concatenar registros parte 1
A rigor só a query abaixo já faz o "join", mas ela retorna como XML:
Select cast(name as varchar) + '; ' AS [text()]
from dbo.sysobjects
where name like 'sp_%'
For XML PATH ('')
Então para retornar em String:
Select (Select cast(name as varchar) + '; ' AS [text()]
from dbo.sysobjects
where name like 'sp_%'
For XML PATH ('')) as Array
Split parte 2
DECLARE @data NVARCHAR(MAX), @delimiter NVARCHAR(5)
DECLARE @textXML XML;
Set @data = 'Linha A1;Linha B1;Linha C1;Linha D1;Linha E1;Linha F1'
SELECT @textXML = CAST('
SELECT T.split.value('.', 'nvarchar(max)') AS data
FROM @textXML.nodes('/d') T (split)
Split parte 1
Create Table #tmpLista (xCol VarChar(max))
Insert Into #tmpLista Values ('Linha A1;Linha B1;Linha C1;Linha D1;Linha E1;Linha F1')
Insert Into #tmpLista Values ('Linha A2;Linha B2;Linha C2;Linha D2;Linha E2;Linha F2')
Insert Into #tmpLista Values ('Linha A3;Linha B3;Linha C3;Linha D3;Linha E3;Linha F3')
Insert Into #tmpLista Values ('Linha A4;Linha B4;Linha C4;Linha D4;Linha E4;Linha F4')
Insert Into #tmpLista Values ('Linha A5;Linha B5;Linha C5;Linha D5;Linha E5;Linha F5')
Insert Into #tmpLista Values ('Linha A6;Linha B6;Linha C6;Linha D6;Linha E6;Linha F6')
Insert Into #tmpLista Values ('Linha A7;Linha B7;Linha C7;Linha D7;Linha E7;Linha F7')
Insert Into #tmpLista Values ('Linha A8;Linha B8;Linha C8;Linha D8;Linha E8;Linha F8')
Insert Into #tmpLista Values ('Linha A9;Linha B9;Linha C9;Linha D9;Linha E9;Linha F9')
Insert Into #tmpLista Values ('Linha A10;Linha B10;Linha C10;Linha D10;Linha E10;Linha F10')
;WITH tmpListaDados (DadosXML) AS (
SELECT CAST('
FROM #tmpLista)
SELECT CAST(DadosXML.query('for $coluna in /N return $coluna/n[1]/text()') AS VARCHAR(max)) As Coluna1,
CAST(DadosXML.query('for $coluna in /N return $coluna/n[2]/text()') AS VARCHAR(max)) As Coluna2,
CAST(DadosXML.query('for $coluna in /N return $coluna/n[3]/text()') AS VARCHAR(max)) As Coluna3,
CAST(DadosXML.query('for $coluna in /N return $coluna/n[4]/text()') AS VARCHAR(max)) As Coluna4,
CAST(DadosXML.query('for $coluna in /N return $coluna/n[5]/text()') AS VARCHAR(max)) As Coluna5,
CAST(DadosXML.query('for $coluna in /N return $coluna/n[6]/text()') AS VARCHAR(max)) As Coluna6
FROM tmpListaDados
Drop Table #tmpLista
O que o seu SQLServer está executando agora?
Estas duas querys mostram exatamente o que está sendo executado nas sessões ativas do banco de dados.
É bastante útil quando você está com problemas de execução no banco e precisa saber o que está causando os problemas.
/********************************************************/
/* Mosta o SQL que cada sessão está executando */
/********************************************************/
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
go
SELECT [Spid] = session_Id
, ecid
, [Database] = DB_NAME(sp.dbid)
, [User] = nt_username
, [Status] = er.status
, [Wait] = wait_type
, [Individual Query] = SUBSTRING (qt.text,
er.statement_start_offset/2,
(CASE WHEN er.statement_end_offset = -1
THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
ELSE er.statement_end_offset END -
er.statement_start_offset)/2)
,[Parent Query] = qt.text
, Program = program_name
, Hostname
, nt_domain
, start_time
FROM sys.dm_exec_requests er
INNER JOIN sys.sysprocesses sp ON er.session_id = sp.spid
CROSS APPLY sys.dm_exec_sql_text(er.sql_handle)as qt
WHERE session_Id > 50 -- Ignore system spids.
AND session_Id NOT IN (@@SPID) -- Ignore this current statement.
ORDER BY 1, 2
SELECT SDER.[statement_start_offset],
SDER.[statement_end_offset],
CASE
WHEN SDER.[statement_start_offset] > 0 THEN
--The start of the active command is not at the beginning of the full command text
CASE SDER.[statement_end_offset]
WHEN -1 THEN
--The end of the full command is also the end of the active statement
SUBSTRING(DEST.TEXT, (SDER.[statement_start_offset]/2) + 1, 2147483647)
ELSE
--The end of the active statement is not at the end of the full command
SUBSTRING(DEST.TEXT, (SDER.[statement_start_offset]/2) + 1, (SDER.[statement_end_offset] - SDER.[statement_start_offset])/2)
END
ELSE
--1st part of full command is running
CASE SDER.[statement_end_offset]
WHEN -1 THEN
--The end of the full command is also the end of the active statement
RTRIM(LTRIM(DEST.[text]))
ELSE
--The end of the active statement is not at the end of the full command
LEFT(DEST.TEXT, (SDER.[statement_end_offset]/2) +1)
END
END AS [executing statement],
DEST.[text] AS [full statement code]
FROM sys.[dm_exec_requests] SDER CROSS APPLY sys.[dm_exec_sql_text](SDER.[sql_handle]) DEST
WHERE SDER.session_id > 50
ORDER BY SDER.[session_id], SDER.[request_id]
Estatísticas e ShowPlan de uma Query.
Os exemplos abaixo mostram os tipos de estatísticas.
/**************************************************************************************************************//* *//* Statistics */ /* */ /**************************************************************************************************************/
SET STATISTICS TIME ON
go
Select B.object_id, B.name as Tabela, A.name from syscolumns A Inner Join sys.objects B On B.object_id = A.id
go
SET STATISTICS TIME Off
SET STATISTICS IO ON;
GO
Select B.object_id, B.name as Tabela, A.name from syscolumns A Inner Join sys.objects B On B.object_id = A.id
GO
SET STATISTICS IO OFF;
SET STATISTICS PROFILE On
GO
Select B.object_id, B.name as Tabela, A.name from syscolumns A Inner Join sys.objects B On B.object_id = A.id
GO
SET STATISTICS PROFILE Off
SET STATISTICS XML ON
GO
Select B.object_id, B.name as Tabela, A.name from syscolumns A Inner Join sys.objects B On B.object_id = A.id
GO
SET STATISTICS XML Off
/**************************************************************************************************************//* *//* ShowPlan */ /* */ /**************************************************************************************************************/
SET SHOWPLAN_ALL ON;
GO
Select B.object_id, B.name as Tabela, A.name from syscolumns A Inner Join sys.objects B On B.object_id = A.id
GO
Select B.object_id, B.name as Tabela, A.name from syscolumns A Inner Hash Join sys.objects B On B.object_id = A.id
GO
SET SHOWPLAN_ALL OFF;
GO
SET SHOWPLAN_TEXT ON;
GO
Select B.object_id, B.name as Tabela, A.name from syscolumns A Inner Join sys.objects B On B.object_id = A.id
GO
Select B.object_id, B.name as Tabela, A.name from syscolumns A Inner Hash Join sys.objects B On B.object_id = A.id
GO
SET SHOWPLAN_TEXT Off;
GO
quinta-feira, 20 de agosto de 2009
Listar arquivos do diretório.
Há outras opções, entre elas utilizando a xp_cmdshell e utilizando FSO. Mas de longe esta é a mais simples.
No exemplo a seguir, ele vai listar todos os arquivos e pasta do c:\
Parametros:
1) Pasta inicial: caminho da pasta inicial para pesquisa
2) Nivel da busca: 1 é somente a pasta inicial, 0 ou Null são todas as pastas a partir da pasta inicial informada, qualquer valor > 1 é a quantidade de niveis de subpastas a partir da pasta inicial informada.
3) Inclui arquivo: 1 Inclui arquivos e pastas; 0 ou Null só pastas.
EXEC master.dbo.xp_dirtree N'c:\', 1, 1
O retorno é:
1) SubDirectory - Nome da pasta ou arquivo
2) Depth - Nivel do arquivo em relação à pasta inicial da pesquisa.
3) File - 1 para arquivo e 0 para Pasta
Ela vale tambem para diretórios de maquinas da rede, desde que estejam compartilhadas (não precisam estar mapeadas)
EXEC master.dbo.xp_dirtree N'\\Servidor_de_rede\comum', 1, 1
Espaço em disco 3
No exemplo abaixo, utilizando a xp_cmdshell a rotina executa a aplicação DOS fsutil retornando o espaço livre do disco C:. Este retorno é gravado em uma tabela temporária e depois separado e mostrado.
DECLARE @Drive varchar(max),
@SQL VARCHAR(max)
SET @SQL = 'EXEC XP_CMDSHELL "fsutil volume diskfree c:"'
Create Table #tmpLista (xCol VarChar(max))
Insert Into #tmpLista
Exec(@SQL)
Delete #tmpLista Where xCol is null
;WITH tmpDrivers (DadosXML) AS (
SELECT CAST('
FROM #tmpLista)
SELECT CAST(DadosXML.query('for $coluna in /N return $coluna/n[1]/text()') AS VARCHAR(80)) As Descricao,
--CAST(DadosXML.query('for $coluna in /N return $coluna/n[last()]/text()') AS VARCHAR(80)) As Tamanho
CAST(DadosXML.query('for $coluna in /N return $coluna/n[2]/text()') AS VARCHAR(80)) As Tamanho
FROM tmpDrivers
Drop Table #tmpLista
Espaço em disco 2
IF EXISTS (SELECT name FROM tempdb..sysobjects WHERE name = '##_DriveSpace')
DROP TABLE ##_DriveSpace
IF EXISTS (SELECT name FROM tempdb..sysobjects WHERE name = '##_DriveInfo')
DROP TABLE ##_DriveInfo
CREATE TABLE ##_DriveSpace
(
DriveLetter CHAR(1) not null
, FreeSpace VARCHAR(10) not null
)
CREATE TABLE ##_DriveInfo
(
DriveLetter CHAR(1)
, TotalSpace bigint
, FreeSpace bigint
, Label varchar(10)
)
DECLARE @Result INT
, @objFSO INT
, @Drv INT
, @cDrive VARCHAR(13)
, @Size VARCHAR(50)
, @Free VARCHAR(50)
, @Label varchar(10)
INSERT INTO ##_DriveSpace
EXEC master.dbo.xp_fixeddrives
-- Iterate through drive letters.
DECLARE curDriveLetters CURSOR
FOR SELECT driveletter FROM ##_DriveSpace
DECLARE @DriveLetter char(1)
OPEN curDriveLetters
FETCH NEXT FROM curDriveLetters INTO @DriveLetter
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
BEGIN
SET @cDrive = 'GetDrive("' + @DriveLetter + '")'
EXEC @Result = sp_OACreate 'Scripting.FileSystemObject', @objFSO OUTPUT
IF @Result = 0
EXEC @Result = sp_OAMethod @objFSO, @cDrive, @Drv OUTPUT
IF @Result = 0
EXEC @Result = sp_OAGetProperty @Drv,'TotalSize', @Size OUTPUT
IF @Result = 0
EXEC @Result = sp_OAGetProperty @Drv,'FreeSpace', @Free OUTPUT
IF @Result = 0
EXEC @Result = sp_OAGetProperty @Drv,'VolumeName', @Label OUTPUT
IF @Result <> 0
EXEC sp_OADestroy @Drv
EXEC sp_OADestroy @objFSO
SET @Size = (CONVERT(BIGINT,@Size) / 1048576 )
SET @Free = (CONVERT(BIGINT,@Free) / 1048576 )
INSERT INTO ##_DriveInfo
VALUES (@DriveLetter, @Size, @Free, @Label)
END
FETCH NEXT FROM curDriveLetters INTO @DriveLetter
END
CLOSE curDriveLetters
DEALLOCATE curDriveLetters
PRINT 'Drive information for server ' + @@SERVERNAME + '.'
PRINT ''
-- Produce report.
SELECT DriveLetter
, Label
, FreeSpace AS [FreeSpace MB]
, (TotalSpace - FreeSpace) AS [UsedSpace MB]
, TotalSpace AS [TotalSpace MB]
, ((CONVERT(NUMERIC(9,0),FreeSpace) / CONVERT(NUMERIC(9,0),TotalSpace)) * 100) AS [Percentage Free]
FROM ##_DriveInfo
ORDER BY [DriveLetter] ASC
GO
DROP TABLE ##_DriveSpace
DROP TABLE ##_DriveInfo
Espaço em disco 1
Ela executa a Stored Procedure xp_fixeddrives que retorna a lista de drivers do servidor e o espaço livre de cada um, insere estes dados em uma tabela temporaria, para depois cruzar com a informação da function fn_servershareddrives, que mostra se é um drive Shared.
CREATE TABLE #DriveSpace ( Drive char(1), MBFree int )
-- get availabe drives and free space on each of them
INSERT INTO #DriveSpace EXEC xp_fixeddrives
SELECT * INTO #DriveUnion FROM (
SELECT A.DriveName COLLATE Latin1_General_CI_AS [Drives Available],
#DriveSpace.MBFree, 'X'[Shared]
FROM ::fn_servershareddrives() A
LEFT JOIN #DriveSpace on A.DriveName COLLATE Latin1_General_CI_AS = #DriveSpace.drive
UNION
SELECT Drive COLLATE Latin1_General_CI_AS [Drives Available],
MBFree, '-'[Shared]
FROM #DriveSpace
WHERE Drive NOT IN (SELECT DriveName COLLATE Latin1_General_CI_AS
FROM ::fn_servershareddrives()) ) A
Select * from #DriveUnion
Drop Table #DriveUnion
Drop Table #DriveSpace
Executar comandos DOS no SQLServer
Por default o SQLServer vem com opção de uso da xp_cmdshell desabilitado, sendo necessário habilitar manualmente pelo administrador do banco.
A liberação da xp_cmdshell implica em alguns riscos de segurança, pesquise sobre os riscos e avalie sua necessidade.
Quando é chamado por um usuário que não é um membro da função de servidor fixa sysadmin, xp_cmdshell se conecta ao Windows usando o nome da conta e a senha armazenadas na credencial chamada ##xp_cmdshell_proxy_account##. Se essa credencial de proxy não existir, xp_cmdshell falhará.
Para habilitar a opção de uso da xp_cmdshell:
sp_configure 'xp_cmdshell', '1'
GO
Reconfigure
Go
Aqui vai um exemplo usando o comando Dir C:\*.*:
Declare @DirCmd as Varchar(100)
Declare @Return as Varchar(Max)
Drop Table #dirlist
CREATE TABLE #dirlist ([FName] NVARCHAR(1000), [DS] VARCHAR(14), [CreateDate] DATETIME)
SET @DirCmd = 'dir C:\*.*'
EXEC @Return = master..xp_cmdshell @DirCmd
Várias informações do seu servidor
Select
SERVERPROPERTY('BuildClrVersion') BuildClrVersion,
SERVERPROPERTY('Collation') Collation,
SERVERPROPERTY('CollationId') CollationId,
SERVERPROPERTY('ComparisonStyle') ComparisonStyle,
SERVERPROPERTY('ComputerNamePhysicalNetBIOS') ComputerNamePhysicalNetBIOS,
SERVERPROPERTY('Edition') Edition,
SERVERPROPERTY('EditionID') EditionID,
SERVERPROPERTY('EngineEdition') EngineEdition,
SERVERPROPERTY('InstanceName') InstanceName,
SERVERPROPERTY('IsClustered') IsClustered,
SERVERPROPERTY('IsFullTextInstalled') IsFullTextInstalled,
SERVERPROPERTY('IsIntegratedSecurityOnly') IsIntegratedSecurityOnly, SERVERPROPERTY('IsSingleUser') IsSingleUser,
SERVERPROPERTY('LCID') LCID,
SERVERPROPERTY('LicenseType') LicenseType,
SERVERPROPERTY('MachineName') MachineName,
SERVERPROPERTY('NumLicenses') NumLicenses,
SERVERPROPERTY('ProcessID') ProcessID,
SERVERPROPERTY('ProductVersion') ProductVersion,
SERVERPROPERTY('ProductLevel') ProductLevel,
SERVERPROPERTY('ResourceLastUpdateDateTime') ResourceLastUpdateDateTime,
SERVERPROPERTY('ResourceVersion') ResourceVersion,
SERVERPROPERTY('ServerName') ServerName,
SERVERPROPERTY('SqlCharSet') SqlCharSet,
SERVERPROPERTY('SqlCharSetName') SqlCharSetName,
SERVERPROPERTY('SqlSortOrder') SqlSortOrder,
SERVERPROPERTY('SqlSortOrderName') SqlSortOrderName,
SERVERPROPERTY('FilestreamShareName') FilestreamShareName,
SERVERPROPERTY('FilestreamConfiguredLevel') FilestreamConfiguredLevel,
SERVERPROPERTY('FilestreamEffectiveLevel') FilestreamEffectiveLevel
GO
A xp_msver retorna:
ProductName
ProductVersion
Language
Platform
Comments
CompanyName
FileDescription
FileVersion
InternalName
LegalCopyright
LegalTrademarks
OriginalFilename
PrivateBuild
SpecialBuild
WindowsVersion
ProcessorCount
ProcessorActiveMask
ProcessorType
PhysicalMemory
Product ID
exec master..xp_msver
GO
A sp_helpserver retorna entre outras informações o collation do banco, sempre o id=0 é seu banco atual
exec master..sp_helpserver
A sp_server_info retorna:
DBMS_NAME
DBMS_VER
OWNER_TERM
TABLE_TERM
MAX_OWNER_NAME_LENGTH
TABLE_LENGTH
MAX_QUAL_LENGTH
COLUMN_LENGTH
IDENTIFIER_CASE
TX_ISOLATION
COLLATION_SEQ
SAVEPOINT_SUPPORT
MULTI_RESULT_SETS
ACCESSIBLE_TABLES
USERID_LENGTH
QUALIFIER_TERM
NAMED_TRANSACTIONS
SPROC_AS_LANGUAGE
ACCESSIBLE_SPROC
MAX_INDEX_COLS
RENAME_TABLE
RENAME_COLUMN
DROP_COLUMN
INCREASE_COLUMN_LENGTH
DDL_IN_TRANSACTION
DESCENDING_INDEXES
SP_RENAME
REMOTE_SPROC
SYS_SPROC_VERSION
exec master..sp_server_info
Log no Trace do Banco de Dados
Assim como o Event Viewer, em alguns processo é bom gravar algo no Trace do do servidor.
E esse input de evento no Trace é feita com a sp_trace_generateevent
1) event_id - Numero do evento, ele deve ser entre 82 e 91 e deve ser previamente criado pela sp_trace_setevent
2) userinfo - Opcional, uma descrição de até 128 posições sobre o evento.
3) userdata - Opcional, uma descrição de até 8000 posições VarBinary do evento.
EXEC master..sp_trace_generateevent 82, 'Algum evento que mereça uma entrada manual no Trace'
Log no Event Viewer pelo SQLServer.
Em alguns processo é bom gravar algo no Event Viewer do servidor, isso é uma prática muito utilizada por programadores de sistemas em suas aplicações.
No SQLServer tambem dá para gravar Logs no Event Viewer.
1) error_number - É um número de erro definido pelo usuário maior que 50.000. O valor máximo é 2147483647 (2^31 - 1).
2) message - É uma cadeia de caracteres com no máximo 2048 caracteres.
3) severity - É uma destas três cadeias de caracteres: INFORMATIONAL, WARNING ou ERROR. severity é opcional, com um padrão INFORMATIONAL.
EXEC xp_logevent 60000, 'Este é um teste de de Log Event pelo SQLServer', INFORMATIONAL
Lá no servidor o resultado no Event Viewer foi:
Event Type: Information
Event Source: MSSQLSERVER
Event Category: (2)
Event ID: 17061
Date: 20/8/2009
Time: 18:34:06
User: **********
Computer: **********
Description:
Error: 60000 Severity: 10 State: 1 Este é um teste de de Log Event pelo SQLServer
For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
Ler o Log do banco de dados via query
Quer ler o Log do seu banco de dados via query sem precisar abrir o arquivo?
Existe uma Stored Procedure não documentada no SQLServer que faz isso.
Lembramos que as Stored Procedure não documentadas a MS não garante sua continuidade em próximas versões e nem seu funcionamento perfeito.
Os parâmetros de entrada dela são:
1) Número do arquivop de Log: 0 = Atual, 1 = Arquivo #1, 2 = Arquivo #2, etc...
2) Tipo do arquivo de Log: 1 or NULL = Log de Erro, 2 = Log do SQL Agent
3) Search string 1: String para busca nos resultados
4) Search string 2: String para refinamento da busca
5) Data inicial para busca
6) Data final para busca
7) Ordenação dos resultados: N'asc' = ascending, N'desc' = descending
EXEC master.dbo.xp_readerrorlog 0, 1, Null, Null, Null, Null, N'desc'
Msg 0, Level 11, State 0, Line 0 / Msg 0, Level 20, State 0, Line 0
sys.dm_exec_sql_text e sys.dm_exec_query_plan com qualquer Cross Join.
O remédio é instalar o Service Pack 3 ou posterior quando houver para o SQLServer 2005.
Msg 0, Level 11, State 0, Line 0
Erro grave no comando atual. Os resultados, se houver algum, deverão ser descartados.
Msg 0, Level 20, State 0, Line 0
Erro grave no comando atual. Os resultados, se houver algum, deverão ser descartados.
O erro é falta do Service Pack:
http://support.microsoft.com/kb/910416/en-us#top
você sabe quais são as Querys mais custosas do seu Banco?
SELECT TOP 20 SUBSTRING(qt.text, (qs.statement_start_offset/2)+1,
((CASE qs.statement_end_offset
WHEN -1 THEN DATALENGTH(qt.text)
ELSE qs.statement_end_offset
END - qs.statement_start_offset)/2)+1),
qs.execution_count,
qs.total_logical_reads, qs.last_logical_reads,
qs.min_logical_reads, qs.max_logical_reads,
qs.total_elapsed_time, qs.last_elapsed_time,
qs.min_elapsed_time, qs.max_elapsed_time,
qs.last_execution_time,
qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE qt.encrypted=0
ORDER BY qs.total_logical_reads DESC
View de Gerenciamento Dinâmico sys.dm_os_ring_buffers
Apesar de ser um pouco chato a extração de informações do campo Record (xml), vale a pena estar sempre de olho nas informações que esta view traz.
As informações são divididas por tipos (ring_buffer_type):
RING_BUFFER_RESOURCE_MONITOR – memory state changes due to various types of memory pressure
RING_BUFFER_MEMORY_BROKER – notification to components by memory broker advising them to grow, shrink or stay stable
RING_BUFFER_SINGLE_PAGE_ALLOCATOR – when the Buffer Pool single page allocator turns on/off internal memory pressure
RING_BUFFER_OOM – out-of-memory conditions
RING_BUFFER_BUFFER_POOL – severe buffer pool failures, including
buffer pool out-of-memory conditions
RING_BUFFER_SCHEDULER – scheduler operations
RING_BUFFER_SCHEDULER_MONITOR – scheduler health
RING_BUFFER_EXCEPTION – list of exceptions
RING_BUFFER_CLRAPPDOMAIN – state of AppDomains loaded in the system
RING_BUFFER_SECURITY_ERROR – (new in SQL Server 2005 SP2) Windows
API failure information
No post anterior tem um exemplo de como utilizar esta View para verificar o processamento do servidor.
Como está o processamento do servidor.
Estes dados são percentuais entre Idle (Livre), Utilizados pelo SQL e Utilizados por outros processos do sistema (Não SQLServer).
Esta informação combinadas com algumas estatisticas e traces podem te dar uma bela ideia de como está se comportando sua base, por horarios, querys, atividades, etc... e até se ha necessidade de intervensão física no servidor.
declare @ts_now bigint
select @ts_now = cpu_ticks / convert(float, cpu_ticks_in_ms) from sys.dm_os_sys_info
select record_id, dateadd(ms, -1 * (@ts_now - [timestamp]), GetDate()) as EventTime, SQLProcessUtilization, SystemIdle, 100 - SystemIdle - SQLProcessUtilization as OtherProcessUtilization from (select record.value('(./Record/@id)[1]', 'int') as record_id, record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int') as SystemIdle, record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]', 'int') as SQLProcessUtilization, timestamp from (select timestamp, convert(xml, record) as record from sys.dm_os_ring_buffers where ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR' and record like '%
Miudezas Parte 3: Transformar TimeStamp em DateTime
Select dateadd(ms, -1 * @@DBTS, GetDate()) as EventTime
Separar Nome e Sobrenome
Ele transfoma a string em XML para poder utilizar os comandos XQuery.
No NomeXML.query você nota a $nome/n[1]/text() que pega a primeira parte de nome e o $nome/n[last()]/text() que pega somente a última. Essa solução eu vou usar mais para frente para fazer um "Split" de uma string no SQLServer.
CREATE TABLE #Nomes (Nome VARCHAR(80))
-- Inserção de registros
INSERT INTO #Nomes VALUES ('Joana Maria')
INSERT INTO #Nomes VALUES ('Ana Paula Silveira')
INSERT INTO #Nomes VALUES ('Pedro Paulo Almeida')
INSERT INTO #Nomes VALUES ('Carlos Eduardo da Silva')
INSERT INTO #Nomes VALUES ('Rodrigo Diógenes Cunha Meira')
INSERT INTO #Nomes VALUES ('Maria')
;WITH NomesF (Nome, NomeXML) AS
( SELECT Nome, CAST('' + REPLACE(Nome,' ','') + '' AS XML) FROM #Nomes)
SELECT Nome,
CAST(NomeXML.query('for $nome in /N return $nome/n[1]/text()') AS VARCHAR(80)) As PrimeiroNome,
CAST(NomeXML.query('for $nome in /N return $nome/n[last()]/text()') AS VARCHAR(80)) As SobreNome,
CAST(NomeXML.query('for $nome in /N return concat($nome/n[1],'' '',$nome/n[last()])') AS VARCHAR(80)) As NomeAbreviado,
LEFT(Nome, Case When CHARINDEX(' ',Nome) = 0 Then Len(Nome) Else CHARINDEX(' ',Nome) -1 End) as UsingReverse1,
RIGHT(Nome, Case When CHARINDEX(' ',REVERSE(Nome)) = 0 Then 0 Else CHARINDEX(' ',REVERSE(Nome))-1 end) as UsingReverse2
FROM NomesF
Como deixar uma Stored Procedure como system sp
Para isso sua Stored Procedure deve ser criada no banco Master.
EXEC sp_ms_marksystemobject 'nome_procedure'
GO
Para verificar se a Stored procedure está como system:
SELECT NAME, IS_MS_SHIPPED
FROM SYS.OBJECTS
WHERE NAME = 'nome_procedure'
GO
Calendário em SQLServer
Alem de ser um excelente exemplo de CTE com recursividade.
declare @start datetime,
@end datetime
set @start = '2009-01-01'
set @end = '2010-01-01'
;with calendar(date,isweekday, y, q,m,d,dw,monthname,dayname,w) as
(
select @start ,
case when datepart(dw,@start) in (1,7) then 0 else 1 end,
year(@start),
datepart(qq,@start),
datepart(mm,@start),
datepart(dd,@start),
datepart(dw,@start),
datename(month, @start),
datename(dw, @start),
datepart(wk, @start)
union all
select date + 1,
case when datepart(dw,date + 1) in (1,7) then 0 else 1 end,
year(date + 1),
datepart(qq,date + 1),
datepart(mm,date + 1),
datepart(dd,date + 1),
datepart(dw,date + 1),
datename(month, date + 1),
datename(dw, date + 1),
datepart(wk, date + 1) from calendar where date + 1< @end
)
select * from calendar option(maxrecursion 10000)
Campos Identity
Primeiro, estra query mostra como estão os Identitys de todas as tabelas do seu banco de dados, a tabela, coluna, o tipo, o valor atual e o % de uso:
SELECT QUOTENAME(SCHEMA_NAME(t.schema_id)) + '.' + QUOTENAME(t.name) AS TableName,
c.name AS ColumnName,
CASE c.system_type_id
WHEN 127 THEN 'bigint'
WHEN 56 THEN 'int'
WHEN 52 THEN 'smallint'
WHEN 48 THEN 'tinyint'
END AS 'DataType',
IDENT_CURRENT(SCHEMA_NAME(t.schema_id) + '.' + t.name) AS CurrentIdentityValue,
CASE c.system_type_id
WHEN 127 THEN (IDENT_CURRENT(SCHEMA_NAME(t.schema_id) + '.' + t.name) * 100.) / 9223372036854775807
WHEN 56 THEN (IDENT_CURRENT(SCHEMA_NAME(t.schema_id) + '.' + t.name) * 100.) / 2147483647
WHEN 52 THEN (IDENT_CURRENT(SCHEMA_NAME(t.schema_id) + '.' + t.name) * 100.) / 32767
WHEN 48 THEN (IDENT_CURRENT(SCHEMA_NAME(t.schema_id) + '.' + t.name) * 100.) / 255
END AS 'PercentageUsed'
FROM sys.columns AS c
INNER JOIN
sys.tables AS t
ON t.[object_id] = c.[object_id]
WHERE c.is_identity = 1
ORDER BY PercentageUsed DESC
Para incrementar passo (seed) a um identity e retornar o valor:
SELECT IDENT_INCR('sua_tabela') AS 'IDENT_INCR';
Para mostra o valor atual do identity:
SELECT IDENT_CURRENT('sua_tabela') AS Current_Identity;
Mostra o "valor de passo" (seed) da identity
SELECT IDENT_SEED('sua_tabela') AS 'IDENT_SEED';
Reset na Identity para o próximo valor valido na tabela.
DBCC CHECKIDENT('sua_tabela')
Reset na Identity para o valor informado no último parâmetro.
DBCC CHECKIDENT('sua_tabela', RESEED, 0)
Para desligar o Identity de uma tabela MOMENTANEAMENTE, para um insert:
SET IDENTITY_INSERT sua_tabela On --Desliga o Identity
Faça os Inserts necessários para sua manutenção/carga.
SET IDENTITY_INSERT sua_tabela Off --Religa o IdentityVocê sabe a diferença entre Some, Any e All??
Com este exemplo bem simples, fica facil de entender.
CREATE TABLE #T1 (ID int)
GO
INSERT Into #T1 VALUES (1)
INSERT Into #T1 VALUES (2)
INSERT Into #T1 VALUES (3)
INSERT Into #T1 VALUES (4)
Print 'The following query returns TRUE because 3 is less than some of the values in the table.'
IF 3 < SOME (SELECT ID FROM #T1)
PRINT 'TRUE'
ELSE
PRINT 'FALSE'
Print 'The following query returns FALSE because 3 is not less than all of the values in the table.'
IF 3 < ALL (SELECT ID FROM #T1)
PRINT 'TRUE'
ELSE
PRINT 'FALSE'
Print 'The following query returns TRUE because 3 is less than anyone of the values in the table.'
Print 'SOME is an ISO standard equivalent for ANY.'
IF 3 < Any (SELECT ID FROM #T1)
PRINT 'TRUE'
ELSE
PRINT 'FALSE'
Verificar e Trocar o owner do Banco
Para listar os Bancos e seus owners:
SELECT databases.NAME as Banco,
server_Principals.NAME as Owner
FROM sys.[databases]
INNER JOIN sys.[server_principals] ON [databases].owner_sid = [server_principals].sid
Esta opção deve ser utilizada somente se o banco perdeu o owner, ou é claro, se você tem certeza do que está fazendo.
Para fazer isso você precisa ser SysAdmin ou estar no grupo DB_Owner.
Este exemplo irá trocar o owner do banco de dados atual para SA.
USE Seu_Banco_De_Dados
GO
EXEC sp_changedbowner 'sa'
GO
Detalhes da Execução de um Job.
Com essa Query dá para saber se o Job ainda está executando, ou se já finalizou, com sucesso ou erro, quanto tempo demorou, etc.
/***************************************/
/* Detalhes da Execução do JOB */
/***************************************/
Use msdb
GO
SELECT sjb.Job_id,
stsv.server_id,
stsv.server_name,
stsv.enlist_date,
stsv.last_poll_date,
cast(dateadd(ss, cast(substring(cast(last_run_time + 1000000 as char(7)),6,2) as int),
dateadd(mi, cast(substring(cast(last_run_time + 1000000 as char(7)),4,2) as int),
dateadd(hh, cast(substring(cast(last_run_time + 1000000 as char(7)),2,2) as int),
convert(datetime,cast (last_run_date as char(8)))))) as DateTime) as LastRunDate,
sjs.last_run_duration,
sjs.last_run_outcome,
sjs.last_outcome_message
FROM msdb.dbo.sysjobs sjb
Inner Join msdb.dbo.sysjobservers sjs On sjb.Job_Id = sjs.job_id
Left Join msdb.dbo.systargetservers_view stsv ON (sjs.server_id = stsv.server_id)
WHERE sjb.name = 'BKPIncremental-1.BKPIncremental-1'
Select Top 2 A.*
from msdb..sysjobhistory A
Inner Join msdb.dbo.sysjobs B On A.Job_Id = B.job_id
Where B.name = 'Nome do Seu Job'
Caso tenha dado erro na execução do Job, esta Query, mostra o log do erro do Job:
Select Top 2 A.*
from msdb..sysjobhistory A
Inner Join msdb.dbo.sysjobs B On A.Job_Id = B.job_id
Where B.name = 'Nome do Seu Job'
Os registros sempre vem uma linha para o Job Outcome e uma linha para cada Step do Job, como o exemplo é um Job de um único Step coloquei o Top 2.
Tamanho da tabela no Banco
Essa SP de sistema, mostra o tamanho em KB das seguintes informações da tabela:
1) Quantida de registros da tabela
2) Espaço reservado para a tabela
3) Espaço utilizado pelos dados
4) Espaço utilizado pelos Indices
5) Espaço ainda livre
sp_spaceused 'sua_tabela'
Estas informações são importantes para por exemplo rever um planejamento de capacidade do servidor.
Como está a utilização dos seus Indices?
A grosso modo, não adianta você criar um indice em tabelas que são mais utilizadas para inserts/updates do que para consultas.
E isso "talvez" você só saiba algum tempo depois, após algumas estatisticas.
Esta primeira query mostra a quantidade de Inserts, Updates e Deletes por indices.
/*leaf_insert_count - total count of leaf level inserts leaf_delete_count - total count of leaf level inserts leaf_update_count - total count of leaf level updates
*/
SELECT OBJECT_NAME(A.[OBJECT_ID]) AS [OBJECT NAME], I.[NAME] AS [INDEX NAME], A.LEAF_INSERT_COUNT, A.LEAF_UPDATE_COUNT, A.LEAF_DELETE_COUNT FROM SYS.DM_DB_INDEX_OPERATIONAL_STATS (NULL,NULL,NULL,NULL ) A INNER JOIN SYS.INDEXES AS I ON I.[OBJECT_ID] = A.[OBJECT_ID] AND I.INDEX_ID = A.INDEX_ID WHERE OBJECTPROPERTY(A.[OBJECT_ID],'IsUserTable') = 1 And (A.LEAF_INSERT_COUNT > 0 Or A.LEAF_UPDATE_COUNT > 0 Or A.LEAF_DELETE_COUNT > 0)Order by LEAF_INSERT_COUNT DESC
Esta mostra a quantidade de Index Seeks, Index Scans, Index Lookups e operações de Insert, Update e Delete por indices.
/*user_seeks - number of index seeks
user_scans- number of index scans
user_lookups - number of index lookups
user_updates - number of insert, update or delete operations
*/
SELECT OBJECT_NAME(S.[OBJECT_ID]) AS [OBJECT NAME], I.[NAME] AS [INDEX NAME], USER_SEEKS, USER_SCANS, USER_LOOKUPS, USER_UPDATES FROM SYS.DM_DB_INDEX_USAGE_STATS AS S INNER JOIN SYS.INDEXES AS I ON I.[OBJECT_ID] = S.[OBJECT_ID] AND I.INDEX_ID = S.INDEX_ID WHERE OBJECTPROPERTY(S.[OBJECT_ID],'IsUserTable') = 1 Order by User_Updates DESC, User_Seeks ASC
Miudezas Parte 2: Saber se o SQLAgent está ativo
BEGIN
PRINT 'SQL Server está ativo mas o SQL Server Agent está INATIVO'
END
ELSE
BEGIN
PRINT 'SQL Server e o SQL Server Agent estão ativos'
END
Miudezas Parte 1: Último dia do mês.
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))
--Último dia do mês atual
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
--Último dia do próximo mês
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0))
Horas Uptime
Os primeiros processos das tabela de sysprocesses são iniciado somente quando o banco é iniciado, e não tem como esses processos pararem ou reiniciarem sem parar o banco. Então a partir deles dá p/ saber quanto tempo seu banco está online.
SELECT 'Uptime: ' + Cast(datediff(mi, login_time, getdate()) /60 as VarChar) + ' Horas'
FROM master..sysprocesses WHERE spid = 1
Como iniciar um Job pelo DOS.
Além do OSql, vamos utilizar o Stored Procedure de sistema "sp_start_job" do banco msdb para iniciar o Job.
Vamos supor que o Job que você quer iniciar se chama Job1. Então, no prompt do DOS:
osql -S "NOME_DO_SERVIDOR" -E -Q"exec msdb.dbo.sp_start_job 'Job1'"
Como executar uma Procedure automaticamente no Start do banco.
Algumas vezes é necessário executar algum processo, stored procedure assim que o banco de dados for iniciado. O exemplo abaixo eu criei para me enviar um e-mail, caso o banco seja reiniciado sem eu saber.
Primeiro eu crio o processo que eu quero que seja executado em uma stored procedure. Ela tem que ser criada no Master.
use master
GO
CREATE PROCEDURE sp_AlertStartDBAS
BEGIN
Declare @sbody as VarChar(4000)
Declare @ssubject as VarChar(4000)
set @sbody = 'O servidor ' + CONVERT(sysname, SERVERPROPERTY('servername')) + ' foi inicializado às ' + Cast(getdate() as VarChar)
set @ssubject = 'Inicialização de Banco de Dados: ' + CONVERT(sysname, SERVERPROPERTY('servername'))
EXEC msdb.dbo.sp_send_dbmail @profile_name = 'Admin', @recipients = 'seuemail@provedor.com.br', @body = @sbody, @subject = @ssubject;
END
O próximo passo é configurar ela para ser executada no Start usando a proc sp_procoption. ( http://msdn.microsoft.com/en-us/library/ms181720.aspx )
EXECUTE sp_procoption @procname = 'sp_AlertStartDB', @optionname = 'startup', @optionvalue = 'on'
Tamanho físico dos arquivos do banco
Quer saber como está o tamanho fisico dos arquivos do seu banco?
SELECT Name,
[Physical_Name],
Left(CONVERT(VARCHAR, CAST( [SIZE]*8 AS MONEY ), 1),
Len(CONVERT(VARCHAR, CAST( [SIZE]*8 AS MONEY ), 1)) - 3) as Size_KB
FROM sys.database_files
Foreing Key sem Indices
Na maioria das vezes se você tem uma FK em uma tabela, a chance de se fazer buscas por essa chave é enorme, então, com bom senso, é bom ter indices nessas FKs.
Como descobrir quais colunas não possuem índices nas chaves estrangeiras (Foreing Key)
Select Object_Name(constid), Object_Name(fkeyid), Object_Name(rkeyid), * From Sysreferences Where not exists (Select 1 from Sysindexkeys Where id = fkeyid and fkey1 = colid and keyno=1)