web-dev-qa-db-fra.com

Comment exécuter une instruction SQL de plus de 8 000 caractères à partir d'une variable?

Je peux utiliser le code suivant pour de toutes petites requêtes:

DECLARE @sql VARCHAR(8000)
SET @sql = 'SELECT * FROM myTable'
Exec @sql

La méthode ci-dessus est très utile pour conserver de grandes quantités de code, en particulier lorsque nous devons apporter des modifications une fois et les refléter partout.

Mon problème est ma requête (il ne s'agit que d'une seule requête) que je souhaite nourrir dans la variable @sql qui utilise plus de 25 jointures de table, certaines d'entre elles sur des variables de table temporaires, intègre des opérations complexes. .

Je souhaitais utiliser le type de données TEXT pour stocker cette requête, mais MSDN affiche un message d'avertissement indiquant que Microsoft envisage de supprimer les types de données Text, NText et Image de leurs prochaines versions. Je souhaite que mon code fonctionne à l'avenir aussi.

J'ai pensé stocker cette requête dans un fichier séparé, mais comme elle utilise des jointures sur des variables de table et d'autres paramètres spécifiques à la procédure, je doute que cela soit possible.

Veuillez m'indiquer une méthode pour stocker une requête volumineuse dans une variable et l'exécuter plusieurs fois dans une procédure.

18
Rachcha

Si vous utilisez SQL Server 2008 ou une version plus récente, vous pouvez utiliser VARCHAR (MAX).

DECLARE @sql VARCHAR(MAX)
16
Andrea Colleoni

Le problème est avec la conversion implicite.

Si vous concaténez des valeurs Unicode/nChar/nVarChar, SQL Server convertira implicitement votre chaîne en VarChar (8000) et il est malheureusement trop stupide pour réaliser qu'il tronquera votre chaîne ou même vous avertira que des données ont été tronqué d'ailleurs!

Lors de la concaténation de longues chaînes (ou de chaînes que vous estimez susceptibles d'être longues) toujours pré-concaténez votre construction de chaîne avec CAST ('' comme nVarChar (MAX)) ainsi de suite:

SET @Query = CAST('' as nVarChar(MAX))--Force implicit conversion to nVarChar(MAX)
           + 'SELECT...'-- some of the query gets set here
           + '...'-- more query gets added on, etc.

Quelle douleur et effrayante de penser que c'est juste comment fonctionne SQL Server. :(

Je connais d’autres solutions de contournement sur le Web, telles que diviser votre code en plusieurs assignations SET/SELECT en utilisant plusieurs variables, mais cela n’est pas nécessaire compte tenu de la solution ci-dessus.

Pour ceux qui ont atteint un maximum de 4000 caractères, c'était probablement parce que vous aviez le format Unicode, qui a donc été implicitement converti en nVarChar (4000) .

Explication:
En coulisse, même si la variable à laquelle vous affectez utilise (MAX), SQL Server évaluera le côté droit de la valeur que vous affectez en premier et par défaut à nVarChar (4000) ou VarChar (8000). ) (selon ce que vous êtes en train de concaténer). Après avoir déterminé la valeur (et l'avoir tronquée pour vous), il la convertit en (MAX) lors de l'attribution de votre variable, mais il est alors trop tard.

22
MikeTeeVee
DECLARE @sql VARCHAR(max)
SET @sql = 'SELECT * FROM myTable'
Exec @sql

Remarque: 

Print(@sql)

montre seulement les 8000 premiers caractères!

6
Xtian11

Le problème est que votre chaîne a une limite de 8 000 symboles par défaut. Pour éviter cela, vous devez le convertir en (N) VARCHAR (MAX) 

DECLARE @sql VARCHAR(8000)
        SET @sql = CAST('SELECT * FROM myTable' AS VARCHAR(MAX))
--Check length of variable
 PRINT 'Length is: '+CAST(LEN(@sql) AS VARCHAR)+ 'symbols'
        Exec @sql
3
Dalex

utilisation 

EXEC
(
  '
   --your sql script here
  '
)
3
Thit Lwin Oo

Vous devriez lire la réponse de cet article qui explique fort bien la situation: SQL NVARCHAR et VARCHAR Limits

  1. Si la longueur x de votre chaîne est inférieure à 4000 caractères, une chaîne sera transformée en nvarchar(x)
  2. Si la longueur y est comprise entre 4000 et 8 000, varchar(y)
  3. Si la longueur est supérieure à 8 000 caractères, nvarchar(max) qui peut stocker jusqu'à 2 Go.

Le problème est que nvarchar(max) + varchar(y) = nvarchar(max) + nvarchar(4000); SQL convertira votre varchar(y) en nvarchar(y) ou nvarchar(4000) si y est supérieur à 4000 et inférieur à 8000, tronquant votre chaîne!

2
BD01

Eh bien, j'ai déjà vu cela auparavant (en SQL 2005) et je peux vous dire que vous avez deux options:

1 - Utilisez la procédure stockée sys.sp_sqlexec qui peut prendre un param de type text (IMO, c’est la voie à suivre). Ne fais pas attention à l'avertissement. Dans SQL 2008, ntext est toujours pris en charge, et si vous utilisez varchar (max), cela fonctionnera. Donc, fondamentalement, si vous avez 2008, la solution texte et le varchar (max) fonctionneront, vous aurez donc le temps de le changer = -). En 2012 cependant, seul le varchar (max) fonctionnera. Vous devrez donc le changer avant de procéder à la mise à niveau.

2- (C’est ce que j’ai fait au début) Consultez CETTE publication: http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=52274 et indiquez ce que dit "Kristen". A fonctionné à merveille pour moi. N'oubliez pas de les prérégler à une chaîne vide. Si vous avez compris mon message, vous savez maintenant qu’en SQL 2008 ou plus récent est idiot de le faire.

2
Gaspa79

Il n'y a pas de solution pour cela en cours de route. MsSql à partir de 2012 prend en charge Ntext par exemple, ce qui vous permet d'aller au-delà de 8 000 caractères dans une variable. La solution consiste à créer plusieurs variables ou plusieurs lignes dans une table que vous pouvez parcourir.

Au mieux avec une version de MsSql, la taille maximale d’une variable est de 8 000 caractères pour la dernière version à compter de la date de saisie. Donc, si vous avez affaire à une chaîne de 80 000 caractères. Vous pouvez analyser les données dans dix variables de 8 000 caractères chacune (8 000 x 10 = 80 000) ou vous pouvez les couper en morceaux et les placer dans un tableau, par exemple, LongTable (Bigstring Varchar (8000)), insérez 10 lignes dans celui-ci et utilisez un Identité afin que vous puissiez récupérer les données dans le même ordre.

La méthode que vous essayez ne fonctionnera pas avec MsSql actuellement.

Une autre option obscure qui fonctionnera mais qui n’est pas recommandée consiste à stocker la variable dans un fichier texte à l’aide des commandes de commande Shell pour lire/écrire le fichier. Ensuite, vous avez de la place pour plus de 8 000 caractères. Ceci est lent et moins sécurisé que les autres méthodes décrites ci-dessus.

1
RobPrell

J'ai eu le même problème, avec les chaînes étant tronquées. J'ai appris que vous pouvez exécuter l'instruction sp_executesql plusieurs fois. 

Comme mon bloc de code dépassait largement la limite de 4 ko/max, je le décompose en petits morceaux comme celui-ci: 

set @statement = '                                                                                      
update pd                               
set pd.mismatchtype = 4                             
  FROM [E].[dbo].[' + @monthName + '_P_Data] pd                             
  WHERE pd.mismatchtype is null '                                                                               
exec sp_executesql @statement                               


set @statement = 'Select * from xxxxxxx'
exec sp_executesql @statement

set @statement = 'Select * from yyyyyyy '
exec sp_executesql @statement

end

Ainsi, chaque ensemble @Statement peut avoir le varchar (max) tant que chaque bloc se trouve dans les limites de la taille (j'ai coupé le code dans mon exemple, pour des raisons d'économie d'espace)

0
Eric King
ALTER PROCEDURE [dbo].[spGetEmails]
AS
BEGIN
    SET NOCOUNT ON;
    -- Insert statements for procedure here

    declare @p varbinary(max)
set @p = 0x
declare @local table (col text)

SELECT   @p = @p + 0x3B + CONVERT(varbinary(100), Email)
 FROM tbCarsList
 where email <> ''
 group by email
 order by email

 set @p = substring(@p, 2, 10000000)

 insert @local values(cast(@p as varchar(max)))
 select   col from @local


END
0
Heta77

J'ai eu le même problème. J'ai un SQL qui faisait plus de 21 000 caractères. Pour certaines raisons, 

Declare @SQL VARCHAR(MAX)

EXEC(@SQL) 

viendrait avec plusieurs problèmes

Je devais enfin le diviser en plusieurs variables de manière égale, puis tout fonctionnait.

    Declare @SQL1 VARCHAR(MAX) = 'First Part'
    Declare @SQL2 VARCHAR(MAX) = 'Second  Part'
    Declare @SQL3 VARCHAR(MAX) = 'Third Part'
    Declare @SQL4 VARCHAR(MAX) = 'Fourth Part'

    Set @SQL= @SQL1 + @SQL2 + @SQL3 + @SQL4

    EXEC(@SQL)
0
Amit