Есть ли способ сделать переменную TSQL постоянной?

Есть ли способ сделать переменную TSQL постоянной?

Ответ 1

Нет, но вы можете создать функцию и сделать ее жестко, и использовать ее.

Вот пример:

CREATE FUNCTION fnConstant()
RETURNS INT
AS
BEGIN
    RETURN 2
END
GO

SELECT dbo.fnConstant()

Ответ 2

Используйте псевдо-константы: https://blogs.msdn.microsoft.com/sql_server_appendix_z/2013/09/16/sql-server-variables-parameters-or-literals-or-constants/

Псевдоконстанты не являются переменными или параметрами. Вместо этого они просто просмотры с одной строкой и достаточным количеством столбцов для поддержки вашего константы. С этими простыми правилами SQL Engine полностью игнорирует значение представления, но по-прежнему строит план выполнения на основе его стоимость. План выполнения даже не показывает присоединение к представлению!

Ответ 3

Мое обходное решение для отсутствующих констант - дать подсказки о значении оптимизатору.

DECLARE @Constant INT = 123;

SELECT * 
FROM [some_relation] 
WHERE [some_attribute] = @Constant
OPTION( OPTIMIZE FOR (@Constant = 123))

Это говорит компилятору запроса обрабатывать переменную, как если бы она была константой при создании плана выполнения. Нижняя сторона состоит в том, что вы должны определить значение дважды.

Ответ 4

Нет, но следует использовать добрые старые соглашения об именах.

declare @MY_VALUE as int

Ответ 5

Нет встроенной поддержки констант в T-SQL. Вы можете использовать подход SQLMenace для имитации его (хотя вы никогда не можете быть уверены, что кто-то еще перезаписал функцию, чтобы вернуть что-то еще...) или, возможно, написать таблицу, содержащую константы, как это предлагается здесь. Возможно, написать триггер, который откатывает любые изменения в столбце ConstantValue?

Ответ 6

Перед использованием функции SQL запустите следующий script, чтобы увидеть различия в производительности:

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

Ответ 7

Если вы заинтересованы в получении оптимального плана выполнения для значения в переменной, вы можете использовать динамический код sql. Он делает переменную постоянной.

DECLARE @var varchar(100) = 'some text'
DECLARE @sql varchar(MAX)
SET @sql = 'SELECT * FROM table WHERE col = '''[email protected]+''''
EXEC (@sql)

Ответ 8

Для перечислений или простых констант представление с одной строкой имеет высокую производительность и проверку времени компиляции/отслеживания зависимостей (вызывает имя столбца)

Смотрите сообщение в блоге Джареда Ко https://blogs.msdn.microsoft.com/sql_server_appendix_z/2013/09/16/sql-server-variables-parameters-or-literals-or-constants/

создать вид

 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]

использовать вид

SELECT h.*
FROM Sales.SalesOrderHeader 
WHERE ShipMethodID = ( select [OVERNIGHT J-FAST] from ShipMethods  )

Ответ 9

Хорошо, давайте посмотрим

Константы - это неизменные значения, которые известны во время компиляции и не изменяются для жизни программы

это означает, что вы никогда не можете иметь константу в SQL Server

declare @myvalue as int
set @myvalue = 5
set @myvalue = 10--oops we just changed it

только что изменившееся значение

Ответ 10

Поскольку встроенная поддержка констант отсутствует, мое решение очень простое.

Поскольку это не поддерживается:

Declare Constant @supplement int = 240
SELECT price + @supplement
FROM   what_does_it_cost

Я бы просто преобразовал его в

SELECT price + 240/*CONSTANT:supplement*/
FROM   what_does_it_cost

Очевидно, что это зависит от уникальности всего (значения без конечного пробела и комментария). Изменить его можно с помощью глобального поиска и замены.

Ответ 11

В базе данных нет такой вещи, как "создание константы". Константы существуют так, как они есть, и часто называются значениями. Можно объявить переменную и присвоить ей значение (константу). С учебной точки зрения:

DECLARE @two INT
SET @two = 2

Здесь @two - переменная, а 2 - значение/константа.

Ответ 12

Лучшим ответом является SQLMenace в соответствии с требованием, если это необходимо для создания временной константы для использования в скриптах, то есть для нескольких операторов/пакетов GO.

Просто создайте процедуру в tempdb, тогда вы не будете влиять на целевую базу данных.

Одним из практических примеров этого является создание базы данных script, которая записывает контрольное значение в конце script, содержащего версию логической схемы. В верхней части файла находятся некоторые комментарии с историей изменений и т.д. Но на практике большинство разработчиков забудут прокрутить вниз и обновить версию схемы внизу файла.

Использование вышеуказанного кода позволяет определить константу видимой версии схемы вверху, прежде чем база данных script (скопированная из функции генерации скриптов SSMS) создает базу данных, но используется в конце. Это прямо перед разработчиком рядом с историей изменений и другими комментариями, поэтому они, скорее всего, обновят его.

Например:

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

Ответ 13

К сожалению, это неправильный ответ, который был выбран как правильный здесь...

Правильный ответ дается mbobka/Pixelated выше: Использовать (псевдо) ПОСТОЯННЫЙ ВИД

Даже использование функций с schemabinding не делает компилятор понятным, что он является константой!