Arquivo

Arquivo do Autor

Campanha ganhe um livro A Arte da Guerra (孫子兵法)

25 de agosto de 2011 1 comentário

Galera, vamos lá.

Para ajudar na divulgação do meu novo blog estou criando uma campanha onde irei sortear 2 livros Arte da Guerra do Sun Tzu.

http://pt.wikipedia.org/wiki/A_Arte_da_Guerra

A campanha é simples:

  • Irei eleger 2 criadores com a resposta ou frase mais interessante para a pergunta abaixo, e irei enviar cópia do livro do Sun Tzu a Arte da Guerra.
  • Pergunta: Como o Sun Tzu pode te ajudar a ser um DBA/Desenvolvedor SQL Server melhor ?

Para participar basta enviar um e-mail da frase para “fabiano_amorim arroba bol ponto com ponto br” com o assunto “Campanha – Sun Tzu DBA”.

image

As frases e nomes dos ganhadores serão divulgados aqui no meu blog, e eu contatarei os ganhadores por e-mail para envio do livro.

Não ha limite de envio de frases, mande quantas quiser. Qualquer dúvida é só postar um comentário que logo responderei.

Se eu estivesse participando acho que estas seriam minhas frases Smile:

“A estratégia sem tática é o caminho mais lento para a vitória. Tática sem estratégia é o ruído antes da derrota.” Depois que li essa frase do Sun Tzu nunca mais usei cursor.

Tenho certeza de que as estratégias do Sun Tzu irão elevar o nível de como faço guerra com os DBAs que ousam passar pelo meu caminho. (versão desenvolvedor)

Me desculpa mas depois de ler “A Verdade Sobre Chuck Norris: 400 Fatos Sobre o Humano Mais Fantástico do Mundo” não creio que o Sun Tzu possa me ascrecentar algo.

Windows Functions – Parte 5

24 de agosto de 2011 1 comentário

Sliding Window

Para começar, vejamos a sintaxe da clausula OVER().

OVER (

[ <PARTITION BY clause> ]

[ <ORDER BY clause> ]

[ <ROW or RANGE clause> ]

)

clip_image002

Um ponto importante nas windows functions e que aparentemente pode ser um pouco confuso, é a clausula window frame, também conhecida como windowing clause, window size ou sliding window.

Eu vou chamar de window frame que é como a Microsoft chama está clausula.

Na window frame conseguimos especificar qual é o subset de linhas que uma window function irá trabalhar. É possível dizer qual é a parte superior e a parte inferior de um frame. A sintaxe de um window frame é a seguinte:

[ROWS | RANGE] BETWEEN <Start expr> AND <End expr>

Onde:

<Start expr> pode ser:

  • UNBOUNDED PECEDING: A window inicia na primeira linha da partição.
  • CURRENT ROW: A window inicia na linha atual.
  • <unsigned integer literal> PRECEDING ou FOLLOWING

<End expr> pode ser:

  • UNBOUNDED FOLLOWING: A window termina na última linha da partição.
  • CURRENT ROW: A window termina na linha atual.
  • <unsigned integer literal> PRECEDING ou FOLLOWING

Quando não especificado, o window frame padrão é “range between unbounded preceding and current row”, ou seja, a linha superior é a primeira linha da partição atual (unbounded preceding), e a linha inferior é a linha atual (current row).

Para exemplificar toda essa teoria, vamos considerar os seguintes dados da tabela orders do banco NorthWind.

   1:  USE NorthWind
   2:  GO
   3:  SELECT OrderID, CustomerID
   4:  FROM Orders
   5:  WHERE CustomerID IN (1,2)

clip_image003

O resultado da consulta acima retorna 2 clientes e seus respectivos pedidos. Separei os pedidos em 2 windows particionadas por CustomerID, sendo, CustomerID = 1 e CustomerID = 2.

Ainda que conceitualmente essa não seja uma visualização exata da lógica de o que é uma window, essa é uma forma mais simples de entender o é uma window de linhas.

Uma representação mais correta do que é uma window é a seguinte:

clip_image004

Considerando que a primeira window tem 6 linhas, temos 6 windows que coexistem. Como elas coexistem posso facilmente dizer até onde uma window coexiste com a outra utilizando o frame.

Sei que isso não é simples de entender, mas vejamos alguns exemplos.

First_Value()

Digamos que eu queira pegar o primeiro pedido (OrderID) de cada partição acima. Eu teria uma consulta mais ou menos assim:

   1:  SELECT OrderID, CustomerID,
   2:         FIRST_VALUE(OrderID) OVER(PARTITION BY CustomerID ORDER BY OrderID) AS FirstOrderID
   3:  FROM Orders
   4:  WHERE CustomerID IN (1,2)

clip_image005

Lembre-se de que quando não especificado, o window frame default é “range between unbounded preceding and current row”. Ou seja, a consulta acima é igual à consulta abaixo.

   1:  SELECT OrderID, 
   2:         CustomerID,
   3:         FIRST_VALUE(OrderID) OVER(PARTITION BY CustomerID 
   4:                                   ORDER BY OrderID
   5:                                   ROWS BETWEEN UNBOUNDED PRECEDING 
   6:                                   AND CURRENT ROW) AS FirstOrderID
   7:    FROM Orders
   8:   WHERE CustomerID IN (1,2)

Uma ilustração de como o frame e a função FIRST_VALUE() funciona seria algo assim:

clip_image007

Na figura acima podemos observar que o primeiro valor (FIRST_VALUE) da linha 1 é 10643, para a segunda linha o valor continua sendo 10643 já que o frame que especifica a linha superior é sem precedentes (UNBOUNDED PRECEDING).

Last_Value()

A function LAST_VALUE() pode ser um pouco confusa, mas se entendermos o frame veremos que o que ela faz por “padrão” está correto.

É muito comum testar a function e não obter os resultados esperados, algumas pessoas até acharam que ela estava com problemas como podemos ver aqui.

Vamos ver o que a function retorna para o mesmo exemplo e dados da tabela de Orders.

   1:  SELECT OrderID, 
   2:         CustomerID,
   3:         LAST_VALUE(OrderID) OVER(PARTITION BY CustomerID ORDER BY OrderID) AS LastOrderID
   4:    FROM Orders
   5:   WHERE CustomerID IN (1,2)

clip_image008

Como podemos ver o resultado não foi o esperado, na verdade eu quero retornar o último pedido (OrderID) para cada CustomerID. E o SQL Server acabou retornando o mesmo valor de OrderID.

Vamos usar a mesma ilustração que fizemos com o FIRST_VALUE() para processar o LAST_VALUE(). Lembre-se de que não especifiquei o window frame, ou seja, ele esta usando o default.

clip_image010

Se eu deixar o padrão para o frame que diz qual é a linha inferior, ele vai usar current row. E isso não é o que queremos. Na verdade o correto seria usar um frame dizendo que o valor da linha inferior é unbounded following ou seja, seguinte ilimitado, neste caso o limite é até o fim da partição pois estou utilizando a clausula partition by.

   1:  SELECT OrderID, 
   2:         CustomerID,
   3:         LAST_VALUE(OrderID) OVER(PARTITION BY CustomerID 
   4:                                  ORDER BY OrderID
   5:                                  ROWS BETWEEN UNBOUNDED PRECEDING
   6:                                  AND UNBOUNDED FOLLOWING) AS LastOrderID
   7:    FROM Orders
   8:   WHERE CustomerID IN (1,2)

clip_image011

Agora conseguimos retornar os dados esperados. Vejamos como isso fica na nossa ilustração:

clip_image013

O window frame vai de unbounded preceding até unbounded following, ou seja, quando leio o ultimo valor (LAST_VALUE) para uma linha, a window contempla realmente o primeiro e último valor da minha partição.

Conclusão

Nos próximos artigos sobre windows functions vou continuar a explorar o window frame utilizando algumas variações interessantes.

Apesar de conseguir fazer muita coisa, ainda não temos suporte completo ao window frame, pois o Denali não suporta a clausula INTERVAL para especificar um frame temporal utilizando datas. Por ex:

  • RANGE INTERVAL ‘nn’ DAY PRECEDING
  • RANGE INTERVAL ‘nn’ SECONDS FOLLOWING
  • RANGE INTERVAL ‘nn’ MONTH PRECEDING

That’s all folks.

Recomendação, Canal no YouTube

24 de agosto de 2011 Deixe um comentário

Galera, recomendo muitíssimo o canal que meu amigo MVP Gustavo Maia Aguiar criou no Youtube para postar os vídeos e webcasts que ele já fez sobre SQL Server.

Imperdível, mais detalhes aqui:

http://gustavomaiaaguiar.wordpress.com/2011/08/12/ampliando-a-comunicao-mais-um-canal-para-falar-de-sql-server-e-banco-de-dados/

Parabéns pela iniciativa Gustavo.

Categorias:Não categorizado

Windows Functions – Parte 4

24 de agosto de 2011 Deixe um comentário
Windows Functions no SQL Server Denali

Vamos ver neste artigo como funcionam as Windows Functions que estarão disponíveis no SQL Server Denali.

As windows functions apresentadas abaixo estão disponíveis no CTP 3 do SQL Server Denali, você pode fazer o download para avaliação clicando no link abaixo:

https://www.microsoft.com/betaexperience/pd/SQLDCTP3CTA/enus/default.aspx

Base para testes

Para testar as windows functions iremos utilizar uma tabela de testes chamada Tab1. O código para criação da tabela é o seguinte:

USE TempDB
GO

IF OBJECT_ID('Tab1') IS NOT NULL
DROP TABLE Tab1
GO
CREATE TABLE Tab1 (Col1 Int)
GO
INSERT INTO Tab1 VALUES(5), (5), (3) , (1)
GO
LEAD()

A function LEAD é utilizada para ler o valor da próxima linha, ou linha de baixo. Quando a próxima linha não existir NULL é retornado.

Exemplo:

-- LEAD
SELECT Col1,
LEAD(Col1) OVER(ORDER BY Col1) AS "LEAD"
FROM Tab1

image

Como podemos observar a coluna LEAD retorna a próxima linha, no caso do último registro o valor NULL é retornado.

Por padrão a próxima linha é retornada, mas nós podemos alterar este comportamento para que função retorne o valor de N linhas seguintes, por exemplo:

-- LEAD
SELECT Col1,
LEAD(Col1, 2) OVER(ORDER BY Col1) AS "LEAD"
FROM Tab1

image

No resultado acima, solicitei que a função retornasse o valor de 2 linhas seguintes.

LAG()

A function LAG() é similar a function LEAD(), porém ao invés de retornar o próximo valor ela retorna o valor anterior. Por exemplo:

-- LAG
SELECT Col1,
LAG(Col1) OVER(ORDER BY Col1) AS "LAG()"
FROM Tab1

image

Podemos ver que o valor anterior foi retornado, quando a linha não contém valor anterior NULL é retornado.

Você pode estar se pensando que uma alternativa a function LAG() seria usar a function LEAD() com o valor do OffSet negativo certo? Ou seja, ao invés de pegar 1 valor pra frente pega -1.

Vejamos um exemplo:

SELECT Col1,
LEAD(Col1, -1) OVER(ORDER BY Col1) AS "LEAD() Como LAG()"
FROM Tab1

Msg 8730, Level 16, State 1, Line 1

Offset parameter for Lag and Lead functions cannot be a negative value.

Como podemos ver, não é possível usar valores negativos para as funções LEAD() e LAG().

FIRST_VALUE()

Como o nome praticamente diz FIRST_VALUE() retorna o primeiro valor de um frame. Por exemplo:

-- FIRST_VALUE
SELECT Col1,
FIRST_VALUE(Col1) OVER(ORDER BY Col1) AS "FIRST_VALUE()"
FROM Tab1
image
LAST_VALUE()

Como o nome praticamente diz LAST_VALUE() retorna o primeiro valor de um frame. Por exemplo:

-- LAST_VALUE
SELECT Col1,
LAST_VALUE(Col1) OVER(ORDER BY Col1 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS "LAST_VALUE()"
FROM Tab1
image

Para pegar o último valor da window acima precisei especificar qual era o frame, vou explicar melhor como isso funciona no próximo post.

PERCENT_RANK()

No primeiro artigo sobre windows functions mostrei o comportamento da function RANK(). A function PERCENT_RANK() é bem similar a function RANK() porém o resultado é o seguinte:

Exemplo:

-- PERCENT_RANK
SELECT Col1,
PERCENT_RANK() OVER(ORDER BY Col1) AS "PERCENT_RANK()"
FROM Tab1

image

O mesmo efeito era possível no SQL Server 2005, utilizando a seguinte fórmula:

  • (RANK() – 1) / (NúmeroDeLinhas – 1)

Abaixo podemos visualizar um código para simular o uso da function PERCENT_RANK() no SQL Server 2005:

-- Fake PERCENT_RANK
SELECT Col1,
(RANK() OVER(ORDER BY Col1) - 1.) / ((SELECT COUNT(*) FROM Tab1) - 1.) AS "Fake PERCENT_RANK()"
FROM Tab1
image
CUME_DIST()

A function CUME_DIST() também é utilizada para calcular a posição de um valor em um rank. Vejamos um exemplo:

-- CUME_DIST()
SELECT Col1,
CUME_DIST() OVER(ORDER BY Col1) AS "CUME_DIST()"
FROM Tab1

image

O mesmo resultado pode ser visualizado utilizando a seguinte fórmula:

  • COUNT(*) OVER (ORDER BY Col1) / COUNT(*) OVER ()
Conclusão

Ainda falta mostrar as functions de distribuition PERCENTILE_CONT e PERCENTILE_DISC, e explicar o que é e como usar o frame de uma window.

É isso ai pessoal, fique de olho para o próximo artigo sobre Windows Functions.

Video, WebCast Denali + Windows Functions

24 de agosto de 2011 Deixe um comentário

Galera, segue o vídeo da minha sessão sobre Windows Functions e Denali…

Abraços

Denali + Windows Functions

PPTs e Demos, WebCast Windows Functions

24 de agosto de 2011 Deixe um comentário

Pessoal conforme combinado, segue o link para download do material da minha sessão de hoje na Semana do SQL Server.

http://blogs.solidq.com/fabianosqlserver/Documents/Semana%20SQL%20Server%20-%20PASS.zip

Pra quem perdeu, falei um pouco sobre windows functions, seguem algumas fotos dos PPTs, e das demos:

image

image

image

image

Categorias:Não categorizado

Video – Operadores dos Planos de Execução

24 de agosto de 2011 Deixe um comentário

Galera, conforme combinado, seguem os links para acesso ao vídeo e a gravação do LYNC da minha sessão de hoje (14/07) no SolidQ Virtual Conference. Se você ainda não se inscreveu não perca mais tempo… Smile

Espero que tenham gostado, e qualquer dúvida sabem onde me achar Winking smile.

Link para download do material:

https://skydrive.live.com/#!/?cid=52eff7477e74caa6&sc=documents&uc=1&id=52EFF7477E74CAA6!2023

Pra variar, o Murphy deu as caras, e minha janela do LYNC travou no meio da sessão… Nada grave, mas o video ficou cortado em 2 partes.

Categorias:Não categorizado

Minha lista de Livros prediletos…

24 de agosto de 2011 Deixe um comentário
Categorias:Não categorizado

Bug Query Optimizer – Unnecessary Sort

24 de agosto de 2011 Deixe um comentário

Just created a new connect item about a bug on Query Optimizer, I appreciate if you could vote 😉

More details here: https://connect.microsoft.com/SQLServer/feedback/details/679342/unnecessary-sort#details

IF OBJECT_ID('Departamentos') IS NOT NULL DROP TABLE Departamentos GO CREATE TABLE Departamentos (ID Int IDENTITY(1,1) PRIMARY KEY, Nome_Dep VarChar(200)) GO INSERT INTO Departamentos(Nome_Dep) VALUES('Vendas'), ('TI'), ('Recursos Humanos') GO IF OBJECT_ID('Funcionarios') IS NOT NULL DROP TABLE Funcionarios GO CREATE TABLE Funcionarios (ID Int IDENTITY(1,1) PRIMARY KEY, ID_Dep Int, Nome VarChar(200), Salario Numeric(18,2)) GO INSERT INTO Funcionarios (ID_Dep, Nome, Salario) VALUES(1, 'Fabiano', 2000), (1, 'Amorim', 2500), (1, 'Diego', 9000), (2, 'Felipe', 2000), (2, 'Ferreira', 2500), (2, 'Nogare', 11999), (3, 'Laerte', 5000), (3, 'Luciano', 23500), (3, 'Zavaschi', 13999) GO SELECT Departamentos.Nome_Dep, Nome, Salario, avg(Salario) OVER (PARTITION BY Departamentos.Nome_Dep) AS AvgSalario, rank() OVER (PARTITION BY Departamentos.Nome_Dep ORDER BY Salario desc) AS RankSalario FROM Funcionarios INNER JOIN Departamentos ON Funcionarios.ID_Dep = Departamentos.ID OPTION (RECOMPILE) GO

Two Sorts:

image

SELECT Departamentos.Nome_Dep,
       Nome,       
       Salario,
       rank() OVER (PARTITION BY Departamentos.Nome_Dep ORDER BY Salario desc) AS RankSalario,
       avg(Salario) OVER (PARTITION BY Departamentos.Nome_Dep) AS AvgSalario
  FROM Funcionarios 
 INNER JOIN Departamentos
    ON Funcionarios.ID_Dep = Departamentos.ID
OPTION (RECOMPILE)
GO

One Sort:

image

Categorias:Não categorizado

Eu, MVP?

24 de agosto de 2011 Deixe um comentário

Na sexta-feira passada nessa hora (12:17) eu estava tremendo com o coração batendo a mil por hora…

O Luti falando no skype – Ei não vai twittar não? Conta logo se não eu conto!

Eu tentando me controlar pra conseguir escrever sem errar… porque? Porque eu havia acabado de receber um e-mail com o seguinte assunto “Congratulations 2011 Microsoft MVP!”.

Quando comecei a blogar e me envolver com a comunidade SQL Server eu jamais poderia imaginar onde isso me levaria, e o quanto isso seria tão importante para minha vida profissional e pessoal.

Simple-Talk, Marília TechDay, Amizades, SolidQ, MVP… coisas que não tem preço e já marcaram minha vida. #fato

Estou extremanente orgulhoso e honrado em dizer que sou MVP em SQL Server, na verdade morro de vergonha de dizer isso… não sei se vou me acostumar Smile… parece que estou falando de outra pessoa, ou estou me “achando” Smile with tongue out… é estranho é estranho…

Só de pensar de que faço parte do time de MVPs em SQL Server do Brasil já fico emocionado… Luti, Nilton, Gustavo, Diego, Zava, Laerte… caramba só a galera marvada…

Tenho que agradecer a várias pessoas por me ajudar diretamente ou indiretamente nessa conquista, talvez a lista seja grande mas espero não me esquecer de ninguem então vamos lá…

Primeiramente, todos os créditos ao Deus que sivro e que tem me abençoado com saúde para trabalhar e conseguir fazer o que gosto. “Faz sentido servir alguem melhor que eu!”

Leda Amorim (meu braço direito e esquero)… Obrigado por me suportar, e me incentivar a fazer o que gosto, te amo!

Marcos Amorim (mentor, professor, irmão)… Incontáveis ensinamentos, desde a dirigir na marginal sem carta com seu Corola, a me levar nas reuniões com clientes importantes só pra eu ficar queto, ouvindo, sem fazer nada… aprendendo… isso não tem preço. Obrigado!

Luti – Alguns já sabem, mais o Luti quem começou com essa idea de, Ei porque você não cria um blog e tals… Luti sou muito grato por todas as dicas e direcionamentos que você me deu e pelas conversamos que já tivemos… você é o cara de SQL Server no Brasil, #fato… não tem pra ninguêm… Lembro até hoje quando te mandei o primeiro e-mail, procurei sei e-mail no google, achei em uma webcast sua.. mandei o e-mail e quando recebi a resposta pensei… Caraca o cara respondeu mesmo Smile. Obrigado!

Laerte – Porra, esse é o cara! É o cara mais loco que conheço… Laerte me indicou pro Simple-Talk, me chamou pra participar do Marília TechDay, me apresentou a SolidQ… lembro que no Marília TechDay ele disse… Ei ta vendo aquele cara ali? É o Fernando Guerreiro, CIO Global da SolidQ, cola nele! Não deu outra, foi o que eu fiz eeee… deu certo Open-mouthed smile. Valeu brother, pode contar com seu irmão aqui, sempre!

Caramba… a lista vai longe… mas vou tentar não fazer deste post um livro, vão aqui alguns nomes:

Zava, Diego, Felipe, Thiago Cruz, Evil, Eladio, Fernando Guerreiro, Maycon, Alex Rosa(lembro quando vi ele no teched e pensei, opa, esse é aquele carequinha do Blog KeepLearning Smile with tongue out), Junir Galvão, Nilton, Arnaldo, Vladmir, Rodolpho, Luis, Douglas, Cinéia, Marcondes, JP, Hara, Fabricio, Alx, Andressa, MaryHelpa, Sandro, Claudio, Edvaldo, Zé, João, Thiago, Luciana, Galera da CNP, Mauro Pichiliani, Roberto Fonseca, Rodrigo Souza, Catae, João Polisel, Marcelo Ferandes, Luciano Palma, Paul White, Conor, Craig, Enrique Puig, Brent Ozar, Elvis, Eduardo Santarem, Paul Randal, Paulo (SQLFromHell), Pinal Dave, Rodolfo Roim, Grant Fritchey, Cris, Andrew, Benjamin Nevarez, Holger Schmeling, Phil Factor, Demétrio, Fernando Garcia, Rony Gabriel, Djonatas, FatherJack… Se eu esqueci de você me avisa que coloco aqui :-).

Comunidade pode contar comigo para o que precisar… tamo na área.

Abraços

Fabiano Amorim – SQL Server MVP

Categorias:Não categorizado