Dicas de T-SQL – Operador VALUES

Você conhece a cláusula VALUES do T-SQL? A cláusula VALUES nos permite criar um Result Set sem termos que criar uma tabela e consultar seus valores.

SELECT * FROM 
(
     VALUES ('Segunda-feira', '2020-01-11'), 
     ('Terça-feira', '2020-01-12')
) as Tabela(Dia, DiaSemana);

O resultado do SELECT acima é:

Este operador nos dá um grande artifício para escrita de consultas em T-SQL. Através dele podemos, por exemplo, simular a operação de UNPIVOT que transforma colunas em linhas.

Demonstração:

CREATE TABLE Resultado
(
	Vendedor VARCHAR(30),
	[2018] INT,
	[2019] INT,
	[2020] INT
);

INSERT INTO Resultado (Vendedor, [2018], [2019], [2020]) 
VALUES ('Rodrigo', 10, 30, 10), ('Paulo', 300, 203, 123);

SELECT 
	Resultado.
        Vendedor, 
	ANO, 
	Valor 
  FROM Resultado CROSS APPLY (
VALUES ('2018',[2018]), ('2019',[2019]), ('2020',[2020])
) AS T(ANO, Valor);

O resultado do SELECT com o CROSS APPLY simulando a operação de UNPIVOT é:

Este comportamento do operador VALUES nos permite simular também duas funções – GREATEST e LEAST – bem úteis em outros SGBDs, mas que ainda não estão disponíveis no SQL Server On-Premisses.

GREATEST: Recebe uma lista de colunas e valores e retornar o maior valor entre eles.

LEAST: Recebe uma lista de colunas e valores e retornar o menor valor entre eles.

Simulação do GREATEST:

Objetivo da consulta é retornar a data de último acesso de usuário nos bancos de dados da instância. Para isto, consultamos todos os bancos de dados (sys.databases) e os dados de interação com os índices (sys.dm_db_index_usage_stats). Na DMV sys.dm_db_index_usage_stats temos as colunas com last_user_lookup, last_user_scan_, last_user_update e last_user_seek que retornam a última data em que cada operação ocorreu para aquele índice desde que o banco de dados ficou operacional pela última vez – caso não tenha havia interação leitura ou escrita a DMV não retorna nenhum valor para o índice.

/* 
Simulando o GREATEST
SELECT db.name, ISNULL(GREATEST(ius.last_user_seek, 
ius.last_user_scan, 
ius.last_user_lookup, ius.last_user_update, db.create_date), '19000101') 
  FROM sys.databases db JOIN sys.dm_db_index_usage_stats ius ON (ius.database_id = db.database_id);
*/

  SELECT 
	db.name, 
	ISNULL(
                  (
                       SELECT MAX(d) FROM sys.dm_db_index_usage_stats ius 
                        CROSS APPLY (
                             VALUES (ius.last_user_seek), 
                                    (ius.last_user_scan), 
                                    (ius.last_user_lookup),                  
                                    (ius.last_user_update), 
                                    (db.create_date) 
                        ) as t(d) 
                       WHERE ius.database_id = db.database_id
                   ), '19000101') USER_ACCESS_SINCE_LAST_RESTART -- GREATEST
    FROM 
	sys.databases db;

Para simularmos o LEAST basta trocar a função de agregação MAX por MIN.

Observação: Em novembro de 2020, estas funções foram adicionadas ao Azure SQL Database. Acreditamos que em breve ela deverá está disponível em alguma versão On Premises

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *