Existe uma maneira de tornar uma variável TSQL constante?
sql-server
tsql
TheEmirOfGroofunkistan
fonte
fonte
WITH SCHEMABINDING
deve transformar isso em uma constante 'real' (um requisito para uma UDF ser vista como determinística em SQL). Ou seja, ele deve acabar sendo armazenado em cache. Ainda assim, +1.WITH SCHEMABINDING
naCREATE FUNCTION
instrução (ao contrário de em um procedimento armazenado que pode estar chamando a função) - está certo?Uma solução oferecida por Jared Ko é usar pseudo-constantes .
Conforme explicado em SQL Server: variáveis, parâmetros ou literais? Ou… constantes? :
fonte
Minha solução alternativa para constans ausentes é fornecer dicas sobre o valor para o otimizador.
DECLARE @Constant INT = 123; SELECT * FROM [some_relation] WHERE [some_attribute] = @Constant OPTION( OPTIMIZE FOR (@Constant = 123))
Isso diz ao compilador de consulta para tratar a variável como se fosse uma constante ao criar o plano de execução. O lado ruim é que você precisa definir o valor duas vezes.
fonte
Não, mas as boas e velhas convenções de nomenclatura devem ser usadas.
declare @MY_VALUE as int
fonte
FN_CONSTANT()
. Assim fica claro o que está acontecendo.Não há suporte embutido para constantes no T-SQL. Você poderia usar a abordagem do SQLMenace para simulá-lo (embora você nunca possa ter certeza se alguém sobrescreveu a função para retornar outra coisa ...), ou possivelmente escrever uma tabela contendo constantes, como sugerido aqui . Talvez escreva um gatilho que reverta quaisquer alterações na
ConstantValue
coluna?fonte
Antes de usar uma função SQL, execute o seguinte script para ver as diferenças de desempenho:
IF OBJECT_ID('fnFalse') IS NOT NULL DROP FUNCTION fnFalse GO IF OBJECT_ID('fnTrue') IS NOT NULL DROP FUNCTION fnTrue GO CREATE FUNCTION fnTrue() RETURNS INT WITH SCHEMABINDING AS BEGIN RETURN 1 END GO CREATE FUNCTION fnFalse() RETURNS INT WITH SCHEMABINDING AS BEGIN RETURN ~ dbo.fnTrue() END GO DECLARE @TimeStart DATETIME = GETDATE() DECLARE @Count INT = 100000 WHILE @Count > 0 BEGIN SET @Count -= 1 DECLARE @Value BIT SELECT @Value = dbo.fnTrue() IF @Value = 1 SELECT @Value = dbo.fnFalse() END DECLARE @TimeEnd DATETIME = GETDATE() PRINT CAST(DATEDIFF(ms, @TimeStart, @TimeEnd) AS VARCHAR) + ' elapsed, using function' GO DECLARE @TimeStart DATETIME = GETDATE() DECLARE @Count INT = 100000 DECLARE @FALSE AS BIT = 0 DECLARE @TRUE AS BIT = ~ @FALSE WHILE @Count > 0 BEGIN SET @Count -= 1 DECLARE @Value BIT SELECT @Value = @TRUE IF @Value = 1 SELECT @Value = @FALSE END DECLARE @TimeEnd DATETIME = GETDATE() PRINT CAST(DATEDIFF(ms, @TimeStart, @TimeEnd) AS VARCHAR) + ' elapsed, using local variable' GO DECLARE @TimeStart DATETIME = GETDATE() DECLARE @Count INT = 100000 WHILE @Count > 0 BEGIN SET @Count -= 1 DECLARE @Value BIT SELECT @Value = 1 IF @Value = 1 SELECT @Value = 0 END DECLARE @TimeEnd DATETIME = GETDATE() PRINT CAST(DATEDIFF(ms, @TimeStart, @TimeEnd) AS VARCHAR) + ' elapsed, using hard coded values' GO
fonte
2760ms elapsed, using function
|2300ms elapsed, using local variable
|2286ms elapsed, using hard coded values
|5570 elapsed, using function
|406 elapsed, using local variable
|383 elapsed, using hard coded values
|3893 elapsed, using function without schemabinding
select top 1 @m = cv_val from code_values where cv_id = 'C101'
e mesmo... 'C201'
onde code_values é a tabela de dicionário com 250 vars, existiam todos no SQL-Server 2016Se estiver interessado em obter o plano de execução ideal para um valor na variável, você pode usar um código sql dinâmico. Isso torna a variável constante.
DECLARE @var varchar(100) = 'some text' DECLARE @sql varchar(MAX) SET @sql = 'SELECT * FROM table WHERE col = '''+@var+'''' EXEC (@sql)
fonte
Para enums ou constantes simples, uma visualização com uma única linha tem ótimo desempenho e verificação de tempo de compilação / rastreamento de dependência (porque é um nome de coluna)
Consulte a postagem do blog de Jared Ko https://blogs.msdn.microsoft.com/sql_server_apethoscope_z/2013/09/16/sql-server-variables-parameters-or-literals-or-constants/
crie a vista
CREATE VIEW ShipMethods AS SELECT CAST(1 AS INT) AS [XRQ - TRUCK GROUND] ,CAST(2 AS INT) AS [ZY - EXPRESS] ,CAST(3 AS INT) AS [OVERSEAS - DELUXE] , CAST(4 AS INT) AS [OVERNIGHT J-FAST] ,CAST(5 AS INT) AS [CARGO TRANSPORT 5]
use a vista
SELECT h.* FROM Sales.SalesOrderHeader WHERE ShipMethodID = ( select [OVERNIGHT J-FAST] from ShipMethods )
fonte
Ok vamos ver
Constantes são valores imutáveis que são conhecidos em tempo de compilação e não mudam durante a vida do programa
isso significa que você nunca pode ter uma constante no SQL Server
declare @myvalue as int set @myvalue = 5 set @myvalue = 10--oops we just changed it
o valor acabou de mudar
fonte
Como não há suporte para constantes, minha solução é muito simples.
Como isso não é compatível:
Declare Constant @supplement int = 240 SELECT price + @supplement FROM what_does_it_cost
Eu simplesmente converteria para
SELECT price + 240/*CONSTANT:supplement*/ FROM what_does_it_cost
Obviamente, isso depende de que tudo (o valor sem espaço à direita e o comentário) seja único. Alterá-lo é possível com uma pesquisa e substituição globais.
fonte
Não existe algo como "criar uma constante" na literatura de banco de dados. As constantes existem como são e freqüentemente são chamadas de valores. Pode-se declarar uma variável e atribuir um valor (constante) a ela. Do ponto de vista escolar:
DECLARE @two INT SET @two = 2
Aqui @two é uma variável e 2 é um valor / constante.
fonte
2
é traduzido em um valor binário quando atribuído em "tempo de compilação". O valor real codificado depende do tipo de dados ao qual está sendo atribuído (int, char, ...).A melhor resposta é do SQLMenace de acordo com o requisito se for para criar uma constante temporária para uso em scripts, ou seja, em várias instruções / lotes GO.
Basta criar o procedimento no tempdb e você não terá nenhum impacto no banco de dados de destino.
Um exemplo prático disso é um script de criação de banco de dados que grava um valor de controle no final do script contendo a versão do esquema lógico. Na parte superior do arquivo estão alguns comentários com o histórico de alterações, etc ... Mas, na prática, a maioria dos desenvolvedores se esquecerá de rolar para baixo e atualizar a versão do esquema na parte inferior do arquivo.
Usar o código acima permite que uma constante de versão de esquema visível seja definida na parte superior antes que o script de banco de dados (copiado do recurso de geração de scripts do SSMS) crie o banco de dados, mas usado no final. Isso está bem na cara do desenvolvedor ao lado do histórico de alterações e outros comentários, então é muito provável que eles o atualizem.
Por exemplo:
use tempdb go create function dbo.MySchemaVersion() returns int as begin return 123 end go use master go -- Big long database create script with multiple batches... print 'Creating database schema version ' + CAST(tempdb.dbo.MySchemaVersion() as NVARCHAR) + '...' go -- ... go -- ... go use MyDatabase go -- Update schema version with constant at end (not normally possible as GO puts -- local @variables out of scope) insert MyConfigTable values ('SchemaVersion', tempdb.dbo.MySchemaVersion()) go -- Clean-up use tempdb drop function MySchemaVersion go
fonte