Чи є спосіб зробити змінну TSQL постійною?
Чи є спосіб зробити змінну TSQL постійною?
Відповіді:
Ні, але ви можете створити функцію і жорстко закодувати її там і використовувати її.
Ось приклад:
CREATE FUNCTION fnConstant()
RETURNS INT
AS
BEGIN
RETURN 2
END
GO
SELECT dbo.fnConstant()
WITH SCHEMABINDING
в CREATE FUNCTION
операторі (на відміну від збереженої процедури, яка може викликати функцію) - це правильно?
Одним із рішень, запропонованим Джаредом Ко, є використання псевдоконстант .
Як пояснюється в SQL Server: Змінні, параметри чи літерали? Або ... Константи? :
Псевдоконстанти не є змінними чи параметрами. Натомість це просто подання з одним рядком і достатньо стовпців для підтримки ваших констант. За допомогою цих простих правил, SQL Engine повністю ігнорує значення подання, але все одно створює план виконання на основі його значення. План виконання навіть не показує приєднання до подання!
Створіть так:
CREATE SCHEMA ShipMethod GO -- Each view can only have one row. -- Create one column for each desired constant. -- Each column is restricted to a single value. 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]
Або ось так:
SELECT h.* FROM Sales.SalesOrderHeader h WHERE h.ShipMethodID = (SELECT TOP 1 [OVERNIGHT J-FAST] FROM ShipMethod.ShipMethodID)
Моє обхідне рішення щодо відсутніх констант - дати підказки щодо значення оптимізатору.
DECLARE @Constant INT = 123;
SELECT *
FROM [some_relation]
WHERE [some_attribute] = @Constant
OPTION( OPTIMIZE FOR (@Constant = 123))
Це повідомляє компілятору запитів поводитися зі змінною так, ніби вона була константою при створенні плану виконання. Зворотний бік полягає в тому, що вам потрібно визначити значення двічі.
Ні, але слід використовувати старі добрі правила іменування.
declare @MY_VALUE as int
FN_CONSTANT()
. Таким чином стає зрозуміло, що він робить.
У T-SQL немає вбудованої підтримки констант. Ви можете використовувати підхід SQLMenace для його імітації (хоча ви ніколи не можете бути впевнені, чи хтось інший перезаписав функцію, щоб повернути щось інше ...), або, можливо, написати таблицю, що містить константи, як пропонується тут . Можливо, написати тригер, який відкочує будь-які зміни до ConstantValue
стовпця?
Перш ніж використовувати функцію 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
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'
і тим самим, ... 'C201'
де code_values - це таблиця словників з 250 варіантами, і всі вони були на SQL-Server 2016
Якщо ви зацікавлені в отриманні оптимального плану виконання значення у змінній, ви можете використовувати динамічний код 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 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 )
Гаразд, давайте подивимось
Константи - це незмінні значення, які відомі під час компіляції і не змінюються протягом життя програми
це означає, що ви ніколи не можете мати константу в 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 - значення / константа.
2
перекладається у двійкове значення, коли призначається під час "компіляції". Фактичне закодоване значення залежить від типу даних, якому він присвоюється (int, char, ...).
Найкраща відповідь від SQLMenace відповідно до вимоги, якщо це створити тимчасову константу для використання в сценаріях, тобто в декількох операторах GO / пакетах.
Просто створіть процедуру в tempdb, тоді ви не вплинете на цільову базу даних.
Одним з практичних прикладів цього є сценарій створення бази даних, який записує контрольне значення в кінці сценарію, що містить версію логічної схеми. У верхній частині файлу є кілька коментарів з історією змін тощо ... Але на практиці більшість розробників забудуть прокрутити вниз та оновити версію схеми внизу файлу.
Використання вищевказаного коду дозволяє визначити константу видимої версії схеми вгорі перед тим, як сценарій бази даних (скопійований із функції створення сценаріїв СУБД) створює базу даних, але використовується в кінці. Це прямо перед обличчям розробника поруч із історією змін та іншими коментарями, тому вони, швидше за все, оновлять її.
Наприклад:
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
WITH SCHEMABINDING
повинен перетворити це на "справжню" константу (вимога до того, щоб UDF розглядався як детермінований в SQL). Тобто він повинен потрапити в кеш. Все-таки +1.