J'ai quelques données varbinary stockées dans une table dans MS Sql Server 2005. Quelqu'un a-t-il un code SQL prenant une requête en entrée (disons que la requête garantit qu'une seule colonne de varbinary est renvoyée) et génère les octets sur le disque (un fichier par ligne?) Je suis sûr que cela a déjà été posé mille fois, mais Google propose principalement des solutions .net. Je veux une solution SQL.
L'approche BCP ne fonctionne pas pour moi. Les octets qu'il écrit sur le disque ne peuvent pas être désérialisés vers les objets .net que j'ai stockés. Cela signifie que les octets sur le disque ne sont pas équivalents à ce qui est stocké. Peut-être que BCP est en train d'écrire une sorte d'en-tête. Je ne suis pas sûr.
J'ai trouvé le code suivant ici au bas de l'article. Cela fonctionne très bien! Bien que destiné aux images stockées BMP, il fonctionne avec n’importe quel varbinary.
DECLARE @SQLIMG VARCHAR(MAX),
@IMG_PATH VARBINARY(MAX),
@TIMESTAMP VARCHAR(MAX),
@ObjectToken INT
DECLARE IMGPATH CURSOR FAST_FORWARD FOR
SELECT csl_CompanyLogo from mlm_CSCompanySettingsLocalizations
OPEN IMGPATH
FETCH NEXT FROM IMGPATH INTO @IMG_PATH
WHILE @@FETCH_STATUS = 0
BEGIN
SET @TIMESTAMP = 'd:\' + replace(replace(replace(replace(convert(varchar,getdate(),121),'-',''),':',''),'.',''),' ','') + '.bmp'
PRINT @TIMESTAMP
PRINT @SQLIMG
EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT
EXEC sp_OASetProperty @ObjectToken, 'Type', 1
EXEC sp_OAMethod @ObjectToken, 'Open'
EXEC sp_OAMethod @ObjectToken, 'Write', NULL, @IMG_PATH
EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, @TIMESTAMP, 2
EXEC sp_OAMethod @ObjectToken, 'Close'
EXEC sp_OADestroy @ObjectToken
FETCH NEXT FROM IMGPATH INTO @IMG_PATH
END
CLOSE IMGPATH
DEALLOCATE IMGPATH
Vous pouvez utiliser BCP, pas T-SQL, mais cela fonctionne bien.
BCP "SELECT FileContent FROM table WHERE ID = 1" queryout "C:\file.txt" -T
J'ajoute ceci pour renforcer la réponse de JohnOpincar, afin que ceux qui souhaitent utiliser LinqPad puissent obtenir une solution opérationnelle plus rapidement.
/*
This LinqPad script saves data stored in a VARBINARY field to the specified folder.
1. Connect to SQL server and select the correct database in the connection dropdown (top right)
2. Change the Language to C# Program
3. Change "Attachments" to the name of your table that holds the VARBINARY data
4. Change "AttachmentBuffer" to the name of the field that holds the data
5. Change "Id" to the unique identifier field name
6. Change "1090" to the identity of the record you want to save
7. Change the path to where you want to save the file. Make sure you choose the right extension.
Notes: Windows 10 may give you "Access Denied" error when trying to save directly to C:\. Rather save to a subfolder.
*/
void Main()
{
var context = this;
var query =
from ci in context.Attachments
where ci.Id == 1090
select ci.AttachmentBuffer
;
byte[] result = query.Single().ToArray();
File.WriteAllBytes(@"c:\DEV\dumpfile.xlsx", result);
Console.WriteLine("Done");
}
Je sais que c'est un ancien message, mais j'ai compris pourquoi ce qui suit ne fonctionne pas et comment le corriger:
BCP "SELECT FileContent FROM table WHERE ID = 1" queryout "C:\file.JPG" -T -N
La raison est que bcp a placé Prefix Length au tout début du fichier. Il s'agit soit de 4 octets soit de 8 octets, en fonction du type de données de la colonne FileContent (text, ntext, image: 4 varchar (max), varbinary (max): 8 Voir https://msdn.Microsoft.com/en -us/library/ms190779.aspx )
Utilisez un éditeur binaire, tel que celui de Visual Studio, pour supprimer les octets de préfixe et tout fonctionnera parfaitement. :-)
Juste une alternative. Vous pouvez utiliser le logiciel gratuit Toad for SQL Server et enregistrer directement à partir de l'éditeur.
Vous pouvez aller sur leur site Web https://www.toadworld.com et obtenir le logiciel gratuit à cet endroit ou un essai de 30 jours de la version complète. Son sous Télécharger et choisissez Toad pour SQL Server.
Vous effectuez une instruction select régulière dans Toad sur la ligne contenant l'image que vous souhaitez enregistrer . Lorsque vous voyez les résultats, vous pouvez cliquer sur la colonne de l'image de l'octet et, à droite, un onglet PDF si Ceci est un document PDF ou à gauche un onglet Image . Lorsque vous cliquez sur cet onglet, vous pouvez voir le logo de sauvegarde en bas pour enregistrer l'image ou le fichier.
Si vous avez linqpad, cela fonctionne:
void Main()
{
var context = this;
var query =
from ci in context.Images
where ci.ImageId == 10
select ci.Image
;
var result = query.Single ();
var bytes = Convert.FromBase64String(result);
File.WriteAllBytes(@"c:\image.bmp", bytes);
}
SQL est conçu pour fonctionner avec des objets de base de données, de sorte que, du point de vue de celui-ci, rien d’autre n’existe. Bien sûr, il existe des procédures étendues telles que xp_cmdshell
qui vous permettent d'interagir avec le système d'exploitation, mais ce sont des extensions propriétaires et ne font pas partie de T-SQL.
L'approche la plus proche serait peut-être d'utiliser l'attribut FILESTREAM pour les types binaires de SQL Server 2008, qui permettent de stocker certaines colonnes directement sous forme de fichiers dans un dossier au lieu d'utiliser la base de données:
Note que le stockage FILESTREAM est conçu pour conserver des fichiers volumineux en dehors de la base de données afin d'améliorer les performances, et non pour permettre un accès direct aux fichiers (c.-à-d. Que T-SQL n'a toujours pas le concept de système de fichiers). À mon avis, l’accès direct au système de fichiers à partir de SQL annulera certaines des finalités d’une base de données (notamment le fait de stocker les données de manière structurée).
Je recommanderais donc de suivre les conseils de Dustin et d’utiliser un outil tel que BCP ou tout autre dumper de données.