Existe-t-il un moyen de rendre constante une variable TSQL?
Existe-t-il un moyen de rendre constante une variable TSQL?
Réponses:
Non, mais vous pouvez créer une fonction et la coder en dur et l'utiliser.
Voici un exemple:
CREATE FUNCTION fnConstant()
RETURNS INT
AS
BEGIN
RETURN 2
END
GO
SELECT dbo.fnConstant()
WITH SCHEMABINDING
dans l' CREATE FUNCTION
instruction (par opposition à une procédure stockée qui pourrait appeler la fonction) - est-ce exact?
Une solution proposée par Jared Ko est d'utiliser des pseudo-constantes .
Comme expliqué dans SQL Server: variables, paramètres ou littéraux? Ou… des constantes? :
Les pseudo-constantes ne sont pas des variables ou des paramètres. Au lieu de cela, ce sont simplement des vues avec une ligne et suffisamment de colonnes pour prendre en charge vos constantes. Avec ces règles simples, le moteur SQL ignore complètement la valeur de la vue, mais construit toujours un plan d'exécution basé sur sa valeur. Le plan d'exécution n'affiche même pas de jointure à la vue!
Créez comme ceci:
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]
Ensuite, utilisez comme ceci:
SELECT h.* FROM Sales.SalesOrderHeader h JOIN ShipMethod.ShipMethodID const ON h.ShipMethodID = const.[OVERNIGHT J-FAST]
Ou comme ça:
SELECT h.* FROM Sales.SalesOrderHeader h WHERE h.ShipMethodID = (SELECT TOP 1 [OVERNIGHT J-FAST] FROM ShipMethod.ShipMethodID)
Ma solution de contournement aux constans manquants est de donner des conseils sur la valeur à l'optimiseur.
DECLARE @Constant INT = 123;
SELECT *
FROM [some_relation]
WHERE [some_attribute] = @Constant
OPTION( OPTIMIZE FOR (@Constant = 123))
Cela indique au compilateur de requêtes de traiter la variable comme s'il s'agissait d'une constante lors de la création du plan d'exécution. L'inconvénient est que vous devez définir la valeur deux fois.
Non, mais de bonnes vieilles conventions de dénomination devraient être utilisées.
declare @MY_VALUE as int
FN_CONSTANT()
. De cette façon, ce qu'il fait est clair.
Il n'y a pas de prise en charge intégrée des constantes dans T-SQL. Vous pouvez utiliser l'approche de SQLMenace pour le simuler (bien que vous ne puissiez jamais être sûr si quelqu'un d'autre a écrasé la fonction pour renvoyer quelque chose d'autre…), ou éventuellement écrire une table contenant des constantes, comme suggéré ici . Peut-être écrire un déclencheur qui annule les modifications apportées à la ConstantValue
colonne?
Avant d'utiliser une fonction SQL, exécutez le script suivant pour voir les différences de performances:
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'
et même ... 'C201'
où code_values est une table de dictionnaire avec 250 vars, il y en avait tous sur SQL-Server 2016
Si vous souhaitez obtenir un plan d'exécution optimal pour une valeur de la variable, vous pouvez utiliser un code SQL dynamique. Cela rend la variable constante.
DECLARE @var varchar(100) = 'some text'
DECLARE @sql varchar(MAX)
SET @sql = 'SELECT * FROM table WHERE col = '''+@var+''''
EXEC (@sql)
Pour les énumérations ou les constantes simples, une vue avec une seule ligne a d'excellentes performances et la vérification du temps de compilation / le suivi des dépendances (cause son nom de colonne)
Voir l'article de blog de Jared Ko https://blogs.msdn.microsoft.com/sql_server_appendix_z/2013/09/16/sql-server-variables-parameters-or-literals-or-constants/
créer la vue
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]
utiliser la vue
SELECT h.*
FROM Sales.SalesOrderHeader
WHERE ShipMethodID = ( select [OVERNIGHT J-FAST] from ShipMethods )
D'accord, voyons voir
Les constantes sont des valeurs immuables qui sont connues au moment de la compilation et qui ne changent pas pendant la durée de vie du programme
cela signifie que vous ne pouvez jamais avoir de constante dans SQL Server
declare @myvalue as int
set @myvalue = 5
set @myvalue = 10--oops we just changed it
la valeur vient de changer
Puisqu'il n'y a pas de support intégré pour les constantes, ma solution est très simple.
Puisque cela n'est pas pris en charge:
Declare Constant @supplement int = 240
SELECT price + @supplement
FROM what_does_it_cost
Je le convertirais simplement en
SELECT price + 240/*CONSTANT:supplement*/
FROM what_does_it_cost
Évidemment, cela repose sur le fait que l'ensemble (la valeur sans espace de fin et le commentaire) soit unique. Le changer est possible avec une recherche globale et un remplacement.
Il n'existe pas de "création d'une constante" dans la littérature des bases de données. Les constantes existent telles qu'elles sont et sont souvent appelées valeurs. On peut déclarer une variable et lui attribuer une valeur (constante). D'un point de vue scolaire:
DECLARE @two INT
SET @two = 2
Ici, @two est une variable et 2 est une valeur / constante.
2
est traduit en valeur binaire lorsqu'il est attribué au "moment de la compilation". La valeur réelle encodée dépend du type de données auquel elle est affectée (int, char, ...).
La meilleure réponse vient de SQLMenace selon l'exigence de créer une constante temporaire à utiliser dans les scripts, c'est-à-dire sur plusieurs instructions / lots GO.
Créez simplement la procédure dans tempdb, vous n'aurez aucun impact sur la base de données cible.
Un exemple pratique de ceci est un script de création de base de données qui écrit une valeur de contrôle à la fin du script contenant la version du schéma logique. En haut du fichier se trouvent des commentaires avec l'historique des modifications, etc ... Mais en pratique, la plupart des développeurs oublieront de faire défiler vers le bas et de mettre à jour la version du schéma en bas du fichier.
L'utilisation du code ci-dessus permet de définir une constante de version de schéma visible en haut avant que le script de base de données (copié à partir de la fonction de génération de scripts de SSMS) ne crée la base de données mais utilisé à la fin. C'est juste en face du développeur à côté de l'historique des modifications et d'autres commentaires, il est donc très susceptible de le mettre à jour.
Par exemple:
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
devrait transformer cela en une constante «réelle» (une exigence pour qu'un UDF soit considéré comme déterministe en SQL). Ie il devrait atterrir en cache. Pourtant, +1.