Assim como uma parte dos desenvolvedores, acabo também tendo acesso à bases de dados SQL Server. Como a aplicação utiliza ORM para persistência das informações, o código SQL é totalmente gerado pelo NHibernate. Enquanto o ORM é responsável por fazer a persistência, tenho a necessidade que recorrer ao T-SQL para manipular e gerar massas de dados para exibir (telas e relatórios) nesta mesma aplicação.
À medida em que a versão do SQL Server avança, além das funcionalidades que são criadas em nível ferramental, a sua linguagem também ganha novos recursos, para tornar cada vez mais fácil, otimizado e inteligente a extração e manipulação de dados. Muitas vezes deixamos de acompanhar essa evolução, e quando você se dá conta, há diversos novas opções que facilitam a forma como lidamos com os dados; algo que às vezes, você até recorre à uma linguagem genuína (C#, por exemplo) para tentar realizar uma atividade, pois o T-SQL é “limitado”. A finalidade deste pequeno artigo, é demonstrar alguns recursos, que não são necessariamente novos, mas que podem facilitar o nosso dia-à-dia. Todos os scripts estão disponíveis neste endereço.
PIVOT: Possibilidade de tornar linhas em colunas, agrupando (MAX, MIN, SUM, etc.) os valores que deseja.
SELECT * FROM ( SELECT MONTH(p.Data) As Mes , SUM(Valor) As Total FROM Pedido p WHERE YEAR(p.Data) = 2016 GROUP BY MONTH(p.Data) ) sq PIVOT ( SUM(Total) FOR Mes IN ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12]) ) pvt
ROW_NUMBER: Permite numerar as linhas do resultado. Há a opção com PARTITION, que como o próprio nome diz, particiona o contador dado um critério de ordenação.
SELECT p.Data , p.Valor , ROW_NUMBER() OVER (PARTITION BY MONTH(Data) ORDER BY Data ASC) As Linha FROM Pedido p
PAGINAÇÃO: Se a aplicação suportar, a consulta pode separar em páginas e exibir parte do resultado, que é justamente aquilo que o usuário consegue ver de uma única vez.
DECLARE @PageSize As Int = 10 DECLARE @PageNumber As Int = 1 SELECT Data , Valor FROM Pedido ORDER BY Data OFFSET @PageSize * (@PageNumber - 1) ROWS FETCH NEXT @PageSize ROWS ONLY;
WITH TIES: Quando especificamos a cláusula TOP (N), ele retorna exatamente o número de registros que foi especificado. Com esta opção e dependendo do critério de ordenação, ele acaba extrapolando o número de itens do TOP entendendo que os registros que possuem o mesmo valor da ordenação, devem também estar sendo incluídos no resultado.
SELECT TOP 5 WITH TIES * FROM Pedido ORDER BY MONTH(Data) DESC
BULK INSERT: Se possui um arquivo do tipo CSV, é possível utilizar este recurso para interpretar o mesmo e conseguir inserir diretamente em uma determinada tabela da base de dados.
Id;Data;Valor;Pago
;2016-03-30 00:00:00;14000.00;0
;2016-04-30 00:00:00;14000.00;1
;2016-05-30 00:00:00;14000.00;1
BULK INSERT Pedido FROM 'C:\Temp\05 - BulkInsert.csv' WITH ( FIRSTROW = 2, FIELDTERMINATOR = ';', ROWTERMINATOR = '\n' );
IIF: Operador ternário. Simplifica o uso excessivo de CASE WHEN, que às vezes acaba tornando a consulta ilegível.
SELECT Data , Valor , IIF(Pago = 1, 'Sim', 'Não') As Pago FROM Pedido
AGREGAÇÃO COM WINDOW FUNCTION: Permite aplicar uma regra de agregação em partes do resultado, dado um critério de particionamento do mesmo. No exemplo abaixo, a ideia é ir criando totalizações linha a linha, com a soma de tudo o que está acima da linha corrente.
SELECT Data , Valor , SUM(Valor) OVER (ORDER BY Data ASC) As Total FROM Pedido ORDER BY Data ASC
TABLE VALUED PARAMETERS: Um novo tipo de dados que simula um array de um determinado tipo. Permite a parametrização da cláusula IN. Pode ser utilizado nativamente com o ADO.NET.
CREATE TYPE RelacaoDeIDs AS TABLE ( Id Int NOT NULL ) GO DECLARE @Ids As RelacaoDeIds INSERT INTO @Ids VALUES (3) INSERT INTO @Ids VALUES (34) INSERT INTO @Ids VALUES (48) SELECT * FROM Pedido WHERE Id IN (SELECT Id FROM @Ids)
CONSULTA COM EXPRESSÃO REGULAR: Utilizando uma expressão regular para retornar os clientes onde o nome termina com algum número.
SELECT * FROM Cliente WHERE Nome LIKE '%[0-9]'
LAG/LEAD: Funções que permite acessar alguma coluna da linha anterior ou posterior, respectivamente.
-- Retorna NULL SELECT Data , Valor , LAG(Data, 1) OVER(ORDER BY Data ASC) As PedidoAnteriorEm FROM Pedido ORDER BY Data ASC -- Retorna 2016-01-02 00:00:00.000 SELECT Data , Valor , LEAD(Data, 1) OVER(ORDER BY Data ASC) As ProximoPedidoEm FROM Pedido ORDER BY Data ASC
WITH CTE: Caso você precise de uma massa de dados múltiplas vezes, você pode incluir este resultado em uma CTE (Common Table Expressions) e reutilizar a mesma. Consultas recursivas (exemplo: empregado com superior, itens de menu, etc.), também podem usufruir deste recurso.
WITH totalizacao As ( SELECT SUM(Valor) As Valor FROM Pedido ) SELECT Data , Valor , ROUND(Valor / (SELECT Valor FROM totalizacao) * 100, 2) As Percentual FROM Pedido p
FORMATMESSAGE: Opção para formatar strings sem ter que ficar utilizar o caractere de concatenação (+).
SELECT Data , Valor , FORMATMESSAGE('Status: %s.', IIF(Pago = 1, 'Pago', 'Não Pago')) As Pagamento FROM Pedido
EXCLUSÃO DE OBJETOS: Sintaxe mais simples para remoção de objetos.
-- Antes IF OBJECT_ID('Pedido', 'U') IS NOT NULL DROP TABLE Pedido -- Agora DROP TABLE IF EXISTS Pedido
STRING_SPLIT: Função que recebe uma string (podendo ser uma coluna de uma tabela) separada por um determinado caractere e permite utilizar o resultado na cláusula FROM ou JOIN.
SELECT value FROM string_split('CQRS;HTTP;Data', ';')
COMPRESSÃO: Opção nativa para compressão e descompressão de dados utilizando o varbinary.
INSERT INTO Pedido VALUES (COMPRESS('Dados da Nota Fiscal 123')) SELECT CONVERT(Varchar(100), DECOMPRESS(NotaFiscal)) FROM Pedido