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


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

12 69

12 ответов:

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

вот пример:

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

SELECT dbo.fnConstant()

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

DECLARE @Constant INT = 123;

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

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

использовать псевдо-константы: http://blogs.msdn.com/b/sql_server_appendix_z/archive/2013/09/16/sql-server-variables-parameters-or-literals-or-constants.aspx

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

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

declare @MY_VALUE as int

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

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

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

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

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

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

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

создать вид

 CREATE VIEW ShipMethod.ShipMethodID 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 h 
JOIN ShipMethod.ShipMethodID const 
   ON h.ShipMethodID = const.[OVERNIGHT J-FAST]

Ладно, давайте посмотрим

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

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

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

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

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

Так как это не поддерживается:

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

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

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

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

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

DECLARE @two INT
SET @two = 2

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

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

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

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

использование приведенного выше кода позволяет определить видимую константу версии схемы в верхней части, прежде чем сценарий базы данных (скопированный из функции создания сценариев 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