Czy istnieje sposób na uczynienie zmiennej TSQL stałą?
Czy istnieje sposób na uczynienie zmiennej TSQL stałą?
Odpowiedzi:
Nie, ale możesz utworzyć funkcję, zakodować ją tam i użyć tego.
Oto przykład:
CREATE FUNCTION fnConstant()
RETURNS INT
AS
BEGIN
RETURN 2
END
GO
SELECT dbo.fnConstant()
WITH SCHEMABINDING
w CREATE FUNCTION
instrukcji (w przeciwieństwie do procedury składowanej, która może wywoływać funkcję) - czy to prawda?
Jednym z rozwiązań zaproponowanych przez Jareda Ko jest użycie pseudostałych .
Jak wyjaśniono w SQL Server: zmienne, parametry czy literały? Albo… Stałe? :
Pseudo-stałe nie są zmiennymi ani parametrami. Zamiast tego są po prostu widokami z jednym wierszem i wystarczającą liczbą kolumn do obsługi stałych. Dzięki tym prostym regułom silnik SQL całkowicie ignoruje wartość widoku, ale nadal tworzy plan wykonania na podstawie jego wartości. Plan wykonania nie pokazuje nawet połączenia do widoku!
Utwórz w ten sposób:
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]
Następnie użyj w ten sposób:
SELECT h.* FROM Sales.SalesOrderHeader h JOIN ShipMethod.ShipMethodID const ON h.ShipMethodID = const.[OVERNIGHT J-FAST]
Lub tak:
SELECT h.* FROM Sales.SalesOrderHeader h WHERE h.ShipMethodID = (SELECT TOP 1 [OVERNIGHT J-FAST] FROM ShipMethod.ShipMethodID)
Moim obejściem braku stałych jest udzielenie wskazówek dotyczących wartości optymalizatorowi.
DECLARE @Constant INT = 123;
SELECT *
FROM [some_relation]
WHERE [some_attribute] = @Constant
OPTION( OPTIMIZE FOR (@Constant = 123))
To mówi kompilatorowi zapytań, aby podczas tworzenia planu wykonania traktował zmienną tak, jakby była stałą. Wadą jest to, że musisz dwukrotnie zdefiniować wartość.
Nie, ale należy używać starych, dobrych konwencji nazewnictwa.
declare @MY_VALUE as int
FN_CONSTANT()
. W ten sposób jest jasne, co robi.
W T-SQL nie ma wbudowanej obsługi stałych. Możesz użyć metody SQLMenace, aby to zasymulować (chociaż nigdy nie możesz być pewien, czy ktoś inny nadpisał funkcję, aby zwrócić coś innego…) lub napisać tabelę zawierającą stałe, jak sugerowano tutaj . Może napisać wyzwalacz, który cofnie wszelkie zmiany w ConstantValue
kolumnie?
Przed użyciem funkcji SQL uruchom następujący skrypt, aby zobaczyć różnice w wydajności:
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'
i tym samym, ... 'C201'
gdzie code_values jest tabelą słownika z 250 zmiennymi, wszystkie były na SQL-Server 2016
Jeśli chcesz uzyskać optymalny plan wykonania wartości w zmiennej, możesz użyć dynamicznego kodu sql. Sprawia, że zmienna jest stała.
DECLARE @var varchar(100) = 'some text'
DECLARE @sql varchar(MAX)
SET @sql = 'SELECT * FROM table WHERE col = '''+@var+''''
EXEC (@sql)
W przypadku wyliczeń lub prostych stałych widok z pojedynczym wierszem ma doskonałą wydajność i sprawdzanie czasu kompilacji / śledzenie zależności (ponieważ jest to nazwa kolumny)
Zobacz wpis na blogu Jareda Ko: https://blogs.msdn.microsoft.com/sql_server_appendix_z/2013/09/16/sql-server-variables-parameters-or-literals-or-constants/
utwórz widok
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]
użyj widoku
SELECT h.*
FROM Sales.SalesOrderHeader
WHERE ShipMethodID = ( select [OVERNIGHT J-FAST] from ShipMethods )
Dobra, zobaczmy
Stałe są niezmiennymi wartościami, które są znane w czasie kompilacji i nie zmieniają się przez cały okres istnienia programu
oznacza to, że nigdy nie możesz mieć stałej w SQL Server
declare @myvalue as int
set @myvalue = 5
set @myvalue = 10--oops we just changed it
wartość właśnie się zmieniła
Ponieważ nie ma wbudowanej obsługi stałych, moje rozwiązanie jest bardzo proste.
Ponieważ nie jest to obsługiwane:
Declare Constant @supplement int = 240
SELECT price + @supplement
FROM what_does_it_cost
Po prostu przekonwertowałbym to na
SELECT price + 240/*CONSTANT:supplement*/
FROM what_does_it_cost
Oczywiście wszystko to (wartość bez spacji na końcu i komentarz) ma być unikalne. Zmiana jest możliwa dzięki globalnemu wyszukiwaniu i zamianie.
W literaturze dotyczącej baz danych nie ma czegoś takiego jak „tworzenie stałej”. Stałe istnieją takie, jakie są i często nazywane są wartościami. Można zadeklarować zmienną i przypisać jej wartość (stałą). Ze scholastycznego punktu widzenia:
DECLARE @two INT
SET @two = 2
Tutaj @two jest zmienną, a 2 jest wartością / stałą.
2
jest tłumaczony na wartość binarną, gdy jest przypisywany w „czasie kompilacji”. Rzeczywista zakodowana wartość zależy od typu danych, do którego jest przypisana (int, char, ...).
Najlepszą odpowiedzią jest SQLMenace zgodnie z wymaganiami, jeśli chodzi o utworzenie tymczasowej stałej do użytku w skryptach, tj. W wielu instrukcjach / partiach GO.
Po prostu utwórz procedurę w tempdb, a nie będziesz mieć wpływu na docelową bazę danych.
Jednym z praktycznych przykładów jest skrypt tworzenia bazy danych, który zapisuje wartość kontrolną na końcu skryptu zawierającego wersję schematu logicznego. Na górze pliku znajdują się komentarze z historią zmian itp. Ale w praktyce większość programistów zapomina przewinąć w dół i zaktualizować wersję schematu na dole pliku.
Użycie powyższego kodu pozwala na zdefiniowanie widocznej stałej wersji schematu u góry, zanim skrypt bazy danych (skopiowany z funkcji generowania skryptów SSMS) utworzy bazę danych, ale zostanie użyta na końcu. Dzieje się tak w obliczu dewelopera, obok historii zmian i innych komentarzy, więc jest bardzo prawdopodobne, że zaktualizują go.
Na przykład:
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
powinien przekształcić to w „rzeczywistą” stałą (wymóg, aby UDF był postrzegany jako deterministyczny w SQL). Oznacza to, że powinien zostać zapisany w pamięci podręcznej. Mimo to +1.