Czy istnieje sposób na uczynienie zmiennej TSQL stałą?
sql-server
tsql
TheEmirOfGroofunkistan
źródło
źródło
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.WITH SCHEMABINDING
wCREATE 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? :
źródło
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ść.
źródło
Nie, ale należy używać starych, dobrych konwencji nazewnictwa.
declare @MY_VALUE as int
źródło
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?źródło
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
źródło
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 2016Jeś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)
źródło
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 )
źródło
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
źródło
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.
źródło
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łą.
źródło
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
źródło