web-dev-qa-db-fra.com

Pourquoi ne puis-je pas utiliser des variables en T-SQL comme je l'imagine?

Pardonnez-moi, je suis un développeur qui est passé au monde de SQL. Je pensais que je pouvais améliorer certains SQL en ajoutant des variables, mais cela ne fonctionnait pas comme prévu. Quelqu'un peut-il me dire pourquoi cela ne fonctionne pas? Je ne veux pas de travail, je veux connaître les raisons pour lesquelles cela ne fonctionne pas comme je l'imagine, car je suis sûr qu'il y a une bonne raison, mais actuellement, cela ne me saute pas aux yeux.

DECLARE @DatabaseName varchar(150)
SET @DatabaseName = 'MyAmazingDatabaseName'

CREATE DATABASE @DatabaseName
GO

USE @DatabaseName
GO
18
gareth

Par la page en ligne de livres pour variables

Les variables ne peuvent être utilisées que dans les expressions, pas à la place des noms d'objets ou des mots clés. Pour construire des instructions SQL dynamiques, utilisez EXECUTE.

Cela fonctionnerait comme vous l'attendiez si, par exemple, vous utilisiez votre variable dans une clause where. Quant à savoir pourquoi, je pense que cela a quelque chose à voir avec l'analyseur incapable d'évaluer la variable et donc de vérifier son existence. Lors de l'exécution, la requête est d'abord analysée pour la syntaxe et les objets, puis, si l'analyse réussit, la requête s'exécute à quel point la variable serait définie.

DECLARE @name varchar(20);
SET @name = 'test';

CREATE TABLE [#tmp]([val] varchar(10));

insert into #tmp
values('test')

SELECT *
FROM [#tmp]
WHERE [val] = @name;
20
Bob Klimes

Les limitations de l'utilisation des variables dans les instructions SQL proviennent de l'architecture de SQL.

Le traitement d'une instruction SQL se déroule en trois phases:

  1. Préparation - L'instruction est analysée et un plan d'exécution est compilé, spécifiant quels objets de base de données sont accédés, comment ils sont accédés et comment ils sont liés. Le plan d'exécution est enregistré dans le cache du plan.
  2. Liaison - toutes les variables de l'instruction sont remplacées par des valeurs réelles.
  3. Exécution - le plan mis en cache est exécuté avec les valeurs liées.

Le serveur SQL cache l'étape de préparation au programmeur et l'exécute beaucoup plus rapidement que les bases de données plus traditionnelles telles qu'Oracle et DB2. C'est pour des raisons de performances que SQL passe potentiellement beaucoup de temps à déterminer un plan d'exécution optimal, mais uniquement la première fois que l'instruction est rencontrée après un redémarrage.

Ainsi, dans SQL statique, les variables ne peuvent être utilisées que dans des endroits où elles n'invalideront pas le plan d'exécution, donc pas pour les noms de table, les noms de colonne (y compris les noms de colonne dans les conditions WHERE), etc.

Dynamic SQL existe pour les cas où l'on ne peut pas contourner les restrictions, et le programmeur sait que son exécution prendra un peu plus de temps. Le SQL dynamique peut être vulnérable à l'injection de code malveillant, alors faites attention!

17
grahamj42

Comme vous pouvez le voir, la question du "pourquoi" nécessite un type de réponse différent, y compris une justification historique et des hypothèses sous-jacentes à la langue, je ne suis pas sûr de pouvoir vraiment rendre justice.

Cet article complet par SQL MVP Erland Sommarskog tente de fournir une justification, ainsi que la mécanique:

La malédiction et les bénédictions de Dynamic SQL :

Plans de requête de mise en cache

Chaque requête que vous exécutez dans SQL Server nécessite un plan de requête. Lorsque vous exécutez une requête la première fois, SQL Server crée un plan de requête pour celle-ci - ou, selon la terminologie utilisée - il compile la requête. SQL Server enregistre le plan dans le cache et la prochaine fois que vous exécutez la requête, le plan est réutilisé.

Ceci (et la sécurité, voir ci-dessous) est probablement la principale raison.

SQL fonctionne en partant du principe que les requêtes ne sont pas des opérations ponctuelles, mais qu'elles seront utilisées à plusieurs reprises. Si la table (ou la base de données!) N'est pas réellement spécifiée dans la requête, elle n'a aucun moyen de générer et d'enregistrer un plan d'exécution pour une utilisation future.

Oui, toutes les requêtes que nous exécutons ne seront pas réutilisées, mais c'est la prémisse d'exploitation par défaut de SQL, donc les "exceptions" sont censées être exceptionnelles.

Erland énumère quelques autres raisons (notez qu'il énumère explicitement les avantages de l'utilisation de procédures stockées, mais beaucoup d'entre elles sont également des avantages des requêtes paramétrées (non dynamiques):

  • Le système d'autorisation : le moteur SQL ne peut pas prédire si vous avez le droit d'exécuter une requête s'il ne connaît pas la table (ou la base de données) vous serez contre. Les "chaînes d'autorisations" utilisant le SQL dynamique sont une douleur dans le cul.
  • Réduction du trafic réseau : la transmission du nom du proc stocké et de quelques valeurs de paramètres sur le réseau est plus courte qu'une longue requête.
  • Encapsulation de la logique : Vous devez être familiarisé avec les avantages de l'encapsulation de la logique à partir d'autres environnements de programmation.
  • Garder une trace de ce qui est utilisé : Si je dois changer une définition de colonne, comment puis-je trouver tout le code qui l'appelle? Il existe des procédures système pour rechercher des dépendances dans une base de données SQL, mais uniquement si le code se trouve dans des procédures stockées.
  • Facilité d'écriture du code SQL : la vérification de la syntaxe se produit lorsque vous créez ou modifiez une procédure stockée, donc, espérons-le, moins d'erreurs en résultent.
  • Résolution des bogues et des problèmes : un DBA peut tracer et mesurer les performances de chaque procédure stockée beaucoup plus facilement que le SQL dynamique en constante évolution.

Encore une fois, chacun d'eux a cent nuances que je n'entrerai pas ici.

7
BradC

Vous devez utiliser SQL dynamique

DECLARE @DatabaseName varchar(150) = 'dbamaint'
declare @sqltext nvarchar(max) = N''

set @sqltext = N'CREATE DATABASE '+quotename(@DatabaseName)+ ';'

print @sqltext 

-- once you are happy .. uncomment below
--exec sp_executesql @sqltext
set @sqltext = ''
set @sqltext = N'use '+quotename(@DatabaseName)+ ';'
print @sqltext 
-- once you are happy .. uncomment below
--exec sp_executesql @sqltext

ci-dessous est la sortie de l'impression .. une fois que vous décommentez le exec sp_executesql @sqltext les instructions seront effectivement exécutées ...

CREATE DATABASE [dbamaint];
use [dbamaint];
2
Kin Shah