C'è un modo per rendere costante una variabile TSQL?
C'è un modo per rendere costante una variabile TSQL?
Risposte:
No, ma puoi creare una funzione e codificarla lì e usarla.
Ecco un esempio:
CREATE FUNCTION fnConstant()
RETURNS INT
AS
BEGIN
RETURN 2
END
GO
SELECT dbo.fnConstant()
WITH SCHEMABINDING
nella CREATE FUNCTION
dichiarazione (al contrario di in una stored procedure che potrebbe essere chiamata la funzione) - è giusto?
Una soluzione, offerta da Jared Ko, consiste nell'utilizzare pseudo-costanti .
Come spiegato in SQL Server: variabili, parametri o valori letterali? Oppure ... Costanti? :
Le pseudo-costanti non sono variabili o parametri. Invece, sono semplicemente visualizzazioni con una riga e abbastanza colonne per supportare le tue costanti. Con queste semplici regole, il motore SQL ignora completamente il valore della vista ma crea comunque un piano di esecuzione basato sul suo valore. Il piano di esecuzione non mostra nemmeno un'unione alla vista!
Crea in questo modo:
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]
Quindi usa in questo modo:
SELECT h.* FROM Sales.SalesOrderHeader h JOIN ShipMethod.ShipMethodID const ON h.ShipMethodID = const.[OVERNIGHT J-FAST]
O in questo modo:
SELECT h.* FROM Sales.SalesOrderHeader h WHERE h.ShipMethodID = (SELECT TOP 1 [OVERNIGHT J-FAST] FROM ShipMethod.ShipMethodID)
La mia soluzione alternativa per le costanti mancanti è fornire suggerimenti sul valore all'ottimizzatore.
DECLARE @Constant INT = 123;
SELECT *
FROM [some_relation]
WHERE [some_attribute] = @Constant
OPTION( OPTIMIZE FOR (@Constant = 123))
Ciò indica al compilatore di query di trattare la variabile come se fosse una costante durante la creazione del piano di esecuzione. Il lato negativo è che devi definire il valore due volte.
No, ma dovrebbero essere usate le buone vecchie convenzioni di denominazione.
declare @MY_VALUE as int
FN_CONSTANT()
. In questo modo è chiaro cosa sta facendo.
Non c'è supporto integrato per le costanti in T-SQL. Potresti usare l'approccio di SQLMenace per simularlo (anche se non puoi mai essere sicuro che qualcun altro abbia sovrascritto la funzione per restituire qualcos'altro ...), o possibilmente scrivere una tabella contenente costanti, come suggerito qui . Forse scrivere un trigger che ripristini le modifiche alla ConstantValue
colonna?
Prima di utilizzare una funzione SQL, eseguire il seguente script per vedere le differenze nelle prestazioni:
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'
e lo stesso ... 'C201'
dove code_values è la tabella del dizionario con 250 variabili, c'erano tutte su SQL-Server 2016
Se sei interessato a ottenere un piano di esecuzione ottimale per un valore nella variabile, puoi utilizzare un codice SQL dinamico. Rende la variabile costante.
DECLARE @var varchar(100) = 'some text'
DECLARE @sql varchar(MAX)
SET @sql = 'SELECT * FROM table WHERE col = '''+@var+''''
EXEC (@sql)
Per enumerazioni o costanti semplici, una vista con una singola riga ha ottime prestazioni e controllo del tempo di compilazione / rilevamento delle dipendenze (perché è un nome di colonna)
Vedi il post del blog di Jared Ko https://blogs.msdn.microsoft.com/sql_server_appendix_z/2013/09/16/sql-server-variables-parameters-or-literals-or-constants/
creare la vista
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]
usa la vista
SELECT h.*
FROM Sales.SalesOrderHeader
WHERE ShipMethodID = ( select [OVERNIGHT J-FAST] from ShipMethods )
Va bene, vediamo
Le costanti sono valori immutabili che sono noti in fase di compilazione e non cambiano per la vita del programma
ciò significa che non puoi mai avere una costante in SQL Server
declare @myvalue as int
set @myvalue = 5
set @myvalue = 10--oops we just changed it
il valore è appena cambiato
Poiché non esiste una build a supporto delle costanti, la mia soluzione è molto semplice.
Poiché questo non è supportato:
Declare Constant @supplement int = 240
SELECT price + @supplement
FROM what_does_it_cost
Lo convertirò semplicemente in
SELECT price + 240/*CONSTANT:supplement*/
FROM what_does_it_cost
Ovviamente, questo si basa sul fatto che l'intera cosa (il valore senza lo spazio finale e il commento) sia univoca. Cambiarlo è possibile con una ricerca e sostituzione globale.
Non esistono cose come "creare una costante" nella letteratura del database. Le costanti esistono così come sono e spesso vengono chiamate valori. Si può dichiarare una variabile e assegnarle un valore (costante). Da un punto di vista scolastico:
DECLARE @two INT
SET @two = 2
Qui @two è una variabile e 2 è un valore / costante.
2
viene tradotto in un valore binario quando viene assegnato in "fase di compilazione". Il valore effettivo codificato dipende dal tipo di dati a cui viene assegnato (int, char, ...).
La risposta migliore proviene da SQLMenace in base al requisito se si tratta di creare una costante temporanea da utilizzare all'interno degli script, ovvero attraverso più istruzioni / batch GO.
Basta creare la procedura nel tempdb, quindi non hai alcun impatto sul database di destinazione.
Un esempio pratico di ciò è uno script di creazione del database che scrive un valore di controllo alla fine dello script contenente la versione dello schema logico. Nella parte superiore del file ci sono alcuni commenti con la cronologia delle modifiche ecc ... Ma in pratica la maggior parte degli sviluppatori dimenticherà di scorrere verso il basso e aggiornare la versione dello schema in fondo al file.
L'utilizzo del codice precedente consente di definire una costante di versione dello schema visibile all'inizio prima che lo script del database (copiato dalla funzione di generazione degli script di SSMS) crei il database ma utilizzato alla fine. Questo è giusto di fronte allo sviluppatore accanto alla cronologia delle modifiche e ad altri commenti, quindi è molto probabile che lo aggiornino.
Per esempio:
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
dovrebbe trasformarlo in una costante "reale" (un requisito affinché una UDF sia vista come deterministica in SQL). Vale a dire che dovrebbe finire per essere memorizzato nella cache. Tuttavia, +1.